@amcharts/amcharts4
Version:
amCharts 4
190 lines (164 loc) • 5.87 kB
JavaScript
import * as am4core from "@amcharts/amcharts4/core";
import * as am4charts from "@amcharts/amcharts4/charts";
import am4themes_animated from "@amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.data = [{
"country": "USA",
"visits": 3025
}, {
"country": "China",
"visits": 1882
}, {
"country": "Japan",
"visits": 1809
}, {
"country": "Germany",
"visits": 1322
}, {
"country": "UK",
"visits": 1122
}, {
"country": "France",
"visits": 1114
}, {
"country": "India",
"visits": 984
}, {
"country": "Spain",
"visits": 711
}, {
"country": "Netherlands",
"visits": 665
}, {
"country": "Russia",
"visits": 580
}, {
"country": "South Korea",
"visits": 443
}, {
"country": "Canada",
"visits": 441
}];
chart.padding(40, 40, 40, 40);
chart.maskBullets = false; // allow bullets to go out of plot area
let label = chart.plotContainer.createChild(am4core.Label);
label.text = "Drag column bullet to change it's value";
label.y = 92;
label.x = am4core.percent(100);
label.horizontalCenter = "right";
label.zIndex = 100;
label.fillOpacity = 0.7;
// category axis
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.dataFields.category = "country";
categoryAxis.renderer.minGridDistance = 60;
categoryAxis.renderer.grid.template.disabled = true;
categoryAxis.renderer.line.disabled = true;
// value axis
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// we set fixed min/max and strictMinMax to true, as otherwise value axis will adjust min/max while dragging and it won't look smooth
valueAxis.min = 0;
valueAxis.max = 3500;
valueAxis.strictMinMax = true;
valueAxis.renderer.line.disabled = true;
valueAxis.renderer.minWidth = 40;
// series
let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryX = "country";
series.dataFields.valueY = "visits";
series.tooltip.pointerOrientation = "vertical";
series.tooltip.dy = -8;
// label bullet
let labelBullet = new am4charts.LabelBullet();
series.bullets.push(labelBullet);
labelBullet.label.text = "{valueY.value.formatNumber('#.')}";
labelBullet.strokeOpacity = 0;
labelBullet.stroke = am4core.color("#dadada");
labelBullet.dy = - 20;
// series bullet
let bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.stroke = am4core.color("#ffffff");
bullet.strokeWidth = 3;
bullet.defaultState.properties.opacity = 0;
// resize cursor when over
bullet.cursorOverStyle = am4core.MouseCursorStyle.verticalResize;
bullet.draggable = true;
bullet.circle.radius = 8;
// create hover state
let hoverState = bullet.states.create("hover");
hoverState.properties.opacity = 1; // visible when hovered
// while dragging
bullet.events.on("drag", (event) => {
handleDrag(event);
});
bullet.events.on("dragstop", (event) => {
handleDrag(event);
let dataItem = event.target.dataItem;
dataItem.column.isHover = false;
event.target.isHover = false;
});
function handleDrag(event) {
let dataItem = event.target.dataItem;
// convert coordinate to value
let value = valueAxis.yToValue(event.target.pixelY);
// set new value
dataItem.valueY = value;
// make column hover
dataItem.column.isHover = true;
// hide tooltip not to interrupt
dataItem.column.hideTooltip(0);
// make bullet hovered (as it might hide if mouse moves away)
event.target.isHover = true;
}
// column template
let columnTemplate = series.columns.template;
columnTemplate.column.cornerRadiusTopLeft = 8;
columnTemplate.column.cornerRadiusTopRight = 8;
columnTemplate.fillOpacity = 0.8;
columnTemplate.tooltipText = "drag me";
columnTemplate.tooltipY = 0; // otherwise will point to middle of the column
columnTemplate.strokeOpacity = 0;
// hover state
let columnHoverState = columnTemplate.column.states.create("hover");
columnHoverState.properties.fillOpacity = 1;
// you can change any property on hover state and it will be animated
columnHoverState.properties.cornerRadiusTopLeft = 35;
columnHoverState.properties.cornerRadiusTopRight = 35;
// show bullet when hovered
columnTemplate.events.on("over", (event) => {
let dataItem = event.target.dataItem;
let itemBullet = dataItem.bullets.getKey(bullet.uid);
itemBullet.isHover = true;
})
// hide bullet when mouse is out
columnTemplate.events.on("out", (event) => {
let dataItem = event.target.dataItem;
let itemBullet = dataItem.bullets.getKey(bullet.uid);
// hide it later for touch devices to see it longer
itemBullet.isHover = false;
})
// start dragging bullet even if we hit on column not just a bullet, this will make it more friendly for touch devices
columnTemplate.events.on("down", (event) => {
let dataItem = event.target.dataItem;
let itemBullet = dataItem.bullets.getKey(bullet.uid);
itemBullet.dragStart(event.pointer);
})
// when columns position changes, adjust minX/maxX of bullets so that we could only drag vertically
columnTemplate.events.on("positionchanged", (event) => {
let dataItem = event.target.dataItem;
let itemBullet = dataItem.bullets.getKey(bullet.uid);
let column = dataItem.column;
itemBullet.minX = column.pixelX + column.pixelWidth / 2;
itemBullet.maxX = itemBullet.minX;
itemBullet.minY = 0;
itemBullet.maxY = chart.seriesContainer.pixelHeight;
})
// as by default columns of the same series are of the same color, we add adapter which takes colors from chart.colors color set
columnTemplate.adapter.add("fill", (fill, target) => {
return chart.colors.getIndex(target.dataItem.index).saturate(0.3);
});
bullet.adapter.add("fill", (fill, target) => {
return chart.colors.getIndex(target.dataItem.index).saturate(0.3);
});