Find graphics that are overlapping on the screen.

1493
3
Jump to solution
02-13-2023 02:28 AM
PrashantR
Occasional Contributor

I am using ArcGIS Maps SDK for Javascript 4.20.

I am adding multiple graphics with point geometry and PicturemarkerSymbol in the graphics layer.  

The graphics is basically a black square with size of 100px. How do we find out the squares that are overlapping on the screen?

 

What I have tried so far :

I have tried using toScreen() method to get the screen coordinates of the graphic and  create extents by adding and subtracting width and height from x & y. So I get xmin, ymin, xmax & ymax. This works fine.

But if we add offsets in the symbols then it just doesn't work and I am not sure why. 

Check my code below. It works just fine until the offsets are zero but if I add xoffset of -20 in markerSymbol2 I can see the sqaures overlapping on the screen but it does not work. 

I am just adding the offset in the screen points. Is this the correct way to do it? 

Any suggestions or help would be much appreciated!

Thanks!

 

  require([
            "esri/Map",
            "esri/views/MapView",
            "esri/Graphic",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/layers/GraphicsLayer",
            "esri/geometry/Extent",
            "esri/geometry/geometryEngine",
            "esri/geometry/Geometry",
            "esri/geometry/Point",
            "esri/rest/geometryService"
        ], (Map, MapView, Graphic, SimpleMarkerSymbol, GraphicsLayer, Extent, geometryEngine, Geometry, Point, geometryService) => {
            const map = new Map({
                basemap: "streets"
            });

            const view = new MapView({
                center: [50, 50],
                container: "viewDiv",
                map: map,
                zoom: 5,
            });
            const grLayer = new GraphicsLayer({ graphics: [] });
            map.add(grLayer);

            const point1 = {
                type: "point",
                latitude: 50,
                longitude: 50,
                spatialReference: { wkid: 4326 }
            };
            const point2 = {
                type: "point",
                latitude: 50,
                longitude: 54,
                spatialReference: {  wkid: 4326 }
            };

            const markerSymbol1 = {
                type: 'picture-marker',
                url: 'sqaure.svg',
                width: "80px",
                height: "80px",
                xoffset: 0,
                yoffset: 0
            }
            const markerSymbol2 = {
                type: 'picture-marker',
                url: 'sqaure.svg',
                width: "80px",
                height: "80px",
                xoffset: 0, //-20 here and this will overlap
                yoffset: 0
            }

            // Create a graphic and add the geometry and symbol to it
            const pointGraphic1 = new Graphic({ geometry: point1, symbol: markerSymbol1 });
            const pointGraphic2 = new Graphic({ geometry: point2, symbol: markerSymbol2 });
            grLayer.addMany([pointGraphic1, pointGraphic2]);

            //Return graphic extents in screen coordinates
            var getScreenExtents = function (graphic) {
                var screenPoint = view.toScreen(graphic.geometry);
                //Adding offsets in screenpoints
                screenPoint.x = screenPoint.x + graphic.symbol.xoffset;
                screenPoint.y = screenPoint.y - graphic.symbol.yoffset;
                //return extents
                return new Extent({
                    xmin: screenPoint.x - graphic.symbol.width / 2,
                    ymin: screenPoint.y - graphic.symbol.height / 2,
                    xmax: screenPoint.x + graphic.symbol.width / 2,
                    ymax: screenPoint.y + graphic.symbol.height / 2,
                });;
            }

            var checkOverlap = function () {
                let graphic1 = grLayer.graphics.getItemAt(0);
                let graphic2 = grLayer.graphics.getItemAt(1);
                screenExtent1 = getScreenExtents(graphic1);
                screenExtent2 = getScreenExtents(graphic2);
                if (screenExtent1.intersects(screenExtent2)) {
                    console.log("Overlapping");
                } else {
                    console.log("Not Overlapping");
                }
            }

            view.when(function () {
                checkOverlap();
            });

            view.watch('zoom', zoomChanged);
            function zoomChanged(newValue, oldValue, property, object) {
                checkOverlap();
            }
 

 

 

 

0 Kudos
1 Solution

Accepted Solutions
SamEngel
Occasional Contributor

Hey @PrashantR ! I think it's possible view.toScreen is returning coordinates in pixel space while the xoffset, yoffset, width, and height that come from graphic.symbol are in points. The conversion from points to pixels is 96 / 72 -- you could try multiplying the graphic.symbol values by that and see if it helps!

const pt2px = 96 / 72;

//Adding offsets in screenpoints
screenPoint.x = screenPoint.x + graphic.symbol.xoffset * pt2px;
screenPoint.y = screenPoint.y - graphic.symbol.yoffset * pt2px;

//return extents
return new Extent({
  xmin: screenPoint.x - graphic.symbol.width * pt2px / 2,
  ymin: screenPoint.y - graphic.symbol.height * pt2px / 2,
  xmax: screenPoint.x + graphic.symbol.width * pt2px / 2,
  ymax: screenPoint.y + graphic.symbol.height * pt2px / 2,
});

 

View solution in original post

3 Replies
Sage_Wall
Esri Contributor

Hi @PrashantR ,

I'd suggest using a FeatureLayer instead of a graphics layer.  With the feature layer you can create a query and execute it against the view.extent to get the features visible in the view.  There is an example of creating a feature layer from a graphics array here: https://developers.arcgis.com/javascript/latest/sample-code/layers-featurelayer-collection/

 

Then you can create a query something like this

const queryParams = featureLayer.createQuery();
queryParams.geometry = view.extent;

featureLayer.queryFeatures(queryParams).then(function(results){
  // prints the array of result graphics to the console
  console.log(results.features);
});

 

 

0 Kudos
SamEngel
Occasional Contributor

Hey @PrashantR ! I think it's possible view.toScreen is returning coordinates in pixel space while the xoffset, yoffset, width, and height that come from graphic.symbol are in points. The conversion from points to pixels is 96 / 72 -- you could try multiplying the graphic.symbol values by that and see if it helps!

const pt2px = 96 / 72;

//Adding offsets in screenpoints
screenPoint.x = screenPoint.x + graphic.symbol.xoffset * pt2px;
screenPoint.y = screenPoint.y - graphic.symbol.yoffset * pt2px;

//return extents
return new Extent({
  xmin: screenPoint.x - graphic.symbol.width * pt2px / 2,
  ymin: screenPoint.y - graphic.symbol.height * pt2px / 2,
  xmax: screenPoint.x + graphic.symbol.width * pt2px / 2,
  ymax: screenPoint.y + graphic.symbol.height * pt2px / 2,
});

 

PrashantR
Occasional Contributor

It Works! Thanks a lot.

0 Kudos