Leaflet open multiple popups without binding to a marker - javascript

I am busy writing a simple map implementation using leaflet however I have hit a bit of a snag. I am trying to setup my map and have added a custom control to show labels (which will show the popups) based on the selection of a checkbox.
My custom control is like so:
var checkBoxControl = L.Control.extend({
options: {
position: 'topright'
},
onAdd: function (map) {
var container = L.DomUtil.create('input', 'leaflet-control');
container.style.backgroundColor = 'white';
container.id = 'labels_checkbox';
container.style.width = '30px';
container.style.height = '30px';
container.label = "Labels";
container.type = 'checkbox';
container.onclick = function () {
var checkBox = $("#labels_checkbox");
var checkBoxValue = checkBox[0];
var labelsChecked = checkBoxValue.checked;
var bounds = mymap.getBounds();
for (var i = 0; i < markers.length; i++) {
marker = markers[i].mark;
if (bounds.contains(marker.getLatLng())) {
var previewLabel = markers[i].previewLabel;
if (labelsChecked == true) {
console.log('previewLabel', previewLabel);
mymap.addLayer(previewLabel).fire('popupopen');
} else {
previewLabel.close();
}
}
}
};
return container;
}
});
I can see as per my console that it is fetching all the surrounding markers however the map won't open those markers?
Is there a way for me to open a popup without binding it to a marker?
Thanks

You have to change L.Map behaviour to prevent automatic closing of popups.
It is discussed here.
// prevent a popup to close when another is open
L.Map = L.Map.extend({
openPopup: function (popup, latlng, options) {
if (!(popup instanceof L.Popup)) {
var content = popup;
popup = new L.Popup(options).setContent(content);
}
if (latlng) {
popup.setLatLng(latlng);
}
if (this.hasLayer(popup)) {
return this;
}
// NOTE THIS LINE : COMMENTING OUT THE CLOSEPOPUP CALL
//this.closePopup();
this._popup = popup;
return this.addLayer(popup);
}
});
See this example

Related

How to get the parent child relationship between connected mxgraph

