0

I have a Leaflet web map displaying 13 points and 3 arrows diverging from each point (4 layers total). The map was exported from QGIS via QGIS2Web.

I'm using placeRotatedSymbol() to place the arrow SVG markers. It calculates the positions for the left arrow, right arrow, and heading arrow based on the input coordinates and rotation angles. I have been adjusting the offset values to move arrows closer to the points. It worked for the left & right arrows (blue), but the heading arrow (yellow) is not responding as expected. Here is the relevant snippet, (full code below):

//===============================================
// Function to place rotated symbols 
//===============================================
function placeRotatedSymbol(coords, lhead, rhead, head) {
    //==================================
    // Calculate offsets for left arrow
    //==================================
    var L_offsetX = Math.cos((lhead - 90) * Math.PI / 180) * 0.00000000000009;
    var L_offsetY = Math.sin((lhead - 90) * Math.PI / 180) * -0.00000000000009;
    var L_offset = [coords[1] + L_offsetY, coords[0] + L_offsetX];
    // Add left arrow marker
    var leftMarker = L.marker(L_offset, {
        icon: L_arrow,
        rotationAngle: lhead
    });
    //==================================
    // Calculate offsets for right arrow
    //==================================
    var R_offsetX = Math.cos((rhead - 90) * Math.PI / 180) * 0.00000000000009;
    var R_offsetY = Math.sin((rhead - 90) * Math.PI / 180) * -0.00000000000009;
    var R_offset = [coords[1] + R_offsetY, coords[0] + R_offsetX];
    // Add right arrow marker
    var rightMarker = L.marker(R_offset, {
        icon: R_arrow,
        rotationAngle: rhead
    });
    //==================================
    // Calculate offsets for heading arrow
    //==================================
    var H_offsetX = Math.cos((head - 90) * Math.PI / 180) * -0.00000000000009;
    var H_offsetY = Math.sin((head - 90) * Math.PI / 180) * -0.00000000000009;
    var H_offset = [coords[1] + H_offsetY, coords[0] + H_offsetX];
    // Add heading arrow marker
    var headingMarker = L.marker(H_offset, {
        icon: H_arrow,
        rotationAngle: head
    });

I need to make a minor adjustment so that base of the yellow arrow is centered. Currently it is a bit to right of each point. It also needs to move closer to the point so that there is no gap.

Here is what it currently looks like

enter image description here

here is what i want it to look like. They need to be offset about 1.6 points to the left

enter image description here

Code:

//==============================================================
// Define custom icons for each symbol (1 point, 3 arrows)
//==============================================================
// Sensor marker dimensions
const circleRadius = 6; 
// LR arrow icon dimensions
const LR_Width = 64;
const LR_Height = 64;
// Heading arrow icon dimensions
const H_Height = 40;
const H_Width = 40;

// Left arrow SVG (stored in Leaflet markers exported by QGIS2Web)
var L_arrow = L.icon({
    iconUrl: 'markers/test2.svg',
    iconSize: [LR_Width, LR_Height],
    iconAnchor: [LR_Width / 2, LR_Height + circleRadius] 
});
// Right arrow SVG
var R_arrow = L.icon({
    iconUrl: 'markers/test2.svg',
    iconSize: [LR_Width, LR_Height],
    iconAnchor: [LR_Width / 2, LR_Height + circleRadius] 
});

// Heading arrow SVG
var H_arrow = L.icon({
    iconUrl: 'markers/head.svg',
    iconSize: [H_Width, H_Height],
    iconAnchor: [H_Width / 2, H_Height + circleRadius] 
});

//===============================================
// Function to place rotated symbols 
//===============================================
function placeRotatedSymbol(coords, lhead, rhead, head) {
    //==================================
    // Calculate offsets for left arrow
    //==================================
    var L_offsetX = Math.cos((lhead - 90) * Math.PI / 180) * 0.00000000000009;
    var L_offsetY = Math.sin((lhead - 90) * Math.PI / 180) * -0.00000000000009;
    var L_offset = [coords[1] + L_offsetY, coords[0] + L_offsetX];
    // Add left arrow marker
    var leftMarker = L.marker(L_offset, {
        icon: L_arrow,
        rotationAngle: lhead
    });
    //==================================
    // Calculate offsets for right arrow
    //==================================
    var R_offsetX = Math.cos((rhead - 90) * Math.PI / 180) * 0.00000000000009;
    var R_offsetY = Math.sin((rhead - 90) * Math.PI / 180) * -0.00000000000009;
    var R_offset = [coords[1] + R_offsetY, coords[0] + R_offsetX];
    // Add right arrow marker
    var rightMarker = L.marker(R_offset, {
        icon: R_arrow,
        rotationAngle: rhead
    });
    //==================================
    // Calculate offsets for heading arrow
    //==================================
    var H_offsetX = Math.cos((head - 90) * Math.PI / 180) * -0.00000000000009; //this is the problem
    var H_offsetY = Math.sin((head - 90) * Math.PI / 180) * -0.00000000000009;
    var H_offset = [coords[1] + H_offsetY, coords[0] + H_offsetX];
    // Add heading arrow marker
    var headingMarker = L.marker(H_offset, {
        icon: H_arrow,
        rotationAngle: head
    });
2
  • Again the same question: why do you place each arrow marker at different coordinate? There is absolutely no need for that. Just place each marker at the same coordinate. When you get rid of that we can go to placing yellow arrow marker.
    – TomazicM
    Commented Apr 18 at 19:15
  • Thanks a bunch TomazicM! I edited the SVG a bit and integrated your idea in my code. It is working perfectly. Commented Apr 19 at 21:11

1 Answer 1

0

Update

Thank you TomazicM for your help: here is the updated code based on TomazicM's directions which led me to my solution:

Code

//==============================================================
// Define custom icons for each symbol (1 point, 3 arrows)
//==============================================================
// Sensor marker dimensions
const circleRadius = 6; 
// Arrow icon dimensions
const arrowWidth = 64;
const arrowHeight = 64;
// Heading arrow icon dimensions
const H_Height = 24;
const H_Width = 24;

// Left and right arrow SVG
var arrow = L.icon({
    iconUrl: 'markers/LR.svg',
    iconSize: [arrowWidth, arrowHeight],
    iconAnchor: [arrowWidth / 2, arrowHeight + circleRadius] 
});

// Heading arrow SVG
var H_arrow = L.icon({
    iconUrl: 'markers/head.svg',
    iconSize: [H_Width, H_Height],
    iconAnchor: [H_Width / 2, H_Height + circleRadius] 
});

//===============================================================
// Function to place rotated symbols 
//===============================================================
// Function to calculate offset based on angle and length
    function placeRotatedSymbol(coords, lhead, rhead, head, label, feature) {
    console.log("Placing rotated symbol for feature:", feature);

    // Define calculateOffset function
    function calculateOffset(angle, length) {
        var offsetX = Math.cos((angle - 90) * Math.PI / 180) * length;
        var offsetY = Math.sin((angle - 90) * Math.PI / 180) * length;
        return [offsetX, offsetY];
    }

    // Calculate common offset for all arrow markers using the calculateOffset function
    var offset = calculateOffset(lhead, 0.00000000000009); // Adjust arrow offset as needed

    // Create left arrow marker
    var leftMarker = L.marker([coords[1] + offset[1], coords[0] + offset[0]], {
        icon: arrow,
        rotationAngle: lhead
    });
    leftMarker.addTo(map);
    console.log("Left arrow marker added to map:", leftMarker);

    // Create label marker
    var labelMarker = L.marker([coords[1] + offset[1], coords[0] + offset[0]], {
        icon: L.divIcon({
            className: 'arrow-label',
            html: label,
            iconAnchor: [0, 0],
        })
    });
    labelMarker.addTo(map);
    console.log("Label marker added to map:", labelMarker);

    // Create right arrow marker
    var rightMarker = L.marker([coords[1] + offset[1], coords[0] + offset[0]], {
        icon: arrow,
        rotationAngle: rhead
    });
    rightMarker.addTo(map);
    console.log("Right arrow marker added to map:", rightMarker);

    // Create heading arrow marker
    var headingMarker = L.marker([coords[1] + offset[1], coords[0] + offset[0]], {
        icon: H_arrow,
        rotationAngle: head
    });
    headingMarker.addTo(map);
    console.log("Heading arrow marker added to map:", headingMarker);

    return [leftMarker, labelMarker, rightMarker, headingMarker];
}
//======================================================
// Loop through each feature in the data & place markers
//======================================================
data.features.forEach(function(feature) {   
    // Define variables to access fields (sensor coords, rotation angles for arrows)
    var coords = feature.geometry.coordinates; // Sensor coords stored as long lat (XY)
    var lhead = feature.properties.lhead; // left arrow angles stored in data (sensors.js)
    var rhead = feature.properties.rhead; // right arrow angles
    var head = feature.properties.head; // heading angles
    var label = feature.properties.L_ct; // label for left arrow

    // Call the function to place the rotated symbols on the map for each feature
    var markers = placeRotatedSymbol(coords, lhead, rhead, head, label, feature); 

    // Add circle marker for each point
    L.circleMarker([coords[1], coords[0]], { // Reverse the coords, leaflet takes lat long (YX)
        pane: 'tooltipPane',
        radius: circleRadius,
        color: '#FFFFFF',
        weight: 1,
        fill: true,
        fillColor: '#DBA044',
        fillOpacity: 1
    }).addTo(map);

    // Apply scale-dependent visibility 
    map.on('zoomend', function() {
        var zoomLevel = map.getZoom();
        if (zoomLevel >= 17) {
            markers.forEach(function(marker) {
                map.addLayer(marker);
            });
        } else {
            markers.forEach(function(marker) {
                map.removeLayer(marker);
            });
        }
    });
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.