Couldn't draw shapes on the map using leaflet - javascript

I am using javascript library leaflet to deal with map, I did the location searching part now I want that user can draw circle, line and polygon on the map but the could is not working. The toolbar of searching is visible but of the shapes is not. Can any one point out eh mistake in my code, Thanks in advance.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<!-- Load Leaflet from CDN-->
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet-src.js"></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet"></script>
<!-- Esri Leaflet Geocoder -->
<link rel="stylesheet" href="https://unpkg.com/esri-leaflet-geocoder/dist/esri-leaflet-geocoder.css">
<script src="https://unpkg.com/esri-leaflet-geocoder"></script>
<script src="node_modules/leaflet-toolbar/dist/leaflet.toolbar.js"></script>
<link rel="stylesheet" href="node_modules/leaflet-toolbar/dist/leaflet.toolbar.css" />
<link rel="stylesheet" href="node_modules/leaflet-draw-toolbar/dist/leaflet.draw-toolbar.css" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<!---- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="../node_modules/leaflet/dist/leaflet-src.js"></script>
<script src="../node_modules/leaflet-toolbar/dist/leaflet.toolbar-src.js"></script>
<script src="../node_modules/leaflet-draw/dist/leaflet.draw-src.js"></script>--!-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#turf/turf#5/turf.min.js"></script>
<style>
#map {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<div id="map"> </div>
<script>
var center = [-33.8650, 151.2094];
var map = L.map('map').setView([0, 0], 6);
drawnItems = new L.FeatureGroup().addTo(map);
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=eL1sdTPWF7XeyxpLvpGq', {
attribution: '© MapTiler © OpenStreetMap contributors'
}).addTo(map);
var searchContrl = L.esri.Geocoding.geosearch().addTo(map);
//adding layergroup to search control
var results = L.layerGroup.addTo(map);
searchContrl.on('results', function(data) {
results.clearLayers();
for (var i = data.results.length - 1; i >= 0; i--) {
results.addLayer(L.marker(data.results[i].latlong));
}
});
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
var MyCustomMarker = L.Icon.extend({
options: {
shadowUrl: null,
iconAnchor: new L.Point(12, 12),
iconSize: new L.Point(24, 24),
iconUrl: 'link/to/image.png'
}
});
var options = {
position: 'topright',
draw: {
polyline: {
shapeOptions: {
color: '#f357a1',
weight: 10
}
},
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#bada55'
}
},
circle: false, // Turns off this drawing tool
rectangle: {
shapeOptions: {
clickable: false
}
},
marker: {
icon: new MyCustomMarker()
}
},
edit: {
featureGroup: editableLayers, //REQUIRED!!
remove: false
}
};
var drawControl = new L.Control.Draw(options);
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, function(e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
editableLayers.addLayer(layer);
});
</script>
</body>
</html>

