Drawing custom shapes and text on the map in place of geojson

1 Answer 402 Views
Drawing API Map
Idel
Top achievements
Rank 1
Idel asked on 10 Dec 2021, 12:11 PM

Hello,

we are drawing a kind of graph on top of the map. We are currently trying to draw some text as well and we have gotten it to work kind of.
At the end I am going to include a small script to show how we are doing it right now and also show what the problem is.
We not only need to draw these things but they need to be clickable too. currently we use geojson with an id that allows us to reference the data behind a geojson point.

with the text we are cheating a bit because we interscept and prevent the default shape from being created and append it's dataItem to our new shape which makes it clickable. the problem is it isnt cleaned up well and it will be drawn over if the data changes. in the worst case if the location changes the new shape will be drawn in the new location but the previously drawn ones in the old location are not cleaned up.

Would be lovely if anyone has a tip on how to do in a nice way.

if you execute the fillowing code you will see the text is drawn on top of the previous text while you cannot see the same effect with the native Geojson Lines


function Guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
} 
function rand() {
    return Math.random()*360 - 180;
}
function onMarkerClick(e) {
    console.log(e);
}
function createMap() {
    var datasrc = new kendo.data.DataSource({
        type: "geojson",
        data: []
    });
    var datasrc1 = new kendo.data.DataSource({
        type: "geojson",
        data: []
    });
    var map = $("#map").kendoMap({
        center: [0, 0],
        zoom: 12,
        layers: [{
            type: "tile",
            urlTemplate: "https://#= subdomain #.tile.openstreetmap.org/#= zoom #/#= x #/#= y #.png",
            subdomains: ["a", "b", "c"],
            attribution: "© <a href='http://osm.org/copyright'>OpenStreetMap contributors</a>"
        },
        {
            type: "shape",
            dataSource: datasrc,
        },{
            type: "shape",
            dataSource: datasrc1,
        }],
        markerClick: onMarkerClick,
        markerCreated: onMarkerCreated,
        shapeCreated: onShapeCreated,
    }).data("kendoMap");

    let arr = [];
    let arr1 = [];
    
    for (var i = 0; i < 20; i++) {
        arr.push({type: "Feature", id: Guid(), geometry: {type: "Point", coordinates: [0,0-i*0.005]}})
        datasrc.data(arr)
    }


    for (var i = 0; i < 30; i++) {
        arr1.push({type: "Feature", id: Guid(), geometry: {type: "LineString", coordinates: [[-5,0.08 - i * 0.002], [5,0.08- i * 0.002]]}})
        datasrc1.data(arr1)
    }
}

$(document).ready(createMap);

function onMarkerCreated(e) {
e.preventDefault()
}
function onShapeCreated(e) {
if (e.shape.dataItem.geometry.type == "Point") {
    console.log("creating shape")
    var bbox = e.shape.bbox();
    var center = bbox.center()
    var label = new kendo.drawing.Text("Lorem Ipsum");
    var labelCenter = label.bbox().center()
    label.position([
        center.x - labelCenter.x,
        center.y - labelCenter.y
    ])
    label.dataItem = e.shape.dataItem;
    e.layer.surface.draw(label);
    e.preventDefault();
} else {
    console.log("creating line")
}
}

1 Answer, 1 is accepted

Sort by
1
Accepted
Georgi Denchev
Telerik team
answered on 15 Dec 2021, 09:12 AM

Hello, Idel,

Thank you for the provided code snippet and details.

You can clear the drawing surface of the particular layer through the clear() method. This should remove the old elements from the map and display only the newest ones.

    for (var i = 0; i < 20; i++) {
        arr.push({type: "Feature", id: Guid(), geometry: {type: "Point", coordinates: [0,0-i*0.005]}})
      	map.layers[1].surface.clear();
        datasrc.data(arr)
    }

Runnable example:

https://dojo.telerik.com/@gdenchev/uwUnADuD 

Let me know if this works for you or if you have any questions.

Best Regards,
Georgi Denchev
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Idel
Top achievements
Rank 1
commented on 16 Dec 2021, 09:38 AM | edited

