Draw line with mouse clicks

Hey there,

I want to draw a line by clicking once to start the line and then click a second time to draw a line between these two points. Whats important to me is, that the temporary line from the first click to the current mouse position is drawn as well.

What I have so far is this:

  var screenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

    // Function to add a point at the mouse position
    function addPoint(position) {
        point = viewer.entities.add({
            position: position,
            point: {
                pixelSize: 5,
                color: Cesium.Color.RED
            }
        });
    };

  // Event handler for left click
    screenSpaceEventHandler.setInputAction(function(click) {

    // get position of click
        var clickPosition = viewer.camera.pickEllipsoid(click.position);

    // add point at initial click position
        addPoint(clickPosition);

    // Event handler for mouse movement
        screenSpaceEventHandler.setInputAction(function(movement) {

      // get position of mouse
            var mousePosition = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid, mousePosition);

      // use callback property to add a point at the position of the mouse cursor
            var point = viewer.entities.add({
                position: new Cesium.CallbackProperty(function(time, result) {
                    return mousePosition
                }, false),
                point: {
                    pixelSize: 5,
                    color: Cesium.Color.RED
                }
            });

      // create an empty array where the coordinates of the line will be stored
            var lineArray =

      // convert mouse and click position to lon/lat coordinates and add them to the array
            var cartographicMouse = Cesium.Ellipsoid.WGS84.cartesianToCartographic(mousePosition);
            var cartographicClick = Cesium.Ellipsoid.WGS84.cartesianToCartographic(clickPosition);
      
      startPoint.longitude = cartographicClick.longitude;
      startPoint.latitude = cartographicClick.latitude;
      endPoint.longitude = cartographicMouse.longitude;
      endPoint.latitude = cartographicMouse.latitude;
      
            var x = Cesium.Math.toDegrees(cartographicMouse.longitude);
            var y = Cesium.Math.toDegrees(cartographicMouse.latitude);
            lineArray.push(x);
            lineArray.push(y);
    
            var x = Cesium.Math.toDegrees(cartographicClick.longitude);
            var y = Cesium.Math.toDegrees(cartographicClick.latitude);
            lineArray.push(x);
            lineArray.push(y);
      
      // use callback property to get cartesian coordinates for the line; if there is an existing line remove it, store in varible
            var linePosition = new Cesium.CallbackProperty(function(time, result) {
                if (typeof tempLine !== 'undefined') {
                    viewer.entities.remove(tempLine);
                };
                return new Cesium.Cartesian3.fromDegreesArray(lineArray)
            }, false)

      // draw tempLine
            var tempLine = viewer.entities.add({
                polyline: {
                    positions: linePosition,
                    width: 5,
                    material: Cesium.Color.RED
                }
            });

      // Event handler for second click; draw line with position from variable linePosition
            screenSpaceEventHandler.setInputAction(function(click) {
        
        // get position of click
        var clickPosition = viewer.camera.pickEllipsoid(click.position);
        
        // add point at click position
        addPoint(clickPosition);

                var Line = viewer.entities.add({
                    polyline: {
                        positions: linePosition,
                        width: 5,
                        material: Cesium.Color.RED
                    }
                });
        
            }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE, );

    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

This works fine as far as the functionality goes. I store the coordinates of the first click in a array, store the coordinates of the current mouse position (CallbackPoperty) in that array as well and use the array to draw a temporary line. Once I click again the actual line gets drawn

The problem is, that the temporary line only shows while I move the mouse. As soon as its still the line disappears and shows up again when moving the mouse.

I do understand why this is happening. My question is, if there is a workaround.

Thanks in advance

Hi,

You’ll need to add the position to the list of line positions in order to see it when the mouse it not moving. I would suggest that when the mouse moves, you pop the last position off the list, and push the new mouse position onto the list.

Thanks,

Gabby

He Gabby,

thanks for the answer. I tried your suggestion already. The code I came up with had a different problem. As I moved the mouse cursor a line was drawn for each registered mouse position so that the globe would be full with lines. I still struggle to get a temporary line, that is still visible while the mouse cursor is not moving. Here are Sandcastle friendly code examples for both of my approaches:

https://gist.github.com/AlexZeller/4e4f54fab055f76944e348f757987094

https://gist.github.com/AlexZeller/c0aa4bfc5af1439cd9ed4a9129a63f3e

Thanks

I think this just comes down to restructuring your code. I would avoid nesting the mouse handler functions, and instead keep track of the state of drawing. There are a bunch of examples of other developers solution on the forum if you give it a search. For example, here’s one thread.