例:ドラッグの実装
これは、Apache EChartsTMでグラフィック要素のドラッグを実装する方法を紹介する小さな例です。この例から、ECharts APIに基づいて豊富なインタラクティビティを備えたアプリケーションを作成する方法を見ていきます。
この例では主に、曲線の点をドラッグし、それによって曲線が変更されることを実装しています。簡単な例ですが、それに基づいて、チャートを視覚的に編集するなど、より多くのことができます。それでは、この簡単な例から始めましょう。
基本的なドラッグの実装
まず、基本的な折れ線グラフ(折れ線シリーズ)を作成します。
var symbolSize = 20;
var data = [
[15, 0],
[-50, 10],
[-56.5, 20],
[-46.5, 30],
[-22.1, 40]
];
myChart.setOption({
xAxis: {
min: -100,
max: 80,
type: 'value',
axisLine: { onZero: false }
},
yAxis: {
min: -30,
max: 60,
type: 'value',
axisLine: { onZero: false }
},
series: [
{
id: 'a',
type: 'line',
smooth: true,
// Set a big symbolSize for dragging convenience.
symbolSize: symbolSize,
data: data
}
]
});
折れ線グラフのシンボルはドラッグできないため、グラフィックコンポーネントを使用して、シンボルにそれぞれドラッグ可能な円形要素を追加することでドラッグできるようにします。
myChart.setOption({
// Declare a graphic component, which contains some graphic elements
// with the type of 'circle'.
// Here we have used the method `echarts.util.map`, which has the same
// behavior as Array.prototype.map, and is compatible with ES5-.
graphic: echarts.util.map(data, function(dataItem, dataIndex) {
return {
// 'circle' means this graphic element is a shape of circle.
type: 'circle',
shape: {
// The radius of the circle.
r: symbolSize / 2
},
// Transform is used to located the circle. position:
// [x, y] means translate the circle to the position [x, y].
// The API `convertToPixel` is used to get the position of
// the circle, which will introduced later.
position: myChart.convertToPixel('grid', dataItem),
// Make the circle invisible (but mouse event works as normal).
invisible: true,
// Make the circle draggable.
draggable: true,
// Give a big z value, which makes the circle cover the symbol
// in line series.
z: 100,
// This is the event handler of dragging, which will be triggered
// repeatly while dragging. See more details below.
// A util method `echarts.util.curry` is used here to generate a
// new function the same as `onPointDragging`, except that the
// first parameter is fixed to be the `dataIndex` here.
ondrag: echarts.util.curry(onPointDragging, dataIndex)
};
})
});
上記のコードでは、API convertToPixelを使用して、データを「ピクセル座標」に変換します。これにより、各グラフィック要素をキャンバスにレンダリングできます。「ピクセル座標」という用語は、座標がキャンバスピクセルにあることを意味します。その原点はキャンバスの左上です。文myChart.convertToPixel('grid', dataItem)
では、最初のパラメータ'grid'
は、dataItem
が最初のグリッドコンポーネント(デカルト座標)で変換されるべきであることを示します。
注意:convertToPixel
は、setOption
が最初に呼び出される前に呼び出すべきではありません。つまり、座標系(グリッド/極/ ...)が初期化された後にのみ使用できます。
これで点がドラッグ可能になりました。次に、これらの点へのドラッグに関するイベントリスナーをバインドします。
// This function will be called repeatly while dragging.
// The mission of this function is to update `series.data` based on
// the new points updated by dragging, and to re-render the line
// series based on the new data, by which the graphic elements of the
// line series can be synchronized with dragging.
function onPointDragging(dataIndex) {
// Here the `data` is declared in the code block in the beginning
// of this article. The `this` refers to the dragged circle.
// `this.position` is the current position of the circle.
data[dataIndex] = myChart.convertFromPixel('grid', this.position);
// Re-render the chart based on the updated `data`.
myChart.setOption({
series: [
{
id: 'a',
data: data
}
]
});
}
上記のコードでは、convertToPixelの逆プロセスであるAPI convertFromPixelが使用されています。myChart.convertFromPixel('grid', this.position)
は、ピクセル座標をグリッド(デカルト座標)のデータ項目に変換します。
最後に、キャンバスサイズの変更に応答するようにグラフィック要素を作成するコードを追加します。
window.addEventListener('resize', function() {
// Re-calculate the position of each circle and update chart using `setOption`.
myChart.setOption({
graphic: echarts.util.map(data, function(item, dataIndex) {
return {
position: myChart.convertToPixel('grid', item)
};
})
});
});
ツールチップコンポーネントの追加
これで、基本的な機能がパート1で実装されました。ドラッグ時にデータをリアルタイムで表示する必要がある場合は、ツールチップコンポーネントを使用してそれを行うことができます。それにもかかわらず、ツールチップコンポーネントにはデフォルトの「表示/非表示ルール」があり、このケースには適用できません。したがって、このケースの「表示/非表示ルール」をカスタマイズする必要があります。
上記のコードブロックにこれらのスニペットを追加します
myChart.setOption({
// ...,
tooltip: {
// Means disable default "show/hide rule".
triggerOn: 'none',
formatter: function(params) {
return (
'X: ' +
params.data[0].toFixed(2) +
'<br>Y: ' +
params.data[1].toFixed(2)
);
}
}
});
myChart.setOption({
graphic: data.map(function(item, dataIndex) {
return {
type: 'circle',
// ...,
// Customize "show/hide rule", show when mouse over, hide when mouse out.
onmousemove: echarts.util.curry(showTooltip, dataIndex),
onmouseout: echarts.util.curry(hideTooltip, dataIndex)
};
})
});
function showTooltip(dataIndex) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: dataIndex
});
}
function hideTooltip(dataIndex) {
myChart.dispatchAction({
type: 'hideTip'
});
}
API dispatchActionは、ツールチップコンテンツを表示/非表示にするために使用されます。ここで、アクションshowTipおよびhideTipがディスパッチされます。
完全なコード
完全なコードを以下に示します
import echarts from 'echarts';
var symbolSize = 20;
var data = [
[15, 0],
[-50, 10],
[-56.5, 20],
[-46.5, 30],
[-22.1, 40]
];
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
tooltip: {
triggerOn: 'none',
formatter: function(params) {
return (
'X: ' +
params.data[0].toFixed(2) +
'<br />Y: ' +
params.data[1].toFixed(2)
);
}
},
xAxis: { min: -100, max: 80, type: 'value', axisLine: { onZero: false } },
yAxis: { min: -30, max: 60, type: 'value', axisLine: { onZero: false } },
series: [
{ id: 'a', type: 'line', smooth: true, symbolSize: symbolSize, data: data }
]
});
myChart.setOption({
graphic: echarts.util.map(data, function(item, dataIndex) {
return {
type: 'circle',
position: myChart.convertToPixel('grid', item),
shape: { r: symbolSize / 2 },
invisible: true,
draggable: true,
ondrag: echarts.util.curry(onPointDragging, dataIndex),
onmousemove: echarts.util.curry(showTooltip, dataIndex),
onmouseout: echarts.util.curry(hideTooltip, dataIndex),
z: 100
};
})
});
window.addEventListener('resize', function() {
myChart.setOption({
graphic: echarts.util.map(data, function(item, dataIndex) {
return { position: myChart.convertToPixel('grid', item) };
})
});
});
function showTooltip(dataIndex) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: dataIndex
});
}
function hideTooltip(dataIndex) {
myChart.dispatchAction({ type: 'hideTip' });
}
function onPointDragging(dataIndex, dx, dy) {
data[dataIndex] = myChart.convertFromPixel('grid', this.position);
myChart.setOption({
series: [
{
id: 'a',
data: data
}
]
});
}
上記で紹介した知識を使用すると、より多くの機能を実装できます。たとえば、dataZoomコンポーネントをデカルト座標と連携するように追加したり、座標系にプロットボードを作成したりできます。想像力を働かせてください〜