The use is wrong
var results = L.layerGroup.addTo(map);
should be
var results = new L.LayerGroup().addTo(map);
(Like you did in the search container)
<!DOCTYPE html>
<html>
<head>
<!-- Load Leaflet from CDN-->
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet-src.js"></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet"></script>
<!-- Esri Leaflet Geocoder -->
<link rel="stylesheet" href="https://unpkg.com/esri-leaflet-geocoder/dist/esri-leaflet-geocoder.css">
<script src="https://unpkg.com/esri-leaflet-geocoder"></script>
<script src="node_modules/leaflet-toolbar/dist/leaflet.toolbar.js"></script>
<link rel="stylesheet" href="node_modules/leaflet-toolbar/dist/leaflet.toolbar.css" />
<link rel="stylesheet" href="node_modules/leaflet-draw-toolbar/dist/leaflet.draw-toolbar.css" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<!---- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="../node_modules/leaflet/dist/leaflet-src.js"></script>
<script src="../node_modules/leaflet-toolbar/dist/leaflet.toolbar-src.js"></script>
<script src="../node_modules/leaflet-draw/dist/leaflet.draw-src.js"></script>--!-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#turf/turf#5/turf.min.js"></script>
<style>
#map {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<div id="map"> </div>
<script>
var center = [-33.8650, 151.2094];
var map = L.map('map').setView([0, 0], 6);
drawnItems = new L.FeatureGroup().addTo(map);
L.tileLayer('https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=eL1sdTPWF7XeyxpLvpGq', {
attribution: '© MapTiler © OpenStreetMap contributors'
}).addTo(map);
var searchContrl = L.esri.Geocoding.geosearch().addTo(map);
//adding layergroup to search control
console.log(L.LayerGroup);
var results = new L.LayerGroup().addTo(map);
searchContrl.on('results', function(data) {
results.clearLayers();
for (var i = data.results.length - 1; i >= 0; i--) {
results.addLayer(L.marker(data.results[i].latlong));
}
});
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
var MyCustomMarker = L.Icon.extend({
options: {
shadowUrl: null,
iconAnchor: new L.Point(12, 12),
iconSize: new L.Point(24, 24),
iconUrl: 'link/to/image.png'
}
});
var options = {
position: 'topright',
draw: {
polyline: {
shapeOptions: {
color: '#f357a1',
weight: 10
}
},
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#bada55'
}
},
circle: false, // Turns off this drawing tool
rectangle: {
shapeOptions: {
clickable: false
}
},
marker: {
icon: new MyCustomMarker()
}
},
edit: {
featureGroup: editableLayers, //REQUIRED!!
remove: false
}
};
var drawControl = new L.Control.Draw(options);
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, function(e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
editableLayers.addLayer(layer);
});
</script>
</body>
</html>
BTW, I used var because of your syntax but const and let are much better.

Related

Problems getting OverlappingMarkerSpiderfier and Leaflet working

