How can I move cursor over chart at any place and not just on the series data points?

822 Views Asked by At

I have 2 point line series each having default cursor on them. The default cursor runs along the series data (points). What I want is a cursor that I can move anywhere in the chart not just on the series data.

2

There are 2 best solutions below

2
On BEST ANSWER

thanks for your question. Based on the tags, I'll assume you are using LightningChart JS.

If I understood your desired behaviour correctly, you'd like the cursor to always be positioned at the users mouse, and displaying the solved closest data-point in the result table.

This can be achieved with a Chart Marker, which is basically a cursor that can be created and positioned in application code.

Custom cursor with ChartMarkerXY

Here's a code snippet on how to:

  • listen to mouse events on the document.

  • solve nearest data-point from series.

  • position Chart Marker at arbitrary location.

const marker = chart.addChartMarkerXY()

document.addEventListener( 'mousemove', ( event ) => {
    // Solve nearest data point.
    const cursorPoint = chart.solveNearest( { x: event.clientX, y: event.clientY } )
    // Translate mouse location to Axis.
    const locationOnAxes = translatePoint(
        chart.engine.clientLocation2Engine( event.clientX, event.clientY ),
        chart.engine.scale,
        {
            x: chart.getDefaultAxisX().scale,
            y: chart.getDefaultAxisY().scale
        }
    )
    // Position Chart Marker, but override its location.
    marker
        .pointAt( cursorPoint )
        // Override Cursor location to that of mouse location.
        .setPosition( locationOnAxes )
} )
0
On

If someone is looking for a solution that also works in charts that are not fullscreen, the following may be helpful.

I added the following to get the current position of the element:

const elemLeftSpace = elem.getBoundingClientRect().left;
const elemTopSpace = elem.getBoundingClientRect().top;

Make sure you call up the position in the listener, as they change as you scroll the page or resize the browser window.

After that you can calculate correct position:

const cursorPoint = chart.solveNearest( { x: event.clientX - elemLeftSpace, y: event.clientY - elemTopSpace } );

Complete code:

const marker = chart.addChartMarkerXY();
const elem = document.getElementById('chart-container');
    
elem.addEventListener( 'mousemove', ( event ) => {

    const elemLeftSpace = elem.getBoundingClientRect().left;
    const elemTopSpace = elem.getBoundingClientRect().top;

    // Solve nearest data point.
    const cursorPoint = chart.solveNearest( { x: event.clientX - elemLeftSpace, y: event.clientY - elemTopSpace } );

    if (cursorPoint) {
        const locationOnAxes = translatePoint(
            chart.engine.clientLocation2Engine( event.clientX, event.clientY ),
            chart.engine.scale,
            {
                x: chart.getDefaultAxisX().scale,
                y: chart.getDefaultAxisY().scale
            }
        );
        // Position Chart Marker, but override its location.
        marker
            .pointAt( cursorPoint )
            // Override Cursor location to that of mouse location.
            .setPosition( locationOnAxes );
})

Working example below:

const {
    lightningChart,
    AxisTickStrategies,
    DataPatterns,
    SolidLine,
    translatePoint,
    AutoCursorModes
} = lcjs

const containerId = 'chart-container';
const chart = lightningChart().ChartXY({
    containerId,
}).setAutoCursorMode(AutoCursorModes.disabled)

const axisX = chart.getDefaultAxisX()
const axisY = chart.getDefaultAxisY()
             
const data = [];

for (let i = 0; i < 10; i++) {
  data[i] = {x: i, y: Math.floor(Math.random() * 10)};
}

const lineSeries = chart.addLineSeries({
                  xAxis: axisX,
                  yAxis: axisY,
                  dataPattern: DataPatterns.horizontalProgressive

              })
            .setMouseInteractions(false);


lineSeries.add(data);


const marker = chart.addChartMarkerXY()
const elem = document.getElementById('chart-container');

elem.addEventListener( 'mousemove', ( event ) => {
    const elemLeftSpace = elem.getBoundingClientRect().left;
    const elemTopSpace = elem.getBoundingClientRect().top;

    // Solve nearest data point.
    const cursorPoint = chart.solveNearest( { x: event.clientX - elemLeftSpace, y: event.clientY - elemTopSpace } )
    // Translate mouse location to Axis.

    if (cursorPoint) {
        const locationOnAxes = translatePoint(
            chart.engine.clientLocation2Engine( event.clientX, event.clientY ),
            chart.engine.scale,
            {
                x: chart.getDefaultAxisX().scale,
                y: chart.getDefaultAxisY().scale
            }
        )
        // Position Chart Marker, but override its location.
        marker
            .pointAt( cursorPoint )
            // Override Cursor location to that of mouse location.
            .setPosition( locationOnAxes )
    }

} )
.chart-container-wrapper {
    width: 80%;
    height: 300px;
    margin: 10px auto;
}
        
        
#chart-container {
    width: 100%;
    height: 100%;
}
<div class="chart-container-wrapper">
    <div id='chart-container'></div>
  </div>
<script src="https://unpkg.com/@arction/[email protected]/dist/lcjs.iife.js"></script>