Coder Social home page Coder Social logo

Comments (6)

rbrundritt avatar rbrundritt commented on May 18, 2024

The Azure Maps drawing tools don't have a copy/paste feature, so adding this to the labelling tool would likely be a lot of work. That said, I have been playing around with an idea of how this would work and some of us are considering creating and open source "advanced" drawing tools module for Azure Maps which might be the way to go here.

from satellite-imagery-labeling-tool.

rbrundritt avatar rbrundritt commented on May 18, 2024

I took a stab at creating a rough example of a copy/paste extension for the Azure Maps drawing tools. I haven't tested this a lot, so might be buggy, but seems to work well. Good starting point.

<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>

    <meta charset="utf-8" />    
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />


    <!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
    <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
    <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>

    <!-- Add references to the Azure Maps Map Drawing Tools JavaScript and CSS files. -->
    <link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.css" type="text/css" />
    <script src="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.js"></script>
    
    <script>
        var map, drawingManager;
		var copiedShape;
		var mousePosition;
		var dmSource;

        function GetMap() {
            //Initialize a map instance.
            map = new atlas.Map('myMap', {
                view: 'Auto',

                authOptions: {
                    authType: 'subscriptionKey',
                    subscriptionKey: '<Your Azure Maps Key>'
                }
            });

            //Wait until the map resources are ready.
            map.events.add('ready', function () {

                //Create an instance of the drawing manager and display the drawing toolbar.
                drawingManager = new atlas.drawing.DrawingManager(map, {
                    toolbar: new atlas.control.DrawingToolbar({ position: 'top-right', style: 'light' })
                });			

				dmSource = drawingManager.getSource();	
				
				//Monitor the mouse position over the map.
                map.events.add('mousemove', mouseMoved);
				map.events.add('mouseout', () => { mousePosition = null });
				
				//Add keyboard shortcuts for copy/paste of shapes.
				map.getMapContainer().addEventListener('keyup', keyup);
            });
        }
		
		function keyup(e) {
			//Check to see if the control button is held.
			if(e.ctrlKey) {
				//Check to see if user pressed C to copy.
				if(e.keyCode === 67) {
					//Copy the last drawn shape in the drawing manager.
					var s = dmSource.getShapes();
					
					if(s.length > 0) {
						//Copy JSON version of shape. 
						copiedShape = s[s.length - 1].toJson();
						
						//Delete ids to prevent issues.
						delete copiedShape.id;
						delete copiedShape.properties._azureMapsShapeId;
					} else {
						copiedShape = null;
					}
				} 
				
				//Check to see if user pressed V to paste.
				else if (e.keyCode === 86){
					pasteShape();			
				}
			}
		}
		
		function mouseMoved(e) {
			mousePosition= e.position;
		}
		
		/*function shapeClicked(e) {
			//Check to see if in copy/paste mode.
			var elm = document.getElementById('copyPasteMode');
			if(elm.checked){
				var ds = drawingManager.getSource();
			
				//Check to see if the clicked shape is in the drawing manager data source.
				for(var i=0;i< e.shapes.length;i++){
					//Ensure object is a Shape and is in the drawing manager data source.
					if(e.shapes[i] instanceof atlas.Shape && ds.getShapeById(e.shapes[i].getId())) {
						//Storing json copy.
						copiedShape = e.shapes[i].toJson();
						
						//Delete ids to prevent issues.
						delete copiedShape.id;
						delete copiedShape.properties._azureMapsShapeId;						
						
						//Only select the first selected shape.
						return;
					}
				}
			}
		}*/
		
		function pasteShape() {
			//Paste the shape to where the mouse is over the map, or the center of the map.
			var pasteCenter = mousePosition || map.getCamera().center;
		
			if(copiedShape) {
				//Calculate the center point of the copied shape based on bounding box for simplicity. 
				var copiedCenter = atlas.data.BoundingBox.getCenter(atlas.data.BoundingBox.fromData(copiedShape));
			
				//Calculate the offsets. Use pixels at zoom level 22 for visible accuracy.
				var p = atlas.math.mercatorPositionsToPixels([copiedCenter, pasteCenter], 22);
				var dx = p[1][0] - p[0][0];
				var dy = p[1][1] - p[0][1];
				
				var shapeToPaste = createShapeToPaste(dx, dy);
				
				var ds = drawingManager.getSource();
				ds.add(shapeToPaste);
				
				//Get the last shape added to the data source and put it into edit mode.
				var shapes = ds.getShapes();
				var s = shapes[shapes.length - 1];
				drawingManager.edit(s);
			}
		}
		
		function createShapeToPaste(dx, dy) {
			var g = copiedShape.geometry;
		
			var newGeometry = {
				type: g.type,
				coordinates: [] 
			};		

			//Offset the positions of the geometry.
			switch(g.type) {
				case 'Point':
					newGeometry.coordinates = getOffsetPositions([g.coordinates], dx, dy)[0];
					break;
				case 'LineString':
				case 'MultiPoint':					
					newGeometry.coordinates = getOffsetPositions(g.coordinates, dx, dy);
					break;
				case 'Polygon':
				case 'MultiLineString':					
					newGeometry.coordinates = g.coordinates.map(r => {
						return getOffsetPositions(r, dx, dy);
					});
					break;
				//MultiPolygon
			}
			
			//Create a GeoJSON featuret from new geometry, copy the properties. 
			return new atlas.data.Feature(newGeometry, JSON.parse(JSON.stringify(copiedShape.properties)));		
		}
		
		function getOffsetPositions(positions, dx, dy) {
			//Convert positions to pixel at zoom level 22.
			var pixels = atlas.math.mercatorPositionsToPixels(positions, 22);
			
			//Offset pixels.
			for(var i=0, len = pixels.length; i< len;i++) {
				pixels[i][0] += dx;
				pixels[i][1] += dy;
			}			
			
			//Convert back to positions.
			return atlas.math.mercatorPixelsToPositions(pixels, 22);
		}
    </script>
