将事件位置映射到chartjs折线图中的y轴值

时间:2018-01-08 09:29:16

标签: javascript chart.js interactive

我目前正在修改Chart.js折线图以实现互动。这个想法是用户可以用手指移动图形的点。

以下是使用当前映射的示例:

chart-test.html

我已经设法读取事件并获取我必须修改的数据点:

// register pointer event
canvas.addEventListener('pointerdown', evt => {
    const points = interactiveChart.getElementsAtEventForMode(evt, 'index', {
        intersect: false
    });

    moveDataSetPoint(points, evt);
});

// change point relatively to y point
function moveDataSetPoint(points, evt)
{
    // read active data point
    var activePoint = points[0];
    var data = activePoint._chart.data;
    var datasetIndex = activePoint._datasetIndex;

    // read mouse position
    const helpers = Chart.helpers;
    var position = helpers.getRelativePosition(evt, interactiveChart);

    // calculate y axis value (ugly)
    // todo: map this with a chartjs method to map mouse inputs to yAxis values
    var yValue = map(position.y, window.myLine.height, 0, yMin, yMax);

    data.datasets[datasetIndex].data[activePoint._index] = yValue;
    window.myLine.update();
};

// attached the map function
function map(value, start1, stop1, start2, stop2) {
    return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))
};

但问题是我的地图功能只是将y指针位置相对于画布尺寸映射,然后 y轴 min 最大值。

这是非常不准确的,我正在寻找一种方法,它从指针事件值中提供正确的 y轴值。

chartjs中是否已经实现了一些功能?或者是否有一种方法可以获得图表本身的大小,而没有图例周围的边界和边框(目前我正在映射到整个画布)?

2 个答案:

答案 0 :(得分:1)

我自己找到了解决方案。您必须使用图表bottomtop属性来映射正确的尺寸:

// read chart area
var chartArea = chart.chartArea;
var yValue = map(position.y, chartArea.bottom, chartArea.top, yMin, yMax);

然后映射就像素完美。

答案 1 :(得分:0)

答案非常有用,但是花了我一段时间才了解如何应用。

因此,如果这对某人有帮助,下面是一个简单的工作示例。

如果不太明显,下面的三个文件分别为script.jsstyle.cssindex.html

// some data to be plotted
var x_data = [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050];
var y_data_1 = [86,114,106,106,107,111,133,221,783,2478];
var y_data_2 = [2000,700,200,100,100,100,100,50,25,0];

// globals
var activePoint = null;
var canvas = null;

// draw a line chart on the canvas context
window.onload = function () {

    // Draw a line chart with a single data set
    var ctx = document.getElementById("canvas").getContext("2d");
    canvas = document.getElementById("canvas");
    window.myChart = Chart.Line(ctx, {
        data: {
            labels: x_data,
            datasets: [
                {
                    data: y_data_1,
                    label: "Data 1",
                    borderColor: "#3e95cd",
                    fill: false
                },
                {
                    data: y_data_2,
                    label: "Data 2",
                    borderColor: "#cd953e",
                    fill: false
                }
            ]
        },
        options: {
            animation: {
                duration: 0
            },
            tooltips: {
                mode: 'nearest'
            }
        }
    });

    // set pointer event handlers for canvas element
    canvas.onpointerdown = down_handler;
    canvas.onpointerup = up_handler;
    canvas.onpointermove = null;
};

function down_handler(event) {
    // check for data point near event location
    const points = window.myChart.getElementAtEvent(event, {intersect: false});
    if (points.length > 0) {
        // grab nearest point, start dragging
        activePoint = points[0];
        canvas.onpointermove = move_handler;
    };
};

function up_handler(event) {
    // release grabbed point, stop dragging
    activePoint = null;
    canvas.onpointermove = null;
};

function move_handler(event)
{
    // locate grabbed point in chart data
    if (activePoint != null) {
        var data = activePoint._chart.data;
        var datasetIndex = activePoint._datasetIndex;

        // read mouse position
        const helpers = Chart.helpers;
        var position = helpers.getRelativePosition(event, myChart);

        // convert mouse position to chart y axis value 
        var chartArea = window.myChart.chartArea;
        var yAxis = window.myChart.scales["y-axis-0"];
        var yValue = map(position.y, chartArea.bottom, chartArea.top, yAxis.min, yAxis.max);

        // update y value of active data point
        data.datasets[datasetIndex].data[activePoint._index] = yValue;
        window.myChart.update();
    };
};

// map value to other coordinate system
function map(value, start1, stop1, start2, stop2) {
    return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))
};
body {
  font-family: Helvetica Neue, Arial, sans-serif;
  text-align: center;
}

.wrapper {
  max-width: 800px;
  margin: 50px auto;
}

h1 {
  font-weight: 200;
  font-size: 3em;
  margin: 0 0 0.1em 0;
}

h2 {
  font-weight: 200;
  font-size: 0.9em;
  margin: 0 0 50px;
  color: #555;
}

a {
  margin-top: 50px;
  display: block;
  color: #3e95cd;
}
<!DOCTYPE html>
<html>

  <!-- HEAD element: load the stylesheet and the chart.js library -->
  <head>
    <title>Draggable Points Example</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>

  <!-- BODY element: create a canvas and render a chart on it -->
  <body>

    <!-- canvas element in a container -->
    <div class="wrapper">
      <h1>Draggable Points Example</h1>
      <h2>Click a data point and drag up/down</h2>

      <canvas id="canvas" width="1600" height="900"></canvas>
    </div>

    <!-- call external script to create and render a chart on the canvas -->
    <script src="script.js"></script>
  </body>

</html>