2017-05-03 145 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