I am trying to follow this demo for the leaflet plugin OverlappingMarkerSpiderfier to get overlap markers to spider out but with markers I've defined myself but cannot get it working. (I cannot get their script working either).
The code below runs and displays the two markers as I expect, however do not display the behaviour I expect (the spidering). If anyone can point me to where I am going wrong that would be appreciated. I suspect the problem is how I am adding the markers to the oms layer, or I'm not adding that layer correctly, but I've no idea how to fix that. I have not been able to find many minimal examples online to try mimic.
<!DOCTYPE html>
<html>
<head>
<title> My Leaflet.js Map</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js" integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" crossorigin=""></script>
<script src="oms.min.js"></script>
<style>
#map {
height: 800px;
}
</style>
<script type="text/javascript">
function init() {
let map = new L.map('map', {
minZoom: 3,
maxZoom: 6
}).setView([20.91, 142.70], 5);
let osmLink = "<a href='http://www.openstreetmap.org'>Open StreetMap</a>"
let osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © ' + osmLink,
maxZoom: 18,
}).addTo(map)
var oms = new OverlappingMarkerSpiderfier(map);
var popup = new L.Popup({
closeButton: false,
offset: new L.Point(0.5, -24)
});
oms.addListener('click', function(marker) {
popup.setContent(marker.desc);
popup.setLatLng(marker.getLatLng());
map.openPopup(popup);
});
oms.addListener('spiderfy', function(markers) {
for (var i = 0, len = markers.length; i < len; i++) markers[i].setIcon(new lightIcon());
map.closePopup();
});
oms.addListener('unspiderfy', function(markers) {
for (var i = 0, len = markers.length; i < len; i++) markers[i].setIcon(new darkIcon());
});
let pt1aLatLong = L.latLng(21, 142.6);
let pt1aMarker = L.marker(pt1aLatLong, {
title: "This is the first marker that I have added",
alt: "A marker",
opacity: 0.7
}).addTo(map);
let pt1bLatLong = L.latLng(21.1, 142.6);
let pt1bMarker = L.marker(pt1bLatLong, {
title: "This is a copy marker",
alt: "A marker",
opacity: 0.9
}).addTo(map);
oms.addMarker(pt1bMarker);
oms.addMarker(pt1aMarker);
}
</script>
</head>
<h1></h1>
<body onload=init()>
<div id="map"> </div>
</html>
EDIT: Typo in the code corrected
let pt1LatLong = L.latLng(21, 142.6);
let pt1Marker = L.marker(pt1LatLong,
bolded section corrected to be pt1a... to match oms.addMarker command.
The problem was the .addTo(map) after defining each marker - this should be removed and replaced with map.addLayer(pt1bMaker)
<!DOCTYPE html>
<html>
<head>
<title> My Leaflet.js Map</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js" integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" crossorigin=""></script>
<script src="oms.min.js"></script>
<style>
#map {
height: 800px;
}
</style>
<script type="text/javascript">
function init() {
let map = new L.map('map', {
minZoom: 3,
maxZoom: 6
}).setView([20.91, 142.70], 5);
let osmLink = "<a href='http://www.openstreetmap.org'>Open StreetMap</a>"
let osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © ' + osmLink,
maxZoom: 18,
}).addTo(map)
var oms = new OverlappingMarkerSpiderfier(map);
var popup = new L.Popup({
closeButton: false,
offset: new L.Point(0.5, -24)
});
oms.addListener('click', function(marker) {
popup.setContent(marker.desc);
popup.setLatLng(marker.getLatLng());
map.openPopup(popup);
});
oms.addListener('spiderfy', function(markers) {
for (var i = 0, len = markers.length; i < len; i++) markers[i].setIcon(new lightIcon());
map.closePopup();
});
oms.addListener('unspiderfy', function(markers) {
for (var i = 0, len = markers.length; i < len; i++) markers[i].setIcon(new darkIcon());
});
let pt1aLatLong = L.latLng(21, 142.6);
let pt1aMarker = L.marker(pt1aLatLong, {
title: "This is the first marker that I have added",
alt: "A marker",
opacity: 0.7
})
map.addLayer(pt1aMarker)
oms.addMarker(pt1aMarker);
let pt1bLatLong = L.latLng(21.1, 142.6);
let pt1bMarker = L.marker(pt1bLatLong, {
title: "This is a copy marker",
alt: "A marker",
opacity: 0.9
})
map.addLayer(pt1bMarker);
oms.addMarker(pt1bMarker);
}
</script>
</head>
<h1></h1>
<body onload=init()>
<div id="map"> </div>
</html>

Prevent multiple markerClusterGroup icons from overlapping in Leaflet

I have two seperate markerClusterGroups that occasionally overlap. Is there anyway to prevent this? In my actual code, I am using a custom Icon for one of the cluster groups so that I can tell the difference between the two cluster types. However, it wasn't neccessary for this example so I left that part out for the sake of simplicity.
var map = L.map("map");
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
map.setView([48.85, 2.35], 12);
var mcg = L.markerClusterGroup().addTo(map);
var mcg2 = L.markerClusterGroup().addTo(map);
L.marker([48.85, 2.35]).addTo(mcg);
L.marker([48.85, 2.34]).addTo(mcg);
for(var i=0;i<40;i++){
L.marker([48.85, 2.34091]).addTo(mcg2);
}
Here is an example of what I mean:
http://plnkr.co/edit/yqIhI7RMsp9A7I3AwGnY?p=preview
The requirement states that the markers in category 1 must cluster separately from markers in category 2. However both types must be displayed on the map at the same time.
Is there anyway to prevent this?
Not with several Leaflet.markercluster groups as you did.
Think about it: where should the cluster icons positions be computed, when a given group has no data about another group?
You may have several possible workarounds and/or other libraries that may better fit your need, without having to re-write a clustering algorithm yourself.
For example, a popular alternative to show different categories while clustering is the PruneCluster plugin:
PruneCluster is a fast and realtime marker clustering library.
It's working with Leaflet as an alternative to Leaflet.markercluster.
Excerpt from PruneCluster home page
Another possible workaround would be to merge all categories into the same Marker Cluster Group, but have the latter's cluster icon customized so that they render similarly as the above PruneCluster screenshot, or even render fake icons for each category:
function customClusterIcon(cluster) {
// Count number of markers from each category.
var markers = cluster.getAllChildMarkers();
var cat1count = 0;
var cat2count = 0;
for (var marker of markers) {
var category = marker.options.category;
if (category && category === 'cat2') {
cat2count += 1;
} else {
cat1count += 1;
}
}
// Generate the cluster icon depending on presence of Markers from different categories.
if (cat2count === 0) {
return L.divIcon({
html: cat1count,
className: 'cat1cluster cluster',
iconSize: [20, 20]
});
} else if (cat1count === 0) {
return L.divIcon({
html: cat2count,
className: 'cat2cluster cluster',
iconSize: [20, 20]
});
} else {
return L.divIcon({
html: `
<div class="cat1cluster cluster">${cat1count}</div>
<div class="cat2cluster cluster">${cat2count}</div>
`,
className: '',
iconSize: [45, 20]
});
}
}
var paris = [48.86, 2.35];
var parisLeft = [48.86, 2.25];
var parisRight = [48.86, 2.45];
var map = L.map('map', {
maxZoom: 18
}).setView(paris, 11);
var mcg = L.markerClusterGroup({
iconCreateFunction: customClusterIcon
}).addTo(map);
var category1 = L.layerGroup();
var category2 = L.layerGroup();
var cat2style = {
color: 'red',
category: 'cat2'
};
var markerA = L.circleMarker(paris).addTo(category1);
var markerB = L.circleMarker(paris).addTo(category1);
var markerC = L.circleMarker(paris, cat2style).addTo(category2);
var markerD = L.circleMarker(paris, cat2style).addTo(category2);
var markerE = L.circleMarker(parisLeft).addTo(category1);
var markerF = L.circleMarker(parisLeft).addTo(category1);
var markerG = L.circleMarker(parisRight, cat2style).addTo(category2);
var markerH = L.circleMarker(parisRight, cat2style).addTo(category2);
mcg.addLayers([category1, category2]);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
html,
body,
#map {
height: 100%;
margin: 0;
}
.cat1cluster {
background-color: #3388ff;
}
.cat2cluster {
background-color: red;
}
.cluster {
width: 20px;
height: 20px;
display: inline-block;
text-align: center;
}
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.4.1/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.4.1/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster#1.4.1/dist/leaflet.markercluster-src.js"></script>
<div id="map"></div>
Then if you wish you can further customize the spiderfication so that it shows Markers only from the clicked category cluster icon, and similar for the hovering polygon.

How to pass back value from JS to Python