I'm trying to get simplified relationship between connected mxgraph
Question: I'm trying to get the simplified relationship, once the graph is drawn.
i'm trying to get relationship between connected nodes in json.
Note: solution must work for every drawn state.
Here is codepen:
https://codepen.io/eabangalore/pen/pmELpL
i want to get the relationship from above code snippet.
Expected output (from drawn relationship):
[
{"id":0,"parent":"#","text":"A","child":[{"cid":1,"connectionText":"Bangalore"}]},
{"id":1,"parent":0,"text":"B","child":[{"cid":2,"connectionText":""}]},
{"id":2,"parent":1,"text":"C","child":[{"cid":null,"connectionText":""}]}
];
Please refer codepen, as below snippet is not working.
<!--
Copyright (c) 2006-2013, JGraph Ltd
Dynamic toolbar example for mxGraph. This example demonstrates changing the
state of the toolbar at runtime.
-->
<html>
<head>
<title>Toolbar example for mxGraph</title>
<!-- Sets the basepath for the library if not in same directory -->
<script type="text/javascript">
mxBasePath = 'https://jgraph.github.io/mxgraph/javascript/src';
function setGraphData(){
var graphState ={"tagName":"mxGraphModel","children":[{"tagName":"root","children":[{"tagName":"mxCell","attributes":{"id":"0"}},{"tagName":"mxCell","attributes":{"id":"1","parent":"0"}},{"tagName":"mxCell","attributes":{"id":"2","value":"A","style":"","vertex":"1","parent":"1"},"children":[{"tagName":"mxGeometry","attributes":{"x":"271.56251525878906","y":"82.44792175292969","width":"100","height":"40","as":"geometry"}}]},{"tagName":"mxCell","attributes":{"id":"3","value":"B","style":"","vertex":"1","parent":"1"},"children":[{"tagName":"mxGeometry","attributes":{"x":"678.2291717529297","y":"106.89236450195312","width":"100","height":"40","as":"geometry"}}]},{"tagName":"mxCell","attributes":{"id":"4","value":"Bangalore","edge":"1","parent":"1","source":"2","target":"3"},"children":[{"tagName":"mxGeometry","attributes":{"relative":"1","as":"geometry"}}]},{"tagName":"mxCell","attributes":{"id":"5","value":"C","style":"","vertex":"1","parent":"1"},"children":[{"tagName":"mxGeometry","attributes":{"x":"1013.7847747802734","y":"83.55902862548828","width":"100","height":"40","as":"geometry"}}]},{"tagName":"mxCell","attributes":{"id":"6","edge":"1","parent":"1","source":"3","target":"5"},"children":[{"tagName":"mxGeometry","attributes":{"relative":"1","as":"geometry"}}]}]}]};
localStorage.setItem('graphState',JSON.stringify(graphState));
}
function html2json(html){
if(html.nodeType==3){
return {
"tagName":"#text",
"content":html.textContent
}
}
var element = {
"tagName":html.tagName
};
if(html.getAttributeNames().length>0){
element.attributes = html.getAttributeNames().reduce(
function(acc,at){acc[at]=html.getAttribute(at); return acc;},
{}
);
}
if(html.childNodes.length>0){
element.children = Array.from(html.childNodes)
.filter(
function(el){
return el.nodeType!=3
||el.textContent.trim().length>0
})
.map(function(el){return html2json(el);});
}
return element;
}
function json2html(json){
var xmlDoc = document.implementation.createDocument(null, json.tagName);
var addAttributes = function(jsonNode, node){
if(jsonNode.attributes){
Object.keys(jsonNode.attributes).map(
function(name){
node.setAttribute(name,jsonNode.attributes[name]);
}
);
}
}
var addChildren = function(jsonNode,node){
if(jsonNode.children){
jsonNode.children.map(
function(jsonChildNode){
json2htmlNode(jsonChildNode,node);
}
);
}
}
var json2htmlNode = function(jsonNode,parent){
if(jsonNode.tagName=="#text"){
return xmlDoc.createTextNode(jsonNode.content);
}
var node = xmlDoc.createElement(jsonNode.tagName);
addAttributes(jsonNode,node);
addChildren(jsonNode,node);
parent.appendChild(node);
}
addAttributes(json,xmlDoc.firstElementChild);
addChildren(json,xmlDoc.firstElementChild);
return xmlDoc;
}
</script>
<!-- Loads and initializes the library -->
<script type="text/javascript" src="https://jgraph.github.io/mxgraph/javascript/src/js/mxClient.js"></script>
<!-- Example code -->
<script type="text/javascript">
// Program starts here. Creates a sample graph in the
// DOM node with the specified ID. This function is invoked
// from the onLoad event handler of the document (see below).
function main()
{
setGraphData();
// Checks if browser is supported
if (!mxClient.isBrowserSupported())
{
// Displays an error message if the browser is
// not supported.
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
// Defines an icon for creating new connections in the connection handler.
// This will automatically disable the highlighting of the source vertex.
mxConnectionHandler.prototype.connectImage = new mxImage('images/connector.gif', 16, 16);
// Creates the div for the toolbar
var tbContainer = document.createElement('div');
tbContainer.style.position = 'absolute';
tbContainer.style.overflow = 'hidden';
tbContainer.style.padding = '2px';
tbContainer.style.left = '0px';
tbContainer.style.top = '0px';
tbContainer.style.width = '24px';
tbContainer.style.bottom = '0px';
document.body.appendChild(tbContainer);
// Creates new toolbar without event processing
var toolbar = new mxToolbar(tbContainer);
toolbar.enabled = false
// Creates the div for the graph
var container = document.createElement('div');
container.style.position = 'absolute';
container.style.overflow = 'hidden';
container.style.left = '24px';
container.style.top = '0px';
container.style.right = '0px';
container.style.bottom = '0px';
container.style.background = 'url("editors/images/grid.gif")';
document.body.appendChild(container);
// Workaround for Internet Explorer ignoring certain styles
if (mxClient.IS_QUIRKS)
{
document.body.style.overflow = 'hidden';
new mxDivResizer(tbContainer);
new mxDivResizer(container);
}
// Creates the model and the graph inside the container
// using the fastest rendering available on the browser
var model = new mxGraphModel();
var graph = new mxGraph(container, model);
// Enables new connections in the graph
graph.setConnectable(true);
graph.setMultigraph(false);
// Stops editing on enter or escape keypress
var keyHandler = new mxKeyHandler(graph);
var rubberband = new mxRubberband(graph);
var addVertex = function(icon, w, h, style)
{
var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
vertex.setVertex(true);
var img = addToolbarItem(graph, toolbar, vertex, icon);
img.enabled = true;
graph.getSelectionModel().addListener(mxEvent.CHANGE, function()
{
var tmp = graph.isSelectionEmpty();
mxUtils.setOpacity(img, (tmp) ? 100 : 20);
img.enabled = tmp;
});
};
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rectangle.gif', 100, 40, '');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rounded.gif', 100, 40, 'shape=rounded');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/ellipse.gif', 40, 40, 'shape=ellipse');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rhombus.gif', 40, 40, 'shape=rhombus');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/triangle.gif', 40, 40, 'shape=triangle');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/cylinder.gif', 40, 40, 'shape=cylinder');
addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/actor.gif', 30, 40, 'shape=actor');
// read state on load
if(window.localStorage.graphState){
var doc = json2html(JSON.parse(localStorage.graphState));
var dec = new mxCodec(doc);
dec.decode(doc.documentElement, graph.getModel());
}
// save state on change
graph.getModel().addListener('change',function(){
var codec = new mxCodec();
window.localStorage.graphState = JSON.stringify(html2json(codec.encode(
graph.getModel()
)));
});
}
}
function addToolbarItem(graph, toolbar, prototype, image)
{
// Function that is executed when the image is dropped on
// the graph. The cell argument points to the cell under
// the mousepointer if there is one.
var funct = function(graph, evt, cell, x, y)
{
graph.stopEditing(false);
var vertex = graph.getModel().cloneCell(prototype);
vertex.geometry.x = x;
vertex.geometry.y = y;
graph.addCell(vertex);
graph.setSelectionCell(vertex);
}
// Creates the image which is used as the drag icon (preview)
var img = toolbar.addMode(null, image, function(evt, cell)
{
var pt = this.graph.getPointForEvent(evt);
funct(graph, evt, cell, pt.x, pt.y);
});
// Disables dragging if element is disabled. This is a workaround
// for wrong event order in IE. Following is a dummy listener that
// is invoked as the last listener in IE.
mxEvent.addListener(img, 'mousedown', function(evt)
{
// do nothing
});
// This listener is always called first before any other listener
// in all browsers.
mxEvent.addListener(img, 'mousedown', function(evt)
{
if (img.enabled == false)
{
mxEvent.consume(evt);
}
});
mxUtils.makeDraggable(img, graph, funct);
return img;
}
</script>
</head>
<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
<body onload="main();" >
</body>
</html>
please help me thanks in advance!!!
Check out this CodePen link which has the modified version of the snippet you gave. In it, you can add new elements and change texts and see an updated json string representing the relationships in the graph: https://codepen.io/tien-q-nguyen2/pen/GaQXBO
I also edited the function a little from the first time I posted this answer.
Note: based on the expected output you put in the original question, there is only one parent per vertex element ({"id":1,"parent":0 <= in the example you gave), so if there are multiple nodes pointing to the same child , the child's parent property will only refer to the first parent's id. I can change the parent's property to be an array that can keep multiple parent's ids if you want.
function getNodesFrom(graph){
var cells = graph.getModel().cells;
var vertices = [], edges = [];
for (var key in cells) {
if (cells[key].isVertex()){
vertices.push(cells[key]);
}
else if (cells[key].isEdge()){
edges.push(cells[key]);
}
}
var simpleVertices = [], simpleEdges = [];
var newIndex = 0;
var newIndexOf = [];
vertices.forEach(function(vertex){
simpleVertices.push({id: newIndex, value: vertex.value});
newIndexOf[vertex.id] = newIndex++;
});
edges.forEach(function(edge){
if (edge.target === null || edge.source === null) return;
simpleEdges.push({
parentId: newIndexOf[edge.source.id],
childId: newIndexOf[edge.target.id],
value: edge.value
});
});
var edgesForParentIndex = [];
var edgesForChildIndex = [];
simpleEdges.forEach(function(edge){
if (edgesForParentIndex[edge.parentId] === undefined){
edgesForParentIndex[edge.parentId] = [];
}
edgesForParentIndex[edge.parentId].push(edge);
if (edgesForChildIndex[edge.childId] === undefined){
edgesForChildIndex[edge.childId] = [];
}
edgesForChildIndex[edge.childId].push(edge);
});
var nodes = [];
simpleVertices.forEach(function(vertex){
var node = {};
node.id = vertex.id;
if (edgesForChildIndex[node.id] === undefined){
node.parent = '#';
} else {
node.parent = edgesForChildIndex[node.id][0].parentId;
}
node.text = (vertex.value === undefined || vertex.value === null) ? '' : vertex.value;
node.child = [];
if (edgesForParentIndex[node.id] === undefined){
node.child.push({cid: null, connectionText: ""});
} else {
edgesForParentIndex[node.id].forEach(function(edge){
var text = (edge.value === undefined || edge.value === null) ? '' : edge.value;
node.child.push({cid: edge.childId, connectionText: text});
});
}
nodes.push(node);
});
return nodes;
}

Leaflet map not showing properly on mobile

I have a page with filters on top and a toggle between tile view or map view.
Every time a filter is changed I perform a search with AJAX and change the view using Mustache.
On mobile the default view is the tile view with an icon on the bottom right to toggle the map.
When my view is on the tile view, I change a filter (so the search triggers and filtered tiles show up), i then toggle to the map view and it is max zoomed out, and only the bottom left corner is not greyed out. It looks like this:
When I load the page, and i immediately toggle to my map view, that is also the initial view I see. But if I then change my filters and perform the search again, the map will load correctly and works perfectly. But after switching to tiles, changing filters and going back to Map view, it breaks again.
This is the HTML holder for the map:
<div id="map_canvas"></div>
jQuery:
$(document).ready(function(){
'use strict';
curr_lang = $('#curr_lang').val();
initializeElements();
//Read the query parameters & set everything up according to it
setupConfig(radiusSlider);
//Setup the listeners for the freetext input search field
setupFreetextField();
setupInterestsField();
setupLocationField();
setupDaterangeField();
setupMorefiltersField();
});
function initializeElements() {
$(window).scroll(function() {
var volunteer = $('#map_canvas');
var offset = volunteer.offset();
top = offset.top;
state = $('.footer').offset().top;
var bottom = $('#map_canvas').offset().top;
if ($(window).scrollTop() + volunteer.height() + 134 > state) {
volunteer.removeClass('fixed');
volunteer.addClass('bottom');
} else if ($(this).scrollTop() + 58 > bottom) {
volunteer.addClass('fixed');
volunteer.removeClass('bottom');
} else {
volunteer.removeClass('fixed');
volunteer.removeClass('bottom');
}
//Enable search toggle menu icon
if ($(window).width() <= 768) {
var nav = $('.navbar-wrapper');
var navOffset = nav.offset();
var filters = $('.content-filters');
var filtersOffset = filters.offset().top;
var searchToggle = $('.search-filter-toggle');
if ($(window).scrollTop() > filters.height()) {
searchToggle.addClass('show');
} else {
searchToggle.removeClass('show');
filters.removeClass('mobile-filters');
}
}
});
if ($(window).width() <= 768) {
$('.search-filter-toggle').on('click',function(e) {
var filters = $('.content-filters');
filters.toggleClass('mobile-filters');
});
}
$(window).resize(function() {
var vacancyGrid = $('.vacancy-holder');
var mapGrid = $('.map-holder');
if ($(window).width() > 1227) {
vacancyGrid.removeClass('hide-mobile');
mapGrid.removeClass('show-mobile');
$('#mapview').removeClass('hide-mobile');
$('#gridview').removeClass('show-mobile');
$(document.body).removeClass('map');
}else if($(window).width() < 991){
}
});
$('#mapview').on('click',function(e) {
map.invalidateSize(false);
var vacancyGrid = $('.vacancy-holder');
var mapGrid = $('.map-holder');
vacancyGrid.addClass('hide-mobile');
vacancyGrid.removeClass('show-mobile');
mapGrid.addClass('show-mobile');
mapGrid.removeClass('hide-mobile');
$('#mapview').addClass('hide-mobile');
$('#mapview').removeClass('show-mobile');
$('#gridview').addClass('show-mobile');
$('#gridview').removeClass('hide-mobile');
$(document.body).addClass('map');
$("html, body").animate({ scrollTop: 0 });
});
$('#gridview').on('click',function(e) {
var vacancyGrid = $('.vacancy-holder');
var mapGrid = $('.map-holder');
vacancyGrid.addClass('show-mobile');
vacancyGrid.removeClass('hide-mobile');
mapGrid.addClass('hide-mobile');
mapGrid.removeClass('show-mobile');
$('#mapview').addClass('show-mobile');
$('#mapview').removeClass('hide-mobile');
$('#gridview').addClass('hide-mobile');
$('#gridview').removeClass('show-mobile');
$(document.body).removeClass('map');
$("html, body").animate({ scrollTop: 0 });
});
}
function setupMap(vacancies) {
//Destroy the map if it already exists
if (map != undefined) {
map.remove();
}
console.log("setting up the map...");
// this script enable displaying map with markers spiderfying and clustering using leaflet plugin
var vacArr = [];
var index = 0;
if (vacancies.length > 0) {
for (index = 0; index < vacancies.length; ++index) {
var vacancy = vacancies[index];
if (((vacancy.lat != 0) && (vacancy.lat !== undefined) && (vacancy.lat != null)) && ((vacancy.lng !=0) && (vacancy.lng !== undefined) && (vacancy.lat != null))) {
var vacurl = vacancy.detailurl;
var tempArr = [];
tempArr.push(vacancy.lng);
tempArr.push(vacancy.lat);
tempArr.push(vacurl);
tempArr.push(vacancy.name);
tempArr.push(vacancy.orgname);
vacArr.push(tempArr);
}
}
}
var tiles = L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© OpenStreetMap contributors, Points &copy 2012 LINZ'
});
map = L.map('map_canvas', {
center: L.latLng(51.260197, 4.402771),
zoom: 10,
layers: [tiles]
});
var mcg = L.markerClusterGroup({
chunkedLoading: true,
spiderfyOnMaxZoom: true,
showCoverageOnHover: true //zoomToBoundsOnClick: false
});
var boundsarray = [];
for (var i = 0; i < vacArr.length; i++) {
var detailText = res.ViewDetail;
var info ="<div id='infoId-' style=\"background:white\"> <h5>"+vacArr[i][3] +"</h5> <p class=\"marker_font\">"+vacArr[i][4]+"</p> "+detailText+"</p></div>";
var title=vacArr[i][3];
var marker = L.marker(new L.LatLng(vacArr[i][1], vacArr[i][0]), {
title: title
});
boundsarray.push([vacArr[i][1], vacArr[i][0]]);
mcg.on('clusterclick', function (a) {
if('animationend zoom level: ', map.getZoom() >13)
{
a.layer.spiderfy();
}
});
marker.bindPopup(info);
mcg.addLayer(marker);
}
//console.log(boundsarray);
map.fitBounds(boundsarray);
map.addLayer(mcg);
}
EDIT: I added the complete code after trying to add map.invalidateSize(); on the map toggle function. But it results in the same.
The setupMap() function is called at the end of my AJAX success method for searching. (The vacancies parameter is the result from my AJAX method and contains the information for the tiles and as well the lat/lon of the vacancy)
I had a same problem ( Uncompleted load ) and I tried it with setTimeout and it solved.
setTimeout(function () {
if (!myMap)
loadmap(); /*load map function after ajax is complitly load */
}, 1000);
setTimeout(function () {
if (myMap)
myMap.invalidateSize();
}, 1500);
I hope it helps;
I had a similar problem, it seems the tiles load, but are not positioned.
I found that loading the tiles inside the setTimeout rather than at map initialisation, even with a zero timeout, worked. e.g:
setTimeout(function () {
tiles.addToMap(map);
},0);
This delays the rendering of the tiles long enough to ensure other script do not interfere.
Possibly the mirage script from CloudFlare is a source of the problem, but I did not have access to change CloudFlare settings for this site.
Note, in my final implementation though, I included all the map code inside the timeout so as not to have the short but noticeable delay before the tiles are rendered.

