Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dragging does not work with panning plugin #43

Closed
Zuckerbrot opened this issue Dec 26, 2019 · 6 comments
Closed

Dragging does not work with panning plugin #43

Zuckerbrot opened this issue Dec 26, 2019 · 6 comments

Comments

@Zuckerbrot
Copy link

Hi, thanks for this great plugin.
Is it possible to make it compatible with the zoom/panning plugin?
https://github.com/chartjs/chartjs-plugin-zoom

I can only get either panning or data-dragging to work.
Example (works in Safari):
https://jsfiddle.net/zpq8an40/1/

Would be nice to have both, like eg here
http://bl.ocks.org/stepheneb/1182434

Is there any workaround available?

Thank you!

@chrispahm
Copy link
Collaborator

Hi! Thanks for the inquiry!

I remember discussing a similar matter here: #21 (comment)

It basically boils down to the question of which implementation would be best from a UI perspective. Currently, both the zoom plugin and this plugin use the same gestures, so there is no way to detect whether the user wants to drag a point or zoom the chart. In your example, zooming is triggered by dbl clicking the chart. As far as I know, the zoom plugin does not support this method. So you could either open an issue there or use the workaround I proposed in the other issue.

Merry Christmas and good luck,
Christoph

@Zuckerbrot
Copy link
Author

Thanks for the quick reply. I opened an issue at the zoom plugin project (chartjs/chartjs-plugin-zoom#308)

However, I wonder whether it is possible to detect if the dragging gesture is made on a data point or somewhere else in the plotting area. In the first case dragging the data point would be natural, in the latter, one would expect scrolling/panning the plotting area.

Thank you and happy holidays!

@chrispahm
Copy link
Collaborator

Alright, so I had another look at the source code of the zoom plugin:
Event listeners for mousedown, mousemove, and mouseup events are attached in the beforeInit function. In order to detect if the dragging gesture is made on a data point, you would need to adjust the code to something like the following:

chartInstance.$zoom._mouseDownHandler = function(event) {
  // Disable zoom when click happened on a chart element
  if (chartInstance.getElementAtEvent(event).length > 0) return
  node.addEventListener('mousemove', chartInstance.$zoom._mouseMoveHandler);
  chartInstance.$zoom._dragZoomStart = event;
};

But unfortunately, that's not all there is to it. The d3-drag event listeners used in this plugin do not seem to play nice with the event listeners attached by the zoom plugin. From the d3-drag documentation:

If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added.

There may be ways to circumvent this, but as I
a) currently have no use-case for using the two plugins simultaneously
b) am quite satisfied with the d3-drag implementation in this plugin for all use-cases
c) can't spent much more time on this issue, as this an enhancement and not really a bug,
I won't be digging any deeper 😢

If you are eager to get these two plugins to work fine together, and are willing to go the extra mile, I would propose you to

  1. Fork both plugins
  2. Add the above element click detection to the zoom plugin
  3. Tinker with the event detection in this plugin until they work well together
  4. ???
  5. Nobel prize in open source development

I wish you all the best luck with this, please keep me posted when you come up with something!
Best
Christoph

@chrispahm
Copy link
Collaborator

PS: An excellent example of how the drag plugin can be used in combination with the zoom plugin was done by @imartinezl
https://imartinezl.github.io/formula-one-viewer/

I think this demo shows how an innovative UI can make data approachable and easy to understand, without overwhelming the user.

@chrispahm
Copy link
Collaborator

Hi @Zuckerbrot,

in an issue similar to this one, @yoelz55 mentioned that the mode property required by the chartjs-plugin-zoom can be defined with a function.

plugins: {
  zoom: {
    pan: {
      enabled: true,
      mode: function({chart }) {
        // check if gesture was made over a data point
        return 'xy' // or ''
      }
    },

with this in mind, you could add a mousemove event to the ChartJS container, and observe whether a gesture was made on a datapoint or not. Then, depending on the value of the global variable, either return mode 'xy' or ''.

var eventOutsideDataPoint = true
chartCanvas.onmousemove = function(evt) {
  var activePoints = yourChart.getElementsAtEvent(evt);
  eventOutsideDataPoint = activePoints && activePoints.length ? false : true
};

//
var chartConfig: {
  ...
  plugins: {
  zoom: {
    pan: {
      enabled: true,
      mode: function({chart }) {
        if (eventOutsideDataPoint) {
          return 'xy';
        }
        return ''
      }
    },
   ....
}

Here is a fiddle showcasing this workaround.

Since the mousemove events executes hundreds of times per second, you need to be careful with this approach from a performance perspective. Also, you would need to think about the necessary adaptations (e.g. the correct listeners) to make this work correctly on touch screens. However, from a technical point of view I think these are managable obstacles from now on.

From a UI perspective, I'd still argue that this is rather cumbersome though...

@chrispahm
Copy link
Collaborator

I will close this as answered (see above comment for a working example). Please re-open if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants