Chart.js drag points on linear chart

后端 未结 3 448
-上瘾入骨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:36

    Here is how I fixed using both touchscreen or mouse event x,y coordinates for the excellent d3 example above by wrapping event screen coordinates in a more "generic" x,y object.

    (Probably d3 has something similar to handle both types of events but lot of reading to find out..)

    //Get an class of {points: [{x, y},], type: event.type} clicked or touched
    function getEventPoints(event)
    {
        var retval = {point: [], type: event.type};
    
        //Get x,y of mouse point or touch event
        if (event.type.startsWith("touch")) {
            //Return x,y of one or more touches
            //Note 'changedTouches' has missing iterators and can not be iterated with forEach 
            for (var i = 0; i < event.changedTouches.length; i++) {
                var touch = event.changedTouches.item(i);
                retval.point.push({ x: touch.clientX, y: touch.clientY })
            }
        }
        else if (event.type.startsWith("mouse")) {
            //Return x,y of mouse event
            retval.point.push({ x: event.layerX, y: event.layerY })
        }
    
        return retval;
    }
    

    .. and here is how I would use it in the above d3 example to store the initial grab point Y. And works for both mouse and touch.

    Check the Fiddle


    Here how I solved the problem with using d3 and wanting to drag the document on mobile or touch screens. Somehow with the d3 event subscription all Chart area events where already blocked from bubbling up the DOM.

    Was not able to figure out if d3 could be configured to pass canvas events on without touching them. So in a protest I just eliminated d3 as it was not much involved other than subscribing events.

    Not being a Javascript master this is some fun code that subscribes the events the old way. To prevent chart touches from dragging the screen only when a chart point is grabed each of the handlers just have to return true and the event.preventDefault() is called to keep the event to your self.

    //ChartJs event handler attaching events to chart canvas
    const chartEventHandler = {
    
        //Call init with a ChartJs Chart instance to apply mouse and touch events to its canvas.
        init(chartInstance) {
    
            //Event handler for event types subscribed
            var evtHandler =
            function myeventHandler(evt) {
                var cancel = false; 
                switch (evt.type) {
                case "mousedown":
                case "touchstart":
                    cancel = beginDrag(evt);
                    break;
                case "mousemove":
                case "touchmove":
                    cancel = duringDrag(evt);
                    break;
                case "mouseup":
                case "touchend":
                    cancel = endDrag(evt);
                    break;
                default:
                    //handleDefault(evt);
                }
    
                if (cancel) {
                    //Prevent the event e from bubbling up the DOM
                    if (evt.cancelable) {
                        if (evt.preventDefault) {
                            evt.preventDefault();
                        }
                        if (evt.cancelBubble != null) {
                            evt.cancelBubble = true;
                        }
                    }                
                }
            };
    
            //Events to subscribe to
            var events = ['mousedown', 'touchstart', 'mousemove', 'touchmove', 'mouseup', 'touchend'];
    
            //Subscribe events
            events.forEach(function (evtName) {
                chartInstance.canvas.addEventListener(evtName, evtHandler);
            });
    
        }
    };
    

    The handler above is initiated like this with an existing Chart.js object:

    chartEventHandler.init(chartAcTune);
    

    The beginDrag(evt), duringDrag(evt) and endDrag(evt) have the same basic function as in the d3 example above. Just returns true when wanting to consume the event and not pasing it on for document panning and similar.


    Try it in this Fiddle using a touch screen. Unless you touch close to select a chart point the rest of the chart will be transparent to touch/mouse events and allow panning the page.

提交回复
热议问题