How to update position of markers with real time gps coordinates?

I've got real time gps positions for a few cars and I want to create a map with updating markers. My code works but it doesn't "update" the markers, instead it adds new objects with new coordinates to the leaflet map. After few minutes my map is full of markers. What I'm doing wrong? Here is my basic concept.
var intervalV = document.getElementById("intervalValue").value * 1000;
document.getElementById("setIntervalButton").onclick = startData;
function startData() {
DataInterval = window.setInterval(getNewData, intervalV);
};
function getNewData() {
$.getJSON(server, {
fun : "GetGpsData",
userId : "user",
sessionId : $("#sessionId").val()
}, fillMap);
}
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var positions = json.devicesData[i].positions.length;
var devicepostiion;
if (json.devicesData[i].connected == false
) {
var devicepostion = L.marker([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon], {
icon : offlineCarIcon
}, {
draggable : false
}).addTo(map);
} else {
devicepostion = new L.marker(, {
icon : onlineCarIcon
});
devicepostion.addTo(map).setLatLng([json.devicesData[i].positions[positions - 1].lat, json.devicesData[i].positions[positions - 1].lon]).update();
}
}
}
};
If your goal is to update markers with a new visual appearance and location if they already exist on the map...then you should be using .setIcon and .setLatLng on the existing marker instead of making a new one.
Your current code makes new markers in both cases.
Here your code updated to work as you want. As #snkashis pointed out, you do not need to create a new marker each time
var devicePosition = -1;
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (devicePosition === -1) {
var devicePosition = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition.setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition !== -1) {
devicePosition.setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}
If you have multiple markers, you need to update each one accordingly to their id, I suggest to find (or add, if you create the APIs) an unique ID in json.devicesData[i].
Let's suppose the uniqueId of each marker is called, well, uniqueId, then your code can be something like this:
var devicePosition = {};
function fillMap(json) {
for (var i = 0; i < json.devicesData.length; i++) {
var data = json.devicesData[i];
var uniqueId = data.uniqueId;
if (data.positions) {
var index = data.positions.length - 1;
if (data.positions[index].lat && data.positions[index].lon) {
var latLng = L.latLng(parseFloat(data.positions[index].lat), parseFloat(data.positions[index].lon));
if (!devicePosition[uniqueId]) {
var devicePosition[uniqueId] = L.marker(latLng, {draggable : false})
.addTo(map);
} else {
devicePosition[uniqueId].setLatLng(latLng)
.update();
}
// Optional if you want to center the map on th marker
// map.panTo(latLng);
}
}
if (data.connected && devicePosition[uniqueId]) {
devicePosition[uniqueId].setIcon(data.connected ? 'onlineCarIcon' : 'offlineCarIcon');
}
}

Multiple popups opened at the same time in OL3

I have some serious question. How can i set multiple popups to be opened at the same time? I am using this code to open a popup:
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
var overlay = new ol.Overlay({
element: container
});
And for viewing content for specific feature in cluster at specific coordinates i use this:
map.on('click', function (evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function (feature, layer) { return feature; });
var coordinate = evt.coordinate;
var prop;
var vyprop = "";
overlay.setPosition(coordinate);
var features = feature.get('features');
for(var i = 0; i < features.length; i++) {
prop = features[i].getProperties();
vyprop += prop.odbermisto + "<br>";
}
content.innerHTML = vyprop;
});
Because it uses div as a content and moves it from coordinates, hwere it is needed, I ain't able to open two popups at the same time. is there any solution to do that, without duplicating and deleting divs, which i dont wanna do? Thx for help guys

