in my program I have created polygons on a graphicsLayer from coordinates on my mapView. When I hover over a polygon, I want to highlight that polygon with orange color.
require([
"esri/Map",
"esri/views/MapView",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/widgets/Search",
"dojo/dom",
"esri/renderers/UniqueValueRenderer",
"esri/symbols/SimpleLineSymbol"
], function (Map, MapView, Graphic, GraphicsLayer, Search, dom, UniqueValueRenderer, SimpleLineSymbol) {
map = new Map({
basemap: "streets-navigation-vector"
});
var center = app.addresses[0].center;
view = new MapView({
container: "viewDiv",
map: map,
center: center, // longitude, latitude
zoom: 15,
highlightOptions: {
color: "orange"
}
});
var search = new Search({
view: view,
container: "search"
});
graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
var i = 0;
app.addresses.forEach(function (address) {
var polygon = {
type: "polygon",
rings: address.polygon_rings
};
address.polygonGraphic = new Graphic({
geometry: polygon,
symbol: address.parking_zone
});
graphicsLayer.add(address.polygonGraphic);
i++;
});
view.on("click", function(event){
var screenPoint = {
x: event.x,
y: event.y
};
view.hitTest(screenPoint).then(function (response) {
if (response.results.length) {
var graphic = response.results.filter(function (result) {
// check if the graphic belongs to the layer of interest
return result.graphic.layer === graphicsLayer;
})[0].graphic;
// do something with the result graphic
ToggleSelectedAddress(parseInt(graphic.uid));
}
});
});
view
.when()
.then(function() {
return graphicsLayer.when();
})
.then(function(layer) {
// Set up an event handler for pointer-down (mobile)
// and pointer-move events (mouse)
// and retrieve the screen x, y coordinates
return view.whenLayerView(layer);
})
.then(function(layerView) {
view.on("pointer-move", eventHandler);
view.on("pointer-down", eventHandler);
function eventHandler(event) {
// the hitTest() checks to see if any graphics in the view
// intersect the x, y coordinates of the pointer
view.hitTest(event).then(getGraphics);
}
let highlight;
function getGraphics(response) {
// the topmost graphic from the hurricanesLayer
// and display select attribute values from the
// graphic to the user
if (response.results.length) {
const graphic = response.results.filter(function(result) {
if(result.graphic.layer === graphicsLayer){
layerView.highlight(result.graphic);
}
return result.graphic.layer === graphicsLayer;
})[0].graphic;
if(highlight) {
console.log("highlighted");
highlight.remove();
}
// highlight all features belonging to the same hurricane as the feature
// returned from the hitTest
highlight = layerView.highlight(graphic);
} else {
// remove the highlight if no features are
// returned from the hitTest
highlight.remove();
highlight = null;
}
}
});
});
I even tried creating functions that change the symbol on those polygon graphics, but to no success.
I think, that the else statement at the end is never executed. Which means, that the hitTest almost always returns a result. I debugged this a little and I saw, that the results are streets, buildings and such. After filtering those results I get the correct graphics I wish to highlight. However, layerView.highlight(graphic) doesn't work. This is how I create my mapView:
view = new MapView({
container: "viewDiv",
map: map,
center: center, // longitude, latitude
zoom: 15,
highlightOptions: {
color: "orange"
}
});
When I take the hovered graphic and change its' symbol to orange, it gets highlighted, but doesn't get unhighlighted once I unhover the element (since the else{} statement is almost never executed). Can anyone explain why hitTest always returns a result and why .highlight() doesn't work?
You problem is that you are highlighting when highlight is null, that is the first hit at start or after no feature is hit. You need to change,
if (highlight) {
return;
}
for
if (highlight) {
highlight.remove();
}
That means, if there is a feature highlighted, then remove it. Then highlight the new hit feature.
hitTest
returns the topmost feature from each layer that intersects the
specified screen coordinates
(ArcGIS Doc - MapView hitTest).
Here is the code modification from the ArcGIS example,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>Access features with pointer events - 4.14</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.14/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.14/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer"
], function(Map, MapView, FeatureLayer) {
const hurricanesLayer = new FeatureLayer({
url:
"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Hurricanes/MapServer/1",
outFields: ["*"]
});
const map = new Map({
basemap: "dark-gray",
layers: [hurricanesLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [-61.125537, 35.863534],
zoom: 4,
highlightOptions: {
color: "orange"
}
});
view
.when()
.then(function() {
return hurricanesLayer.when();
})
.then(function(layer) {
const renderer = layer.renderer.clone();
renderer.symbol.width = 4;
renderer.symbol.color = [128, 128, 128, 0.8];
layer.renderer = renderer;
// Set up an event handler for pointer-down (mobile)
// and pointer-move events (mouse)
// and retrieve the screen x, y coordinates
return view.whenLayerView(layer);
})
.then(function(layerView) {
view.on("pointer-move", eventHandler);
view.on("pointer-down", eventHandler);
function eventHandler(event) {
// the hitTest() checks to see if any graphics in the view
// intersect the x, y coordinates of the pointer
view.hitTest(event).then(getGraphics);
}
let highlight, currentYear, currentName;
function getGraphics(response) {
// the topmost graphic from the hurricanesLayer
if (response.results.length) {
const features = response.results.filter(function(result) {
return result.graphic.layer === hurricanesLayer;
});
if (features.length) {
const graphic = features[0].graphic;
if (highlight) {
highlight.remove();
}
highlight = layerView.highlight(graphic);
return;
}
}
// remove the highlight if no features, of the layer, are
// returned from the hitTest
highlight.remove();
highlight = null;
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Related
I am using this sample, which uses layer blending and effect on multiple layers to create a more artistic way of highlighting features selected by the user. When the application loads, the basemap is displayed over all other layers in the map. When a user clicks on a country, the country will be highlighted.
The light gray canvas vector tiles layer and a countries feature layer are added to a group layer and the destination-over blendMode is set on the group layer. With the destination-over blendMode, the background layer covers, or is placed over, the top layer. The content of the top layer is visible where both layers do not overlap. When the app loads, you see the modern antique vector tiles basemap on top of the groupLayer.
My question is, is there a way to do the same with Feature Access instead of using portal ID.
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>
Highlight feature with effects and blending | Sample | ArcGIS API for
JavaScript 4.21
</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#messageDiv {
padding-left: 10px;
padding-right: 10px;
}
</style>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.21/esri/themes/light/main.css"
/>
<script src="https://js.arcgis.com/4.21/"></script>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/layers/VectorTileLayer",
"esri/Graphic",
"esri/layers/FeatureLayer",
"esri/layers/GraphicsLayer",
"esri/layers/GroupLayer"
], (
WebMap,
MapView,
VectorTileLayer,
Graphic,
FeatureLayer,
GraphicsLayer,
GroupLayer
) => {
const map = new WebMap({
basemap: {
portalItem: {
id: "f35ef07c9ed24020aadd65c8a65d3754" // modern antique vector tiles
}
}
});
const vtLayer = new VectorTileLayer({
portalItem: {
id: "2afe5b807fa74006be6363fd243ffb30" // gray vector tiles canvas
}
});
const countries = new FeatureLayer({
portalItem: {
id: "53a1e68de7e4499cad77c80daba46a94" // boundaries of countries
}
});
// This group layer groups the gray canvas vector tiles and
// countries feature layer.
// With destination-over blendMode, the background layer covers
// the top layer. The top layer is put behind the destination layer.
// So when the app starts, the basemap layer will be shown over this layer
const groupLayer = new GroupLayer({
layers: [vtLayer, countries],
blendMode: "destination-over"
});
map.add(groupLayer);
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 6,
center: [2, 46],
constraints: {
snapToZoom: false,
minScale: 147914381
}
});
let layerView, animation;
// countryGraphicsLayer is added to the view's basemap.
// It will contain black polygon covering the extent of the world
// the country graphic will also be added to this layer when user clicks a country.
// With destination-in blend mode, the contents of background layer is
// kept where it overlaps with top layer. Everything else is made transparent.
// In this case, the countryGraphicsLayer will be displayed underneath
// modern antique vector tiles basemap.
// The bloom effect will add a glow around the selected country.
const countryGraphicsLayer = new GraphicsLayer({
blendMode: "destination-in",
effect: "bloom(200%)"
});
map.loadAll().then(async () => {
addWorld();
map.basemap.baseLayers.getItemAt(1).blendMode = "multiply";
// add the buffer graphicslayer to the basemap
map.basemap.baseLayers.add(countryGraphicsLayer);
// get a reference ot the countries featurelayer's layerview
// layerview will be queried to get the intersecting country
// when user clicks on the map
layerView = await view.whenLayerView(countries);
});
view.ui.add("messageDiv", "top-right");
const symbol = {
type: "simple-fill",
color: "white",
outline: null
};
// listen to the view's click event
view.on("click", async (event) => {
// query the countries featurelayer for a country that intersects the point
// user clicked on
const {
features: [feature]
} = await layerView.queryFeatures({
geometry: view.toMap(event),
returnGeometry: true,
maxAllowableOffset: 10000,
outFields: ["*"]
});
countryGraphicsLayer.graphics.removeAll();
animation && animation.remove();
let world = addWorld();
// add the clicked country feature to the graphicslayer
if (feature) {
feature.symbol = symbol;
countryGraphicsLayer.graphics.add(feature);
// add a fade animation to show the highlight effect
// for the selected country
animation = fadeWorld(world);
// zoom to the highlighted country
view.goTo(
{
target: view.toMap(event),
extent: feature.geometry.extent.clone().expand(1.8)
},
{ duration: 1000 }
);
}
});
function addWorld(world) {
world = new Graphic({
geometry: {
type: "extent",
xmin: -180,
xmax: 180,
ymin: -90,
ymax: 90
},
symbol: {
type: "simple-fill",
color: "rgba(0, 0, 0, 1)",
outline: null
}
});
countryGraphicsLayer.graphics.add(world);
return world;
}
// add a fading animation when user clicks on a country
function fadeWorld(world) {
let timer;
// requestAnimationFrame method specifies "frame" function
// to perform an animation where the opacity of the world polygon graphic
// decreased by 0.1 until it is 0 or completely transparent
// then the animation is cancelled
function frame() {
const symbol = world.symbol.clone();
symbol.color.a = Math.max(0, symbol.color.a - 0.1);
world.symbol = symbol;
if (symbol.color.a > 0) {
timer = requestAnimationFrame(frame);
}
}
frame();
return {
remove() {
cancelAnimationFrame(timer);
}
};
}
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="messageDiv" class="esri-widget esri-heading">
<h4 class="esri-heading">Click on a country</h4>
</div>
</body>
</html>
Mapbox GL JS w/ w3w grid
Hi, I'm just playing around with the What3Words grid on Mapbox code from the tutorial. (https://developer.what3words.com/tutorial/displaying-the-what3words-grid-on-a-mapbox-map)
I'm trying to make the tiles from the grid interactive, kind of like in the w3w website (clickable, hover effect, getting data from them, etc), but the grid doesn't seem to work when the data source is loaded as a 'fill' layer on Mapbox, it only works as a 'line' layer type. Every single example I find online uses Polygons (or MultiPolygons) from a fill layer type, but I can't see nothing around with bounding boxes.
(Basically trying to achieve something like this, but with every tile instead of the states: https://docs.mapbox.com/mapbox-gl-js/example/hover-styles/)
I don't really know what's going on, why can't I add the source data as a fill layer? Is there a way to load the data as Polygons instead of bounding boxes?
Thanks.
Code (from the tutorial):
<html>
<head>
<script src="https://assets.what3words.com/sdk/v3.1/what3words.js?key=YOUR_API_KEY"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.js"></script>
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css" rel="stylesheet" />
<style>
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// Create the Mapbox
mapboxgl.accessToken = "YOUR_MAPBOX_TOKEN";
let map = new mapboxgl.Map({
container: "map", // container id
style: "mapbox://styles/mapbox/streets-v9", // stylesheet location
center: [-0.195499, 51.52086], // starting position [lng, lat]
zoom: 18 // starting zoom
});
map.addControl(new mapboxgl.NavigationControl());
</script>
<script>
function drawGrid() {
const zoom = map.getZoom();
const loadFeatures = zoom > 17;
if (loadFeatures) { // Zoom level is high enough
var ne = map.getBounds().getNorthEast();
var sw = map.getBounds().getSouthWest();
// Call the what3words Grid API to obtain the grid squares within the current visble bounding box
what3words.api
.gridSectionGeoJson({
southwest: {
lat: sw.lat, lng: sw.lng
},
northeast: {
lat: ne.lat, lng: ne.lng
}
}).then(function(data) {
// Get the grid source from the map (it won't exist initally)
var grid = map.getSource('grid');
if (grid === undefined) {
// Create a source of type 'geojson' which loads the GeoJSON returned from the what3words API
map.addSource('grid', {
type: 'geojson',
data: data
});
// Create a new layer, which loads data from the newly created data source
map.addLayer({
id: 'grid_layer',
type: "line",
source: 'grid',
layout: {
"line-join": "round",
"line-cap": "round"
},
paint: {
"line-color": '#777',
"line-width": .5
}
});
} else {
// The source and map layer already exist, so just update the source data to be the new
// GeoJSON returned from the what3words API
map.getSource('grid').setData(data);
}
}).catch(console.error);
}
// If we have reached the required zoom level, set the 'grid_layer' to be visible
var grid_layer = map.getLayer('grid_layer');
if (typeof grid_layer !== 'undefined') {
map.setLayoutProperty('grid_layer', 'visibility', loadFeatures ? 'visible' : 'none');
}
}
// When the map is either loaded or moved, check to see if the grid should be draw
// if the appropriate zoom level has been met, and if so draw it on.
map
.on('load', drawGrid)
.on('move', drawGrid);
</script>
</body>
</html>
im working on a PWA which retrieves the users location via geolocation-API, places a pin to the current location of the user and allows him to drag the pin to a certain location.
this works perfectly in chrome but when testing it in safari, the map only displays the whole world on
the map and doesnt allow zooming further than a few pinches + it doesnt place a marker.
// configure pin
function addDraggableMarker(map, behavior) {
// create icon
var svgMarkup = /* some random svg here */;
var icon = new H.map.Icon(svgMarkup);
// position the pin
var coords = {
lat: lat,
lng: lng
};
// initialize pin
window.marker = new H.map.Marker(
coords, {
icon: icon
}, {
volatility: true
}
);
// make pin draggable
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target.offset = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
behavior.enable();
window.markerMoved = target.getGeometry();
}
}, false);
// Listen to the drag event and move the position of the marker as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target.offset.x, pointer.viewportY - target.offset.y));
}
}, false);
}
// click on the button which displays the map
$("#addLocation").on('click', function() {
// 1. connect to API
window.platform = new H.service.Platform({
'apikey': 'MY_API_KEY'
});
window.defaultLayers = platform.createDefaultLayers();
// 2. initialize map
window.map = new H.Map(document.getElementById('map'),
defaultLayers.vector.normal.map, {
center: {
lat: lat,
lng: lng
},
zoom: 16,
pixelRatio: window.devicePixelRatio || 1
});
// stretch map to size of container
window.addEventListener('resize', () => map.getViewPort().resize());
// 3. make map interactive
//Behavior implements default interactions for pan/zoom (also on mobile touch environments)
window.behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// 4. add map UI
window.ui = H.ui.UI.createDefault(map, defaultLayers, "de-DE");
// Add the click event listener.
addDraggableMarker(map, behavior);
});
I copied your code into jsfiddle example and everything works as expected in Safari browser. After clicking the button "AddLocation" the map is displayed at correct location + zoom with marker at the center.
There is one small issue with your code when the Marker is created. volatility property should be next to the icon property:
new H.map.Marker(
coords, {
icon: icon,
volatility: true
}
);
I am trying to build a map-based site that identifies a user's geolocation, draws a marker at his/her position, and then uses that marker/location to click on a data layer (in this case, a GeoJSON layer). Essentially, the user's location should trigger an infowindow automatically if he or she is located on an area delineated by the geojson file. Ideally, each time the user changes location it will be clicking the map to check this GeoJSON layer for info.
So far, I can get the user's location successfully. The map centers on that location. And manual clicks on the GeoJSON layer also populate the info window correctly. But it's not clicking automatically when getting the user location.
I've seen lots of examples where a forced click on a marker takes place, but I can't seem to find one that clicks a data layer. Unfortunately I'm more of a GIS person assigned to a coding job on this, which is way out of my league, so I'm struggling to figure out where I'm going wrong with this.
Here's the script, perhaps I'm making a mistake here:
$<script type="text/javascript">
//centers the map on Iowa City
var map,
currentPositionMarker,
mapCenter = new google.maps.LatLng(41.661354, -91.534729),
map;
function initializeMap()
{
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 18,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
map.data.loadGeoJson('test2.json');
map.data.setStyle({
strokeColor: '#2687bf',
strokeWeight: 5
});
map.data.addListener('click', function(event) {
document.getElementById('info-box').textContent =
event.feature.getProperty('description');
});
}
function locError(error) {
// the current position could not be located
alert("The current position could not be found!");
}
function setCurrentPosition(pos) {
currentPositionMarker = new google.maps.Marker({
map: map,
draggable: true,
position: new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
),
title: "Current Position"
});
new google.maps.event.trigger( 'test2.json', 'click' );
map.panTo(new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
));
}
function displayAndWatch(position) {
// set current position
setCurrentPosition(position);
// watch position
watchCurrentPosition();
}
function watchCurrentPosition() {
var positionTimer = navigator.geolocation.watchPosition(
function (position) {
setMarkerPosition(
currentPositionMarker,
position
);
});
}
function setMarkerPosition(marker, position) {
marker.setPosition(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude)
);
}
function initLocationProcedure() {
initializeMap();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayAndWatch, locError);
} else {
alert("Your browser does not support the Geolocation API");
}
}
$(document).ready(function() {
initLocationProcedure();
});
</script>
</head>
<body>
<div id="map_canvas" style="height:600px;"></div>
<div id="info-box" style="height:250px;">INFO</div>
</body>
</html>
And here are links to my JSON and full HTML file for this:
https://sites.google.com/site/ecocritkml/coding
The JSON is obviously specific to Iowa City, Iowa, but it could be modified easily in a text editor. Any ideas would be really helpful here.
I think I got it.
I had to use a few tricks (some maybe a little dirty)
I put a 500ms delay with setTimeout; this could have been done more elegantly, no doubt
I make a temporary polygon, because it permits to use containsLocation()
I don't invoke a click, but there is a loop over the polygon features, I read the description there, and set it to the div
..
<!doctype html>
<html lang="en">
<head>
<title>Google maps</title>
<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src=http://maps.google.com/maps/api/js?v=3&sensor=true&language=en"></script>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map_canvas {
height: 100%;
}
#info-box {
background-color: white;
border: 1px solid black;
bottom: 30px;
height: 20px;
padding: 10px;
position: absolute;
left: 30px;
}
</style>
<script type="text/javascript">
//centers the map on Iowa City
var map,
currentPositionMarker,
mapCenter = new google.maps.LatLng(41.661354, -91.534729),
map;
function initializeMap() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 18,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
map.data.loadGeoJson('test2.json');
map.data.setStyle({
strokeColor: '#2687bf',
strokeWeight: 5
});
map.data.addListener('click', function(event) {
document.getElementById('info-box').textContent = event.feature.getProperty('description');
});
}
function locError(error) {
// the current position could not be located
}
function setCurrentPosition(pos) {
currentPositionMarker = new google.maps.Marker({
map: map,
draggable: true,
position: new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
),
title: "Current Position"
});
// Wait half a second, then take a loop of the features, see if the marker is inside one of them
setTimeout(function() {
map.data.forEach(function(feature){
var figure = feature.getGeometry();
if(figure.getType() == 'Polygon') {
// make a temporary polygon, see if the marker is inside
var tempPolygon = new google.maps.Polygon({
paths: figure.getAt(0).getArray(), // #see http://stackoverflow.com/questions/33249127/using-containslocation-with-a-google-maps-data-polygon
map: null
});
if(google.maps.geometry.poly.containsLocation(currentPositionMarker.getPosition(), tempPolygon)) {
// marker is inside this feature
// invoke a click. well, just pretend ...
document.getElementById('info-box').textContent = feature.getProperty('description');
}
}
var b;
})
}, 500);
map.panTo(new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
));
}
function displayAndWatch(position) {
// set current position
setCurrentPosition(position);
// watch position
watchCurrentPosition();
}
function watchCurrentPosition() {
var positionTimer = navigator.geolocation.watchPosition(function (position) {
setMarkerPosition(
currentPositionMarker,
position
);
});
}
function setMarkerPosition(marker, position) {
marker.setPosition(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
)
);
// now we see if the marker is inside one of the polygons
var a = 0;
}
function initLocationProcedure() {
initializeMap();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayAndWatch, locError);
}
else {
// alert("Your browser does not support the Geolocation API");
}
}
$(document).ready(function() {
initLocationProcedure();
});
</script>
</head>
<body>
<div id="map_canvas" style="height:600px;"></div>
<div id="info-box" style="height:250px;">INFO</div>
</body>
</html>
i know it is possible to draw circle or rectangle on tile images when using leaflet.js. here is one link http://jsfiddle.net/tridip/p6ssbvqj/
leaflet has function called circle() polygon() etc
my interface is like that i have 4 button one is circle,rectangle,load image, save image.
when page will load first time then i will show a image by leaflet.js and when user click on circle or rectangle button then i have to allow user to draw a circle or rectangle on image. the question which jquery or any javascript library i should use which will allow to draw a circle or rectangle on image ?
next i need to store those coordinate of circle or rectangle at client side because later i could save those info in db.
3rd one when i will reload images again i need to show drawn circle or rectangle on same image and in same location where user has drawn.
please guide me how to achieve it. i have never done before so no idea i have. please help me. thanks
EDIT 1
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
1) What is the meaning of L.FeatureGroup()?
What does L.FeatureGroup() do?
2) What does the code below do?
var drawControl = new L.Control.Draw({
draw: {
position: 'topleft',
polygon: {
allowIntersection: false,
drawError: {
color: '#b00b00',
timeout: 1000
},
shapeOptions: {
color: '#bada55'
},
showArea: true
},
polyline: {
metric: false
},
circle: {
shapeOptions: {
color: '#662d91'
}
}
},
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
what the above code is doing. it seems that the above code is trying to draw control on map programmatically. may be i am not right.
because if the above line is related to draw control on map programmatically then there should be coordinate or something relavent should be there but i have not
found anything in the above code. so please tell me what the above code is doing ?
3) if i need to draw any shape on map then do i need to first add any layer on map because as per your code you first add layer by this line
map.addLayer(drawnItems);
4) the below code is clear
if (type === 'marker') {
coords = JSON.stringify(layer._latlng);
}
the above code storing lat and lang as coordinate in variable but you have missded to show another set of code where i will provide
lat and lang details as coordinate then code will draw same shape in right position as per lat & lang value.
please read my all 4 point and please write answer to drive out my confusion. specially point 1 & 2 related code is not clear to me
and next give me code where i will pass shape name and latlang then leaflet api will draw shape accordingly.
thanks
As gusper noted, Leaflet.draw is a ready-made library for interactive drawing on Leaflet maps. Here's their demo slightly modified to display the coordinates of shapes drawn on the map.
If necessary, you can store these coordinates in a DB, and then use the native Leaflet functions to re-draw these shapes from the list of coordinates.
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
}),
map = new L.Map('map', {
layers: [osm],
center: new L.LatLng(-37.7772, 175.2756),
zoom: 15
});
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
var drawControl = new L.Control.Draw({
draw: {
position: 'topleft',
polygon: {
allowIntersection: false,
drawError: {
color: '#b00b00',
timeout: 1000
},
shapeOptions: {
color: '#bada55'
},
showArea: true
},
polyline: {
metric: false
},
circle: {
shapeOptions: {
color: '#662d91'
}
}
},
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
map.on('draw:created', function(e) {
var type = e.layerType;
var layer = e.layer;
var coords;
console.log(e);
if (type === 'marker') {
coords = JSON.stringify(layer._latlng);
}
if (type === 'circle') {
coords = JSON.stringify(layer._latlng) + " " + layer._mRadius;
}
if (type === 'rectangle') {
coords = JSON.stringify(layer._latlngs);
}
if (type === 'polygon') {
coords = JSON.stringify(layer._latlngs);
}
if (type === 'polyline') {
coords = JSON.stringify(layer._latlngs);
}
document.getElementById("coords").innerHTML = coords;
drawnItems.addLayer(layer);
});
<head>
<title>Leaflet Draw</title>
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.draw/lib/leaflet/leaflet.css" />
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.draw/leaflet.draw.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="lib/leaflet/leaflet.ie.css" />
<link rel="stylesheet" href="leaflet.draw.ie.css" />
<![endif]-->
<script src="http://leaflet.github.io/Leaflet.draw/lib/leaflet/leaflet.js"></script>
<script src="http://leaflet.github.io/Leaflet.draw/leaflet.draw.js"></script>
</head>
<body>
<div id="map" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>
<div id="coords" style="position: fixed; bottom: 0; right: 0; width: 50%; height: 20%; z-index: 99; background-color: white; text-wrap: "></div>