Chart.js drag points on linear chart

后端 未结 3 456
-上瘾入骨i
-上瘾入骨i 2020-12-31 21:59

I have a simple linear chart built with Chart.js library.

And i want to allow user to drag points on chart for dynamically change data of it. I tied chartjs-plugin-d

3条回答
  •  悲哀的现实
    2020-12-31 22:27

    Update: My previous answer got deleted because it only featured a link to a plugin solving the issue, however here comes the explanation to what it does:

    The general procedure on how to achieve the desired behaviour is to

    1. Intercept a mousedown (and check if it's a dragging gesture) on a given chart
    2. Check if the mousedown was over a data point using the getElementAtEvent function
    3. On mousemove, translate the new Y-Pixel value into a data coordinate using the axis.getValueForPixel function
    4. Synchronously update the chart data using chart.update(0)

    as pointed out in this Chart.js issue.

    In order to intercept the mousedown, mousemove and mouseup events (the dragging gesture), event listeners for said events need to be created. In order to simplify the creation of the listeners one may use the d3 library in this case as follows:

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

    On mousedown (the 'start' event here), a function (getElement) may be called thatfetches the closest chart element to the pointers location and gets the ID of the Y-Scale

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

    On mousemove ('drag'), the chart data is supposed to be updated according to the current Y-Pixel value of the pointer. We can therefore create an updateData function that gets the position of the clicked data point in the charts data array and the according dataset like this

    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)
    }
    

    And that's it! If you need to store the resulting value after dragging, you may also specify a callback function like this

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

    Here is a working fiddle of the above code. The functionality is also the core of the Chart.js Plugin dragData, which may be easier to implement in many cases.

提交回复
热议问题