2017-03-17 90 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() 
} 

仍需要弄清楚如何显示视觉悬停指标,因为在这个问题联系了演示,但它是一个开始。