I wanted to display a 2D Map with Python and then do something with the coordinates of the coursor in the Python code. I cant get the coordinates to the Python Part however.
Heres my code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import QWidget,QVBoxLayout, QApplication
from PyQt5.QtWebChannel import QWebChannel
import bs4
maphtml = '''
<!DOCTYPE HTML>
<!DOCTYPE HTML>
<html>
<head>
<meta name="robots" content="index, all" />
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<title>WebGL Earth API - Side-by-side - Basic Leaflet compatibility</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<script src="http://www.webglearth.com/v2/api.js"></script>
<script>
var backend;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
});
function init() {
var m = {};
start_(L, 'L');
start_(WE, 'WE');
function start_(API, suffix) {
var mapDiv = 'map' + suffix;
var map = API.map(mapDiv, {
center: [51.505, -0.09],
zoom: 4,
dragging: true,
scrollWheelZoom: true,
proxyHost: 'http://srtm.webglearth.com/cgi-bin/corsproxy.fcgi?url='
});
m[suffix] = map;
//Add baselayer
API.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution: '© OpenStreetMap contributors'
}).addTo(map);
//Add TileJSON overlay
var json = {"profile": "mercator", "name": "Grand Canyon USGS", "format": "png", "bounds": [-112.26379395, 35.98245136, -112.10998535, 36.13343831], "minzoom": 10, "version": "1.0.0", "maxzoom": 16, "center": [-112.18688965, 36.057944835, 13], "type": "overlay", "description": "", "basename": "grandcanyon", "tilejson": "2.0.0", "sheme": "xyz", "tiles": ["http://tileserver.maptiler.com/grandcanyon/{z}/{x}/{y}.png"]};
if (API.tileLayerJSON) {
var overlay2 = API.tileLayerJSON(json, map);
} else {
//If not able to display the overlay, at least move to the same location
map.setView([json.center[1], json.center[0]], json.center[2]);
}
//Add simple marker
var marker = API.marker([json.center[1], json.center[0]]).addTo(map);
marker.bindPopup(suffix, 50);
marker.openPopup();
//Print coordinates of the mouse
map.on('mousemove', function(e) {
document.getElementById('coords').innerHTML = e.latlng.lat + ', ' + e.latlng.lng;
backend.print(e.latlng.lat)
});
}
//Synchronize view
m['L'].on('move', function(e) {
var center = m['L'].getCenter();
var zoom = m['L'].getZoom();
m['WE'].setView([center['lat'], center['lng']], zoom);
});
}
</script>
<style>
html, body{padding: 0; margin: 0; overflow: hidden;}
#mapL, #mapWE {position:absolute !important; top: 0; right: 0; bottom: 0; left: 0;
background-color: #fff; position: absolute !important;}
#mapL {right: 0%;}
#mapWE {left: 100%;}
#coords {position: absolute; bottom: 0;}
</style>
</head>
<body onload="javascript:init()">
<div id="mapL"></div>
<div id="mapWE"></div>
<div id="coords"></div>
</body>
</html>
'''
class Browser(QApplication):
def __init__(self):
QApplication.__init__(self, [])
self.window = QWidget()
self.window.setWindowTitle("Serial GPS Emulator");
self.web = QWebEngineView(self.window)
self.web.setHtml(maphtml)
self.layout = QVBoxLayout(self.window)
self.layout.addWidget(self.web)
self.window.show()
self.exec()
Browser()
It would be good if the code would stay in one file but if its totally impossible to do it in one splitting it is acceptable.
I guess the first step in solving mny Problem would be to call a function from the HTML/JS part as backend.print("test") also doesnt work.
I also noticed that self.exec() Blocks the rest of the code, is there a way to execute any other code while the map is running? Thanks!
I do not see where in your code you have passed the backend.
In this case you must create a Backend class that can be injected, and for a method to be invoked it must be a slot, for this you must use the pyqtSlot() setting, the parameter that it receives depends on what you are sending it, in the case of the e.latlng is a QJsonValue. In the slot you must separate the necessary parts.
import sys
from PyQt5.QtCore import pyqtSlot, QObject, QJsonValue, pyqtSignal, QTimer
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
maphtml = '''
<!DOCTYPE HTML>
<!DOCTYPE HTML>
<html>
<head>
<meta name="robots" content="index, all" />
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<title>WebGL Earth API - Side-by-side - Basic Leaflet compatibility</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<script src="http://www.webglearth.com/v2/api.js"></script>
<script>
var backend;
new QWebChannel(qt.webChannelTransport, function (channel) {
backend = channel.objects.backend;
console.log(backend);
});
function init() {
var m = {};
start_(L, 'L');
start_(WE, 'WE');
function start_(API, suffix) {
var mapDiv = 'map' + suffix;
var map = API.map(mapDiv, {
center: [51.505, -0.09],
zoom: 4,
dragging: true,
scrollWheelZoom: true,
proxyHost: 'http://srtm.webglearth.com/cgi-bin/corsproxy.fcgi?url='
});
m[suffix] = map;
//Add baselayer
API.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution: '© OpenStreetMap contributors'
}).addTo(map);
//Add TileJSON overlay
var json = {"profile": "mercator", "name": "Grand Canyon USGS", "format": "png", "bounds": [-112.26379395, 35.98245136, -112.10998535, 36.13343831], "minzoom": 10, "version": "1.0.0", "maxzoom": 16, "center": [-112.18688965, 36.057944835, 13], "type": "overlay", "description": "", "basename": "grandcanyon", "tilejson": "2.0.0", "sheme": "xyz", "tiles": ["http://tileserver.maptiler.com/grandcanyon/{z}/{x}/{y}.png"]};
if (API.tileLayerJSON) {
var overlay2 = API.tileLayerJSON(json, map);
} else {
//If not able to display the overlay, at least move to the same location
map.setView([json.center[1], json.center[0]], json.center[2]);
}
//Add simple marker
var marker = API.marker([json.center[1], json.center[0]]).addTo(map);
marker.bindPopup(suffix, 50);
marker.openPopup();
//Print coordinates of the mouse
map.on('mousemove', function(e) {
document.getElementById('coords').innerHTML = e.latlng.lat + ', ' + e.latlng.lng;
backend.print(e.latlng)
});
}
//Synchronize view
m['L'].on('move', function(e) {
var center = m['L'].getCenter();
var zoom = m['L'].getZoom();
m['WE'].setView([center['lat'], center['lng']], zoom);
});
}
</script>
<style>
html, body{padding: 0; margin: 0; overflow: hidden;}
#mapL, #mapWE {position:absolute !important; top: 0; right: 0; bottom: 0; left: 0;
background-color: #fff; position: absolute !important;}
#mapL {right: 0%;}
#mapWE {left: 100%;}
#coords {position: absolute; bottom: 0;}
</style>
</head>
<body onload="javascript:init()">
<div id="mapL"></div>
<div id="mapWE"></div>
<div id="coords"></div>
</body>
</html>
'''
class Backend(QObject):
positionChanged = pyqtSignal(float, float)
def __init__(self, parent=None):
QObject.__init__(self, parent)
self.position = None, None
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.on_timeout)
#pyqtSlot(QJsonValue)
def print(self, val):
coords = val.toObject()
lat, lng = (coords[key].toDouble() for key in ("lat", "lng"))
self.position = lat, lng
if not self.timer.isActive():
self.timer.start()
def on_timeout(self):
self.positionChanged.emit(*self.position)
def foo(lat, lng):
# this function will be called every second.
print(lat, lng)
if __name__ == '__main__':
app = QApplication(sys.argv)
view = QWebEngineView()
view.setWindowTitle("Serial GPS Emulator");
backend = Backend(view)
backend.positionChanged.connect(foo)
channel = QWebChannel()
channel.registerObject('backend', backend)
view.page().setWebChannel(channel)
view.setHtml(maphtml)
view.show()
sys.exit(app.exec_())

