问题描述
我想使用键盘键(例如向上箭头向上平移图表,向下箭头向下平移图表等)拖动图表。
const lcjs = lightningChart({
overrideInteractionMouseButtons: {
chartXYPanMouseButton: 0,chartXYRectangleZoomFitMouseButton: 2,},})
const chart = lcjs.ChartXY()
上面的代码用鼠标没问题,但我使用 javascript 尝试了类似下面的代码,我尝试根据键盘中的箭头键移动图表。
function upArrowPress() {
move = 2;
lastpos_y1 = lastpos_y1 + move;
lastpos_y2 = lastpos_y2 + move;
for (var key in axis) {
axis[key].setScrollStrategy(undefined).setInterval(lastpos_y1[key],lastpos_y2[key])
}
}
以上代码有效,但每个轴的移动方式不同,我无法获得所有轴一起平移的本机效果。如何使用自定义功能实现平滑平移。谢谢。
解决方法
无法保证 X 轴和 Y 轴间隔在视觉上具有相同的大小。这就是为什么当您将轴间隔设置为相同时,仍然会导致视觉上不同的大小变化。
您需要根据每个系列尺度方向上的像素大小调整间隔变化。为此,您首先需要获取每个缩放方向(X 和 Y)series.scale.x.getPixelSize()
和 series.scale.y.getPixelSize()
的像素大小。这两个值是乘数,然后您可以使用它们将间隔更改为在视觉上相同的变化。
const offsetX = 1 // offset should be -1,1 based on what keys are pressed
const origXInterval = series.axisX.getInterval();
const xIntervalSize = origXInterval.end - origXInterval.start
const pixelSizeX = series.scale.x.getPixelSize()
const newXIntervalStart = origXInterval.start + offsetX * pixelSizeX * 10
axisX.setInterval(newXIntervalStart,newXIntervalStart + xIntervalSize)
这里的关键是+ offsetX * pixelSizeX * 10
。这会将 X 间隔向左 (-1) 或向右 (1) 偏移,即 10 个像素将表示的间隔值。
要对所有轴和系列执行此操作,您需要遍历每个系列 chart.getSeries().forEach(series=>{})
并偏移为任何系列找到的所有轴一次。一个轴可能被多个系列使用,因此如果您已经偏移了轴,则需要跟踪,否则平移将不同步。您可以使用 JS Set
轻松做到这一点。检查轴是否已经在集合 processedAxisSet.has(series.axisX)
中,如果不存在,则按照之前的方式进行偏移并将轴添加到集合 processedAxisSet.add(series.axisX)
中。
请参阅下面的完整示例。这是一个现成的 html 文件,您可以将其复制并粘贴到本地文件系统,然后在浏览器中打开以查看它的工作情况。我这样做是因为 iframe 会导致将事件附加到窗口时出现一些问题。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- Flexbox styling to have the chart and header fill the page.
Chart will take as much space as possible. -->
<style>
html,body {
height: 100%;
margin: 0;
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row.header {
flex: 0 1 auto;
}
.box .row.content {
flex: 1 1 auto;
}
</style>
</head>
<body class="box">
<!-- Create div to render the chart into-->
<div id="target" class="row content"></div>
<!--IIFE assembly (lcjs.iife.js) is a standalone JS file,which does not need any build tools,such as NPM,to be installed-->
<!--Script source must be defined in it's own script tag-->
<script src="https://unpkg.com/@arction/lcjs@3.0.1/dist/lcjs.iife.js"></script>
<!--Actual chart related script tag-->
<script>
// Replace the contents of this script tag if you want to test code from our examples:
// https://www.arction.com/lightningchart-js-interactive-examples/
// Extract required parts from LightningChartJS.
const {
lightningChart
} = lcjs //Note: @arction/lcjs is not needed here,when using IIFE assembly
// Create a XY Chart.
const chart = lightningChart().ChartXY({
// Set the chart into a div with id,'target'.
// Chart's size will automatically adjust to div's size.
container: 'target'
})
const axisX = chart.getDefaultAxisX();
const axisY = chart.getDefaultAxisY();
const axisX2 = chart.addAxisX({ opposite: true })
const axisY2 = chart.addAxisY({ opposite: true })
axisX.setScrollStrategy(undefined)
axisY.setScrollStrategy(undefined)
axisX2.setScrollStrategy(undefined)
axisY2.setScrollStrategy(undefined)
const lineSeries = chart.addLineSeries()
lineSeries.addArrayY([1,2,1,3,4,2],1)
const pointSeries = chart.addPointSeries({
xAxis: axisX2,yAxis: axisY2
})
pointSeries.addArrayY([2,7,5,1)
// Create a keymap to track key states
const keymap = new Map();
keymap.set('ArrowUp',0);
keymap.set('ArrowLeft',0);
keymap.set('ArrowRight',0);
keymap.set('ArrowDown',0);
// attach listeners to keydown and keyup events to keep track of key states
// keydown is also used to trigger update to pan the chart based on keyboard input
document.addEventListener('keydown',function (ev) {
keymap.set(ev.code,1);
updateKeyboardPan();
});
document.addEventListener('keyup',0);
});
function updateKeyboardPan() {
// update offsets based on keyboard state
let offsetX = 0
let offsetY = 0
if (keymap.get('ArrowUp') === 1) {
offsetY -= 1
}
if (keymap.get('ArrowDown') === 1) {
offsetY += 1
}
if (keymap.get('ArrowLeft') === 1) {
offsetX += 1
}
if (keymap.get('ArrowRight') === 1) {
offsetX -= 1
}
// set for storing what axes have already been processed
const processedAxisSet = new Set()
chart.getSeries().forEach(series => {
// offset based on pixels only if the axis hasn't been processed this loop
if (!processedAxisSet.has(series.axisX)) {
// Get original state info
const origXInterval = series.axisX.getInterval();
const xIntervalSize = origXInterval.end - origXInterval.start
// get the pixel size for axis
const pixelSizeX = series.scale.x.getPixelSize()
const newXIntervalStart = origXInterval.start + offsetX * pixelSizeX * 10
// pixel size info is used to scale the change to be visually same size for both X and Y axis
series.axisX.setInterval(newXIntervalStart,newXIntervalStart + xIntervalSize)
// add the axis to the processed axis set
processedAxisSet.add(series.axisX)
}
// Do same for Y axis as was done for X axis
if (!processedAxisSet.has(series.axisY)) {
const origYInterval = series.axisY.getInterval();
const yIntervalSize = origYInterval.end - origYInterval.start
const pixelSizeY = series.scale.y.getPixelSize()
const newYIntervalStart = origYInterval.start + offsetY * pixelSizeY * 10
series.axisY.setInterval(newYIntervalStart,newYIntervalStart + yIntervalSize)
processedAxisSet.add(series.axisY)
}
})
}
</script>
</body>
</html>