</head>
<body onload="GetMap()">
    <div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div>
	
	<input id="copyPasteMode" type="checkbox" onclick="toggleCopyPasteMode()" />

    <fieldset style="width:calc(100% - 30px);min-width:290px;margin-top:10px;">
        <legend>Drawing tools - copy/paste extension</legend>
		This is a rough example of adding a copy/paste capability to the drawing tools in Azure Maps.
		
		When the map has focus and you press CTRL + C, the last added shape in the drawing manager will be copied to memory. 
		When you press CTRL + V, the copied shape will be added to the map, centered over the mouse pointer if it is above the map, otherwise the shape will be added to the center of the map.
		Once a shape has been added, the drawing tools go into edit mode for that shape so that fine tune adjustments can be made by dragging the shape.
		Note that circles will maintain their radiu, and as such they could have a different asize pixel area.
    </fieldset>
</body>
</html>

from satellite-imagery-labeling-tool.

reeddolphin avatar reeddolphin commented on May 18, 2024

Ah that's awesome, appreciate the super quick response! I had a hard time getting the drawing keyboard shortcuts to work in the non-local Labeler so I was hopeful my fruitless search for a c&p feature in Azure Maps wasn't going to apply here.

I am a bit of a html neophyte so I might have to come back to your extension at a later point 😅 Is there a project roadmap for the satellite-imagery-labeling-tool or is it mostly in the POC phase these days? the simplicity of it's design is very appealing!

from satellite-imagery-labeling-tool.

rbrundritt avatar rbrundritt commented on May 18, 2024

The satellite-imagery-labeling-tool is a bit of a side project. It was created as part of a disaster response mission some of us were working on last year and we made it open source and have been improving it from time to time. Inside of Microsoft it's been used in at least a dozen different projects so far and has a lot more usage than we expected.

from satellite-imagery-labeling-tool.

rbrundritt avatar rbrundritt commented on May 18, 2024

I took a crack at this today and added in copy paste support. To use it, do the following:

  1. Go into edit mode and select a shape.
  2. Press CTRL + c to copy the selected shape into memory.
  3. Press CTRL + v any time afterwards to paste the shape to the map.

In the settings you can control how the shapes offset when pasted to the map.

from satellite-imagery-labeling-tool.

reeddolphin avatar reeddolphin commented on May 18, 2024

wow awesome thanks so much! it's a really neat tool and it's awesome that it's OSS.

from satellite-imagery-labeling-tool.

Related Issues (12)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.