Chart.js 在线性图上拖动点

Art*_*rti 8 javascript charts chart.js

我有一个使用Chart.js库构建的简单线性图表。

我希望允许用户在图表上拖动点以动态更改它的数据。我绑定了chartjs-plugin-draggable但它只适用于我的注释。我需要完全像这样的图表:

https://www.rgraph.net/canvas/docs/adjusting-line.html

但是在项目中使用新的图形库并不是一个好的解决方案:(

我也尝试玩点事件。

更新

使用 angular 我创建了这样的东西。 在此处输入图片说明

也许如果没有办法在点上添加拖放,将会有一个技巧,可以在点位置上放置具有绝对位置的“滑块”。我也没有找到任何信息:(

Chr*_*yer 9

更新:我之前的回答被删除了,因为它只提供了一个解决问题的插件的链接,但是这里解释了它的作用:

如何实现所需行为的一般程序是

  1. 在给定图表上拦截鼠标按下(并检查它是否是拖动手势)
  2. 使用getElementAtEvent函数检查 mousedown 是否在数据点上
  3. 在 mousemove 上,使用axis.getValueForPixel函数将新的 Y-Pixel 值转换为数据坐标
  4. 使用同步更新图表数据 chart.update(0)

正如在这个Chart.js 问题中指出的那样。

为了拦截 mousedown、mousemove 和 mouseup 事件(拖动手势),需要为这些事件创建事件监听器。为了简化监听器的创建,在这种情况下可以使用d3 库,如下所示:

d3.select(chartInstance.chart.canvas).call(
  d3.drag().container(chartInstance.chart.canvas)
    .on('start', getElement)
    .on('drag', updateData)
    .on('end', callback)
);
Run Code Online (Sandbox Code Playgroud)

在鼠标按下时('start'此处的事件),getElement可以调用函数 ( ) 获取最接近指针位置的图表元素并获取 Y-Scale 的 ID

function getElement () {
    var e = d3.event.sourceEvent
    element = chartInstance.getElementAtEvent(e)[0]
    scale = element['_yScale'].id
}
Run Code Online (Sandbox Code Playgroud)

在 mousemove ( 'drag') 上,图表数据应该根据指针的当前 Y 像素值进行更新。因此,我们可以创建一个updateData函数来获取点击数据点在图表数据数组和相应数据集中的位置,如下所示

function updateData () {
  var e = d3.event.sourceEvent
  var datasetIndex = element['_datasetIndex']
  var index = element['_index']
  var value = chartInstance.scales[scale].getValueForPixel(e.clientY)
  chartInstance.data.datasets[datasetIndex].data[index] = value
  chartInstance.update(0)
}
Run Code Online (Sandbox Code Playgroud)

就是这样!如果需要在拖动后存储结果值,也可以指定这样的callback函数

function callback () {
  var datasetIndex = element['_datasetIndex']
  var index = element['_index']
  var value = chartInstance.data.datasets[datasetIndex].data[index]
  // e.g. store value in database
}
Run Code Online (Sandbox Code Playgroud)

这是上述代码的工作小提琴。该功能也是Chart.js Plugin dragData的核心,在很多情况下可能更容易实现。


Mar*_* CR 5

如果有人正在寻找不需要使用插件的解决方案,那么在 vanilla 中进行非常简单chart.js

这是一个简单的工作示例 - 只需单击并拖动数据点

// 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 two data sets
    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))
};
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>

  <!-- HEAD element: load the stylesheet and the chart.js library -->
  <head>
    <title>Draggable Points</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">
      <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>
Run Code Online (Sandbox Code Playgroud)