Helli Georgi,

thanks for the reply.

It does as advertised, but doesn't play nice.
I alluded that we have different types of elements we draw on the map.
For example one element is just the base circle we get by preventing the defolt on the markerCreated event. Another is a geojson line.

Our custom drawn shapes and normal markers still work, but the lines and circles aren't redrawn, even though they are also readded to the datasource with the data() method.

We currently have all these elements on one layer because they need to all be clickable, and we have found that only the top shape layer accepts click events.

Is there a way to tell the Datasource to always redraw all elements or is there a possibility do have click events working through multiple layers?

 

Thanks and best regards

Georgi Denchev
Telerik team
commented on 21 Dec 2021, 08:50 AM

Hi, Idel,

The problem with the click events is discussed in the following forum thread:

https://www.telerik.com/forums/shapeclick-not-working#3637986 

You can dynamically enable/disable the pointer events of a particular layer, Dojo:

https://dojo.telerik.com/@gdenchev/aNetAFID 

I am not entirely certain I understand the problem with the "lines and circles aren't redrawn", would it be possible for you to recreate in a Dojo so I can take a look it?

If it's already reproduced in the provided Dojo, could you please give me a bit more details what the expected result is? Clearing the layer got rid of the multiple layers of text, however I didn't see any other changes apart from that.

Idel
Top achievements
Rank 1
commented on 21 Dec 2021, 10:02 AM

In this dojo https://dojo.telerik.com/imEzuBEJ/2 I draw the lines and text on the same layer. The clear() being called prevents the label from being drawn multiple times on the same spot, but the lines aren't redrawn.

regarding the layers and events. I think I found that one before and there seems to be no fix as I understand it. which is why we draw all the elements on the same layer.
Georgi Denchev
Telerik team
commented on 22 Dec 2021, 11:56 AM

Hi, Idel,

In this case, is it an option for you to add all of the data of the same layer to an array and append it to the dataSource afterwards? This way you wouldn't be drawing the same shapes over and over again, instead you'll draw them all at once when the array is filled up.

    let arr = [];
    
  	for (var i = 0; i < 30; i++) {
        let item = {type: "Feature", id: Guid(), geometry: {type: "LineString", coordinates: [[-5,0.08 - i * 0.002], [5,0.08- i * 0.002]]}}
        arr.push(item);
    }
    for (var i = 0; i < 20; i++) {
        let item = {type: "Feature", id: Guid(), geometry: {type: "Point", coordinates: [0,0-i*0.005]}};
        arr.push(item)
    }
  
  	datasrc.data(arr);

Dojo:

https://dojo.telerik.com/@gdenchev/agAhotOB 

Idel
Top achievements
Rank 1
commented on 22 Dec 2021, 12:26 PM

Hi Georgi,

no it is not possible.
As the different elements, and there can be quite a few per type are retrieved from the backend they should be continuously added to the map.

I can see 2 ways around the problem myself.
1. Draw lines and circles manually like the text, which adds some extra code to maintain.

2. upon updating, add the data to a new datasource and use the setDataSource method of the layer.

I would hope there is a bit nicer way to do it though.

Georgi Denchev
Telerik team
commented on 23 Dec 2021, 02:02 PM

Hi, Idel,

I've tried a couple of more things and apart from the options that you mentioned, the only other possibility is to zoom in/out the map or center it, once the rendering finishes. The zooming/centering clears the excess text elements, however there's no way for me to verify if this approach will work in your application as well.

You can give it a try and if it isn't suitable, you'll have to go with one of the approaches from your previous reply.

Dojo:

https://dojo.telerik.com/@gdenchev/OKUSenub 

Idel
Top achievements
Rank 1
commented on 24 Dec 2021, 09:12 AM

Hi Georgi,
thank you very much.
It does work and seems for our current date performant enough so we are going with that solution for now.

 

Tags
Drawing API Map
Asked by
Idel
Top achievements
Rank 1
Answers by
Georgi Denchev
Telerik team
Share this question
or