Google Visualization Multiple Query (Spreedsheet)

I have to show multiple chart on a HTML page, but i can't make multiple query (directly on a google spreedsheet).
Actually, I have just the first query who is display.
My code :
<html>
<head>
<meta charset="utf-8">
<title>Page de pilotage</title>
<link rel=stylesheet type="text/css" href="style.css">
<script type="text/javascript" src="javascript.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", '1', {packages:['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/xxx/gviz/tq?sheet=visites');
var query2 = new google.visualization.Query('https://docs.google.com/spreadsheets/d/xxx/gviz/tq?sheet=transactions');
query.send(handleQueryResponse);
query2.send(handleQueryResponse);
}
function handleQueryResponse(response) {
var options = {
pointSize: 4,
title: '',
}
var data = response.getDataTable();
var chart = new google.visualization.LineChart(document.getElementById('visites'));
var chart2 = new google.visualization.LineChart(document.getElementById('transactions'));
chart.draw(data, options);
chart2.draw(data, options);
}
</script>
</head>
<body>
<h1>Page de pilotage - KPI/PROGRESSION</h1>
<p>Cette page WEB rassemble des informations générales pour aider au pilotage du site</p>
<h2>PROGRESSION</h2>
<div style="width:1200px;">
<div style="width:599px; float:left;">
<h3>NOMBRE DE VISITES</h3>
<div id="visites" style="height: 280px; z-index: 1; margin-top: -25px; border-right:1px solid #ccc;"></div>
</div>
<div style="width:599px; float:right;">
<h3>NOMBRE DE TRANSACTIONS</h3>
<div id="transactions" style="height: 280px; z-index: 1; margin-top: -25px;"></div>
</div>
</div>
</body>
</html>
I think the problem was on these lines :
query.send(handleQueryResponse);
query2.send(handleQueryResponse);
function drawChart() {
var visites = new google.visualization.Query('https://docs.google.com/spreadsheets/d/xxx/gviz/tq?sheet=visites');
var transactions = new google.visualization.Query('https://docs.google.com/spreadsheets/d/xxx/gviz/tq?sheet=transactions');
visites.send(handleQueryResponse);
transactions.send(handleQueryResponse2);
conversion.send(handleQueryResponse3);
rebond.send(handleQueryResponse4);
}
function handleQueryResponse(response) {
var options = {
pointSize: 4,
title: '',
}
var data = response.getDataTable();
var chart = new google.visualization.LineChart(document.getElementById('visites'));
chart.draw(data, options);
}
function handleQueryResponse2(response) {
var options = {
pointSize: 4,
title: '',
}
var data = response.getDataTable();
var chart2 = new google.visualization.LineChart(document.getElementById('transactions'));
chart2.draw(data, options);
}

