artus9033 / chartjs-plugin-dragdata

Draggable data points plugin for Chart.js
MIT License
257 stars 55 forks source link

Drag on horizontal bar graph always resets one end to graph start #118

Closed macka601 closed 1 year ago

macka601 commented 1 year ago

Having some trouble figuring out what i've done wrong. I'm not sure if it's my Dataset class i've created or just something else.

If i add my data via the class then the drag of the graph data stops working, when dragging it will put the start of the data way off to the start of the chart. Yet the data is correctly displayed.

Best i can tell is that what is being passed into the onDrag callback should be an array of values, but when its not working it's just a single value, not an array

I've created a fiddle showing what it should do https://jsfiddle.net/e4ohu2f5/3/ and this is what it does https://jsfiddle.net/e4ohu2f5/2/ the class data is in the "tuesday" slot.

I think the class is correct? Its the first time i've really done anything with javascript classes. Any pointers would be good.

chrispahm commented 1 year ago

Hey @macka601,

Thanks for raising an issue! There are two things in your example that cause the plugin to misbehave:

  1. We're currently using a very lazy check to see if a bar chart is considered a floating bar chart → https://github.com/chrispahm/chartjs-plugin-dragdata/blob/cb96a4844dbce1ac8d80b9b0ee95e48de260399a/src/index.js#L49 https://github.com/chrispahm/chartjs-plugin-dragdata/blob/cb96a4844dbce1ac8d80b9b0ee95e48de260399a/src/index.js#L50 → we're just checking if the first datapoint in the chart is an array of length 2. Since you filled the datapoints with empty arrays ([]) of length 0, that check didn't succeed. A possible solution is to just fill the initial arrays with [undefined, undefined] instead.
  2. The data passed to the plugin is an array of strings in the format HH:mm. While the plugin receives the correct value from the click event through Chart.js own getValueForPixel, the second value in the array remains a string. Internally, the plugin now tries to identify if the user dragged at the beginning or at the end of the bar. However, there is no way to compare the string value passed from the Chart.js instance (e.g. "10:39") to the dragged value (which is a number in milliseconds, e.g. 1678892158768.9). A possible solution is to convert all datapoints to milliseconds when creating the chart. You could do that using a simple function like the following:
function arrayToDate(dateArray) {
    return [
      DATE
        .fromFormat(dateArray[0], "HH:mm")
        .toMillis(),
      DATE
        .fromFormat(dateArray[1], "HH:mm")
        .toMillis()
    ];
  }

// later when creating the chart.js instance
// ...
datasets: [
        myData, {
          label: "",
          data: [
            arrayToDate([
              "08:25", "08:39"
            ]),
            arrayToDate([
              "09:45", "09:55"
            ]),
            [undefined, undefined],
            [undefined, undefined],
            [undefined, undefined],
            [undefined, undefined],
            [undefined, undefined]
          ],
         // ...

Here's an updated fiddle which should work like intended https://jsfiddle.net/wo9zku6s/16/

macka601 commented 1 year ago

@chrispahm! Thank you so much for the explanation and the fix! REALLY appreciate that and it works well now! thank you soo soo much.