2017-03-17 89 views

回答

3

以@ jordanwillis's和你的答案爲基礎,通過在圖表上放置另一個畫布,可以輕鬆實現任何你想要的。
只需將pointer-events:none添加到它的樣式中,以確保它不會干擾圖表的事件。
無需使用註釋插件。
例如(在這個例子中canvas是原始圖表畫布,overlay是您的新畫布放置在頂部):

var options = { 
 
    type: 'line', 
 
    data: { 
 
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], 
 
    datasets: [{ 
 
     label: '# of Votes', 
 
     data: [12, 19, 3, 5, 2, 3], 
 
     borderWidth: 1 
 
     }, 
 
     { 
 
     label: '# of Points', 
 
     data: [7, 11, 5, 8, 3, 7], 
 
     borderWidth: 1 
 
     } 
 
    ] 
 
    }, 
 
    options: { 
 
    scales: { 
 
     yAxes: [{ 
 
     ticks: { 
 
      reverse: false 
 
     } 
 
     }] 
 
    } 
 
    } 
 
} 
 

 
var canvas = document.getElementById('chartJSContainer'); 
 
var ctx = canvas.getContext('2d'); 
 
var chart = new Chart(ctx, options); 
 
var overlay = document.getElementById('overlay'); 
 
var startIndex = 0; 
 
overlay.width = canvas.width; 
 
overlay.height = canvas.height; 
 
var selectionContext = overlay.getContext('2d'); 
 
var selectionRect = { 
 
    w: 0, 
 
    startX: 0, 
 
    startY: 0 
 
}; 
 
var drag = false; 
 
canvas.addEventListener('pointerdown', evt => { 
 
    const points = chart.getElementsAtEventForMode(evt, 'index', { 
 
    intersect: false 
 
    }); 
 
    startIndex = points[0]._index; 
 
    const rect = canvas.getBoundingClientRect(); 
 
    selectionRect.startX = evt.clientX - rect.left; 
 
    selectionRect.startY = chart.chartArea.top; 
 
    drag = true; 
 
    // save points[0]._index for filtering 
 
}); 
 
canvas.addEventListener('pointermove', evt => { 
 

 
    const rect = canvas.getBoundingClientRect(); 
 
    if (drag) { 
 
    const rect = canvas.getBoundingClientRect(); 
 
    selectionRect.w = (evt.clientX - rect.left) - selectionRect.startX; 
 
    selectionContext.globalAlpha = 0.5; 
 
    selectionContext.clearRect(0, 0, canvas.width, canvas.height); 
 
    selectionContext.fillRect(selectionRect.startX, 
 
     selectionRect.startY, 
 
     selectionRect.w, 
 
     chart.chartArea.bottom - chart.chartArea.top); 
 
    } else { 
 
    selectionContext.clearRect(0, 0, canvas.width, canvas.height); 
 
    var x = evt.clientX - rect.left; 
 
    if (x > chart.chartArea.left) { 
 
     selectionContext.fillRect(x, 
 
     chart.chartArea.top, 
 
     1, 
 
     chart.chartArea.bottom - chart.chartArea.top); 
 
    } 
 
    } 
 
}); 
 
canvas.addEventListener('pointerup', evt => { 
 

 
    const points = chart.getElementsAtEventForMode(evt, 'index', { 
 
    intersect: false 
 
    }); 
 
    drag = false; 
 
    console.log('implement filter between ' + options.data.labels[startIndex] + ' and ' + options.data.labels[points[0]._index]); 
 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.js"></script> 
 

 
<body> 
 
    <canvas id="overlay" width="600" height="400" style="position:absolute;pointer-events:none;"></canvas> 
 
    <canvas id="chartJSContainer" width="600" height="400"></canvas> 
 
</body>

注意到,我們立足我們的活動,並在原來的座標畫布,但我們繪製覆蓋。這樣我們就不會弄亂圖表的功能。

+0

非常感謝!這個例子看起來不錯。 –

+0

不客氣,很高興幫助 –

2

不幸的是,沒有像這樣的東西被內置到chart.js中。您必須實現您自己的事件掛鉤和處理程序,這些掛鉤和處理程序會在圖表上呈現突出顯示的部分,然後使用原型方法來確定哪些數據已突出顯示。即使這些內置的鉤子可能不足以實現你想要的東西。

事件鉤選項是:

  • 添加的事件處理程序的畫布元件本身上(見下面的例子)

    canvas.onclick = function(evt){ 
        var activePoints = myLineChart.getElementsAtEvent(evt); 
        // => activePoints is an array of points on the canvas that are at the same position as the click event. 
    }; 
    
  • 使用onClick添加事件處理程序的chart.js之圖表對象上配置選項(explained here)。

  • 擴展一些核心圖表事件掛鉤並添加自己的。 (有關指導,請參見here)。

假設這種方法可行,那麼你可以再相應地過濾原始的圖表數據陣列(在基礎chart.js之對象),並調用.update()原型法繪製新圖。

1

根據@jordanwillis'幾個月後更新'回答:我已經有了範圍選擇的開始。

canvas.onpointerdown = function (evt) { 
    clearAnnotations() 
    const points = chart.getElementsAtEventForMode(evt, 'index', { intersect: false }) 
    const label = chart.data.labels[points[0]._index] 
    addAnnotation(label) 
} 

canvas.onpointerup = function (evt) { 
    const points = chart.getElementsAtEventForMode(evt, 'index', { intersect: false }) 
    const label = chart.data.labels[points[0]._index] 
    addAnnotation(label) 
} 

function clearAnnotations() { 
    if (chart.options.annotation) { 
    chart.options.annotation.annotations = [] 
    } 
} 

function addAnnotation (label) { 
    const annotation = { 
    scaleID: 'x-axis-0', 
    type: 'line', 
    mode: 'vertical', 
    value: label, 
    borderColor: 'red' 
    } 
    chart.options.annotation = chart.options.annotation || {} 
    chart.options.annotation.annotations = chart.options.annotation.annotations || [] 
    chart.options.annotation.annotations.push(annotation) 
    chart.update() 
} 

仍需要弄清楚如何顯示視覺懸停指標,因爲在這個問題聯繫了演示,但它是一個開始。