Openlayers - display pacific markers popup using marker id and onclick event

I have the following code which addes 3 markers to the map along with there popup boxes what I want to do is have a list of location at bottom of page and using the id of the marker when click a place in the list it just make that places popup appear on the map.
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Open Street Map</title>
<style type="text/css">
body { font: normal 10pt Helvetica, Arial; }
#map { width: 100%; height: 100%; border: 0px; padding: 0px; }
</style>
<script src="lib/OpenLayers.js" type="text/javascript"></script>
<script type="text/javascript">
var iconSize = new OpenLayers.Size(21, 25);
var iconOffset = new OpenLayers.Pixel(-(iconSize.w / 2), -iconSize.h);
var icon = new OpenLayers.Icon("img/fourmarker.png",
iconSize, iconOffset);
var zoom, center, currentPopup, map, lyrMarkers;
var popupClass = OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
"autoSize": true,
"minSize": new OpenLayers.Size(300, 50),
"maxSize": new OpenLayers.Size(500, 300),
"keepInMap": true
});
var bounds = new OpenLayers.Bounds();
function addMarker(id, lng, lat, info) {
var pt = new OpenLayers.LonLat(lng, lat)
.transform(new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject());
bounds.extend(pt);
var feature = new OpenLayers.Feature(lyrMarkers, pt);
feature.closeBox = true;
feature.popupClass = popupClass;
feature.data.popupContentHTML = info ;
feature.data.overflow = "auto";
var marker = new OpenLayers.Marker(pt, icon.clone());
var markerClick = function(evt) {
if (currentPopup != null && currentPopup.visible()) {
currentPopup.hide();
}
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
marker.events.register("mousedown", feature, markerClick);
lyrMarkers.addMarker(marker);
}
function initMap() {
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
numZoomLevels: 19,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-0.13011, -0.13011, 51.51039, 51.51039)
};
map = new OpenLayers.Map("map", options);
map.addControl(new OpenLayers.Control.DragPan());
var lyrOsm = new OpenLayers.Layer.OSM();
map.addLayer(lyrOsm);
lyrMarkers = new OpenLayers.Layer.Markers("Markers");
map.addLayer(lyrMarkers);
//add marker on given coordinates
addMarker('1',-0.12519,51.51112 , '<b>Tescos</b><br/>Covent garden');
addMarker('2',-0.13264,51.50918 , '<b>Spar</b><br/>Leicester Square');
addMarker('3', -0.12498,51.50807 , '<b>M & S</b><br/>Embankment');
center = bounds.getCenterLonLat();
map.setCenter(center, map.getZoomForExtent(bounds) - 1);
zoom = map.getZoom();
}
</script>
</head>
<body onload="initMap()" style="margin:0; border:0; padding:0; width:1000px; height:500px;">
<div id="map"></div>
</body>
</html>
EXTRA INFORMATION
I am going to add a list to bottom of map like so:
<ul>
<li>location1</li>
<li>location2</li>
<li>location3</li>
</ul>
What i want to get working is when the user clicks so location1 alink then that relevent popup box will show and the other will be removed.
How would this be done.
This very fast example (modify addMarker function):
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Open Street Map</title>
<style type="text/css">
body { font: normal 10pt Helvetica, Arial; }
#map { width: 100%; height: 100%; border: 0px; padding: 0px; }
#list > div { background-color: #aaa; margin-top: 10px; }
</style>
<script src="http://openlayers.org/api/OpenLayers.js" type="text/javascript"> </script>
</head>
<body onload="initMap()" style="margin:0; border:0; padding:0; width:1000px; height:500px;">
<div id="map"></div>
<div id="list" style="width:100%; height: 100%"></div>
</body>
<script type="text/javascript">
var iconSize = new OpenLayers.Size(21, 25);
var iconOffset = new OpenLayers.Pixel(-(iconSize.w / 2), -iconSize.h);
var icon = new OpenLayers.Icon("img/fourmarker.png",
iconSize, iconOffset);
var list = document.getElementById('list');
var zoom, center, currentPopup, map, lyrMarkers;
var popupClass = OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
"autoSize": true,
"minSize": new OpenLayers.Size(300, 50),
"maxSize": new OpenLayers.Size(500, 300),
"keepInMap": true
});
var bounds = new OpenLayers.Bounds();
function addMarker(id, lng, lat, info) {
var pt = new OpenLayers.LonLat(lng, lat)
.transform(new OpenLayers.Projection("EPSG:4326"),
map.getProjectionObject());
bounds.extend(pt);
var feature = new OpenLayers.Feature(lyrMarkers, pt);
feature.closeBox = true;
feature.popupClass = popupClass;
feature.data.popupContentHTML = info ;
feature.data.overflow = "auto";
var marker = new OpenLayers.Marker(pt, icon.clone());
var markerClick = function(evt) {
if (currentPopup != null && currentPopup.visible()) {
currentPopup.hide();
}
if (this.popup == null) {
this.popup = this.createPopup(this.closeBox);
map.addPopup(this.popup);
this.popup.show();
} else {
this.popup.toggle();
}
currentPopup = this.popup;
OpenLayers.Event.stop(evt);
};
marker.events.register("mousedown", feature, markerClick);
lyrMarkers.addMarker(marker);
// add items
var listItem = OpenLayers.Util.createDiv(this.id, null, null, null, 'relative', null);
listItem.innerHTML = info;
list.appendChild(listItem);
var callback = function(e) {
marker.events.triggerEvent('mousedown');
console.log(marker);
OpenLayers.Event.stop(e);
};
OpenLayers.Event.observe(listItem, "touchend", OpenLayers.Function.bindAsEventListener(callback, this));
OpenLayers.Event.observe(listItem, "click", OpenLayers.Function.bindAsEventListener(callback, this));
}
function initMap() {
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
numZoomLevels: 19,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-0.13011, -0.13011, 51.51039, 51.51039)
};
map = new OpenLayers.Map("map", options);
map.addControl(new OpenLayers.Control.DragPan());
var lyrOsm = new OpenLayers.Layer.OSM();
map.addLayer(lyrOsm);
lyrMarkers = new OpenLayers.Layer.Markers("Markers");
map.addLayer(lyrMarkers);
//add marker on given coordinates
addMarker('1',-0.12519,51.51112 , '<b>Tescos</b><br/>Covent garden');
addMarker('2',-0.13264,51.50918 , '<b>Spar</b><br/>Leicester Square');
addMarker('3', -0.12498,51.50807 , '<b>M & S</b><br/>Embankment');
center = bounds.getCenterLonLat();
map.setCenter(center, map.getZoomForExtent(bounds) - 1);
zoom = map.getZoom();
}
</script>
</html>

Categories

Resources