create arrow using leafletjs

I want to create a arrow in leaflet using poly lines of multipolylines whichever suits..
The arrow class should take in following param
baselatitude = base of the arrow where the arrow will be on map
baselongitude = base of the arrow where the arrow will be on map
pointlatitude = the tip of the arrow on the map
pointlongitude = the tip of the arrow on the map
apointlatitude
apointlongitude
bpointlatitude
bpointlongitude
angle = rotation degree
can anyone please provide guidance on creating the arrow using following param . It would be nice to if you can create a leaflet class extension L.arrow
did that myself for fit my requirement .. pasting in if somebody finds it useful someday
feature.geometry.coordinates[0] is the geoJson collection where all the coordinates are retrieved
L.Playback.WindArrowMarker = L.Marker.extend({
initialize: function (startLatLng, options, feature) {
this._min = 99;
this._max = 0;
this._arrowStyleOptions = [
{ color: '#ffff00' },
{ color: '#00ffff' },
{ color: '#00ff00' }];
var ArrowData = feature.geometry.coordinates[0];
var ArrowBaseLon = ArrowData[0];
var ArrowBaseLat = ArrowData[1];
var ArrowPointLat = ArrowData[2];
var ArrowPointLon = ArrowData[3];
var ArrowPointALat = ArrowData[4];
var ArrowPointALon = ArrowData[5];
var ArrowPointBLat = ArrowData[6];
var ArrowPointBLon = ArrowData[7];
var ArrowHeight = ArrowData[8];
var ArrowMagnitude = ArrowData[9];
var ArrowBearing = ArrowData[10];
if (ArrowMagnitude > this._max) this._max = ArrowMagnitude;
if (ArrowMagnitude < this._min) this._min = ArrowMagnitude;
var styleToUse=this._getArrowStyle(ArrowMagnitude);
//Create Arrow structure and assign first value from the playback data
//baseLtlg //PointLtlg
this._arrowbase = L.polyline([[ArrowBaseLat, ArrowBaseLon], [ArrowPointLat, ArrowPointLon]], styleToUse);
//PointLtlg //PointAtLtlg
this._arrowpointA = L.polyline([[ArrowPointLat, ArrowPointLon], [ArrowPointALat, ArrowPointALon]], styleToUse);
//PointLtlg //PointBLtlg
this._arrowpointB = L.polyline([[ArrowPointLat, ArrowPointLon], [ArrowPointBLat, ArrowPointBLon]], styleToUse);
//Call leaflet marker initialization to attach this as marker
L.Marker.prototype.initialize.call(this, [ArrowBaseLat, ArrowBaseLon], {});
//Calculate windspeed
var windspeed = this._calculateWindspeed(ArrowMagnitude, feature.modeldata.Adder, feature.modeldata.Multiplier)
//Attach a popup
this._arrowbase.bindPopup(this.getPopupContent(ArrowBearing, windspeed));
},
_calculateWindspeed: function (magnitude, adder, multiplier) {
return (magnitude - parseFloat(adder)) / multiplier
},
_getArrowStyle: function (magnitude) {
this._arrowMagMed = 7;
this._arrowMagHigh = 10;
if (magnitude > this._arrowMagHigh)
styleToUse = this._arrowStyleOptions[2];
else if (magnitude > this._arrowMagMed)
styleToUse = this._arrowStyleOptions[1];
else
styleToUse = this._arrowStyleOptions[0];
return styleToUse;
},
getPopupContent: function (bearing, windspeed) {
return sprintf("Wind blowing from: %s deg(from North)<br> Wind Speed(m/s): %s", bearing.toFixed(1), windspeed.toFixed(1));
},
addTo: function (map) {
this._arrowbase.addTo(map);
this._arrowpointA.addTo(map);
this._arrowpointB.addTo(map);
},
move: function (windData,transitionTime, modelData) {
var ArrowBaseLon = windData[0];
var ArrowBaseLat = windData[1];
var ArrowPointLat = windData[2];
var ArrowPointLon = windData[3];
var ArrowPointALat = windData[4];
var ArrowPointALon = windData[5];
var ArrowPointBLat = windData[6];
var ArrowPointBLon = windData[7];
var ArrowHeight = windData[8];
var ArrowMagnitude = windData[9];
var ArrowBearing = windData[10];
var styleToUse = this._getArrowStyle(ArrowMagnitude);
//Assign color based on magnitude
this._arrowbase.setStyle(styleToUse);
this._arrowpointA.setStyle(styleToUse);
this._arrowpointB.setStyle(styleToUse);
//Set Base,Apoint,Bpoint LatLongs as they are the ones changing
this._arrowbase.setLatLngs([[ArrowBaseLat, ArrowBaseLon], [ArrowPointLat, ArrowPointLon]])
this._arrowpointA.setLatLngs([[ArrowPointLat, ArrowPointLon], [ArrowPointALat, ArrowPointALon]])
this._arrowpointB.setLatLngs([[ArrowPointLat, ArrowPointLon], [ArrowPointBLat, ArrowPointBLon]])
//Calculate windspeed
var windspeed = this._calculateWindspeed(ArrowMagnitude, modelData.Adder, modelData.Multiplier)
//Check if popup is attached
if (this._arrowbase._popup) {
//Set popup content while moving
this._arrowbase._popup.setContent(this.getPopupContent(ArrowBearing, windspeed));
}
}
});
It would be nice to if you can create a leaflet class extension L.arrow
No: this is not a place where people make things for you. But we can Google things, like Leaflet arrow which leads you directly to Leaflet.PolylineDecorator.

Categories