2017-05-03 146 views
3

我有一个使用Chart.js库构建的简单线性图。Chart.js在线性图上拖动点

而我想让用户拖动图表上的点来动态地改变它的数据。我绑chartjs-plugin-draggable,但它只适用于注释。我需要的图形完全一样:

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

但用在项目新的图形库不是好的解决办法:(

此外,我试图与点事件的发挥

UPDATE

随着角我创造这样的事情 enter image description here

也许如果没有办法添加拖动到点,将有一个黑客把“滑块”的绝对位置在图上的点位置。我没有找到任何信息太:(

回答

1

更新:我以前的答案删除了,因为它只有一个功能链接到一个插件解决问题,但来这里的解释它做什么:

一般关于如何实现所期望的行为过程是

  1. 截取一个鼠标按下(并检查它是否是一个拖动手势)一个给定的图表
  2. 检查上,如果鼠标按下使用getElementAtEvent函数
  3. 是在一个数据点
  4. 在鼠标移动,翻译使用chart.update(0)

如本Chart.js issue指出新的Y像素值转换成坐标数据使用axis.getValueForPixel函数

  • 同步更新图表数据。

    为了拦截mousedown,mousemove和mouseup事件(拖动手势),需要创建所述事件的事件侦听器。为了简化该听众的创建一个可以使用d3 library在这种情况下,如下所示:(这里是'start'事件)

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

    在鼠标按下,一个函数(getElement)可以被称为thatfetches最接近图表元素以指针位置,并得到在Y尺度

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

    在鼠标移动('drag')的ID,该图表数据是应该根据指针的当前的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) 
    } 
    

    就是这样!如果你需要存储在拖动后所得到的值,你也可以指定一个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 
    } 
    

    这里是上面代码的working fiddle。该功能也是Chart.js Plugin dragData的核心,在许多情况下可能更容易实现。

  • +0

    y方向上存在初始小抓取偏移错误,并受浏览器窗口滚动位置的影响。 – flodis

    +0

    解决方案。如果我使用:_chartInstance.scales [scale] .getValueForPixel(** e.layerY **)_,则Y坐标将补偿图表滚动位置。 – flodis

    +0

    以下是我对第二个“旧”数据系列拒绝编辑和新值在整数步骤0..100中更改的图表的贡献。小提琴在这里:[小提琴](https://jsfiddle.net/flodis/3btgtptb/) – flodis

    1

    这里是我同时使用触摸屏或鼠标事件X如何固定,Y通过包裹事件屏幕坐标为优良D3例如上述坐标以更“通用”的x,y的对象。

    (大概D3具有读,找出类似的处理这两种类型的事件的东西,但很多..)

    //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; 
    } 
    

    ..这里是我会怎么用它在上面的例子D3存储最初的抓点Y.并且适用于鼠标和触摸。

    检查Fiddle


    在这里,我是如何解决这个问题,使用D3和想要拖动移动或触摸屏的文档。不知何故,d3事件订阅的所有图表区域事件已经被阻止冒泡DOM。

    无法弄清楚,如果D3可以被配置成自动传递画布事件,不接触他们。所以在一次抗议中,我刚刚取消了d3,因为除了订阅活动之外,它并没有太多涉及。

    并非是一个Javascript高手,这是一些有趣的代码,订阅事件的老路上。为了防止拖动屏幕上的图表触摸,只有当一个图表点grabed每个处理程序只需要回归event.preventDefault()被称为该事件保持你的自我。

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

    处理机上述启动这样与现有chart.js之对象:

    chartEventHandler.init(chartAcTune); 
    

    beginDrag(EVT)duringDrag(EVT)endDrag(EVT)具有与上面d3例子相同的基本功能。当想要使用该事件并且不将它放在文档平移和类似的位置时,只返回true。


    使用触摸屏在此尝试Fiddle。除非您接近选择图表点,否则图表的其余部分对触摸/鼠标事件是透明的,并允许平移页面。

    +0

    这里是一个很好的链接[developers.google.com/web/tools/chrome-devtools](https://developers.google.com/web/tools/chrome-devtools/device-mode/)如何调试和当开发者系统只有鼠标时,在Google Chrome浏览器中模拟触摸屏。 – flodis