Attach Google Charts on Leaflet Popup - leaflet

I tried to attach a google chart on the popup of a layer in Leaflet by followed this instruction. However, I keep getting this error:
"Uncaught (in promise) Error: Container is not defined"
Here is my javascript function that I use to bind the popup:
function layer_name(feature, layer) {
//...
var popupContent = L.popup().setContent('<div id="chart_div" align = "center">1</div>')
layer.bindPopup(popupContent, {maxHeight: 400});
}
When I tried setting
<div id="chart_div" align = "center">1</div>
as just an HTML element there is no error raised.
I have also define the chart to be drawn at the very beginning of the script as below:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
// Load Charts and the corechart package.
google.charts.load('current', {'packages':['corechart']});
// Draw the pie chart for follower chart when Charts is loaded.
google.charts.setOnLoadCallback(drawChart);
// Callback that draws the bar
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Title', 'Value'],
['A', 317],
['B', 148],
['C', 67],
['D', 27],
['E', 23]
]);
var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
chart.draw(data);
}
</script>
How can I fix this?

Your problem is that your HTML Element chart_div is not created until the popup is open. But you try to init the chart on the not created HTML Element.
Call drawChart() after the popup is opened.
Update your layer_name function and add the openpopup event to the layer. It will called when you open the popup.
function layer_name(feature, layer) {
//...
var popupContent = L.popup().setContent('<div id="chart_div" align="center">1</div>')
layer.bindPopup(popupContent, {maxHeight: 400});
layer.on('popupopen',function(e){
drawChart();
})
}

Related

Google Charts in Tampermonkey Not Working

Thanks to this community for all the great help. I have been successful adding new JS functionality to some webpages with Tampermonkey. Now I am trying to show a Google Chart injected on a webpage. Chrome browser. I have been trying on and off for several months, and no joy. I stripped everything down to the simplest TM script to show a pie chart, URL matching on Google home page. The DIV is visible but no chart is rendered. No related errors in JS console.
The chart renders fine if NOT using Tampermonkey.
https://jsfiddle.net/_pirateX/ue88hus0/
I have tried window.onload in various positions, and moved the Google chart loader in various places. I have tried to set the load callback just using the function name drawChart, but no change.
Can anyone please assist and tell me why this is not working. I would be eternally grateful.
// #name Chart Example1
// #namespace http://tampermonkey.net/
// #version 1.0.0
// #description try to take over the world!
// #author You
// #require https://www.gstatic.com/charts/loader.js
// #match https://www.google.com
// ==/UserScript==
/* global google */
'use strict';
google.charts.load("current", {packages:["corechart"]});
window.onload = function() {
var myWrapper = document.createElement('div');
myWrapper.style.position = 'fixed';
myWrapper.id = "myChart";
myWrapper.style.width = '600px';
myWrapper.style.height = '300px';;
myWrapper.style.right = '1em';
myWrapper.style.top= '10em';
myWrapper.style.background = 'rgba(255, 255, 255, 1)';
myWrapper.style.border = '2px solid grey';
document.body.append(myWrapper);
//put here code
google.charts.setOnLoadCallback(function() { drawChart()});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Group');
data.addColumn('number', 'Gender');
data.addRows([
['Males', 10],
['Females', 5]
]);
var options = {'title':'Gender distribution',
'width':300,
'height':300};
var chart = new google.visualization.PieChart(document.getElementById('myChart'));
chart.draw(data, options);
}
}
google's load statement will wait for the page to load by default,
so you can use the load statement, in place of window.onload
try placing the code inside the promise the load statement returns...
google.charts.load("current", {
packages:["corechart"]
}).then(function () {
var myWrapper = document.createElement('div');
myWrapper.style.position = 'fixed';
myWrapper.id = "myChart";
myWrapper.style.width = '600px';
myWrapper.style.height = '300px';;
myWrapper.style.right = '1em';
myWrapper.style.top= '10em';
myWrapper.style.background = 'rgba(255, 255, 255, 1)';
myWrapper.style.border = '2px solid grey';
document.body.append(myWrapper);
var data = new google.visualization.DataTable();
data.addColumn('string', 'Group');
data.addColumn('number', 'Gender');
data.addRows([
['Males', 10],
['Females', 5]
]);
var options = {'title':'Gender distribution',
'width':300,
'height':300};
var chart = new google.visualization.PieChart(document.getElementById('myChart'));
chart.draw(data, options);
});
Apparently there is some incompatibility in the way TM loads/uses Google loader.js. In Github repository, I got a reply from the developer of TM as follows:
The loader injects a script into the page, but the#require'd script "lives" inside the sandbox. Please use #unwrap to make it work.
#unwrap will be included in next release. In the meantime, testing revealed that loading Google loader.js via JS is also effective:
// ==UserScript==
// #name Histogram
// #namespace http://tampermonkey.net/
// #version 0.1
// #description Show histogram.
// #author Me.
// #match https://match.com*
// #icon https://www.google.com/s2/favicons?domain=mydomain
// #require file://D:\mycode.js
// ==/UserScript==
/* global google, injectChartDiv, drawChart */
'use strict';
// Set up onload callback.
window.onload = drawChart;
// Load the Google charts loader.js
var my_script = document.createElement('script');
my_script.setAttribute('src','https://www.gstatic.com/charts/loader.js');
document.head.appendChild(my_script);
I will update this answer as I learn more about #unwrap. For now, my chart is rendering yay! Thanks everyone.

How to draw a polyline with initial point in Leaflet

I'm using custom polyline drawer from Leaflet.draw
let polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable()
I need to programmatically add starting point to polyline
I've tried calling addVertex of L.Draw.Polyline. Looks like it's doesn't work with custom polyline drawer cause of addHooks or something... Tried to change sources, no results.
Also tried firing click on map after drawer is enabled. Like so:
let point = new L.LatLng(x, y)
map.fireEvent('click', {
latlng: point,
layerPoint: map.latLngToLayerPoint(point),
containerPoint: map.latLngToContainerPoint(point),
})
Also doesn't work
EDIT: Actually, AddVertex does work with custom polylines. It "didn't work" because I passed wrong arguments in my function. Somehow, I missed that.
Using addVertex on your drawer object does let you add a starting point to your line :
var polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable();
var latlng = L.latLng(48.8583736, 2.2922926);
polylineDrawer.addVertex(latlng);
and a demo
var style = {
stroke: true,
color: 'red',
weight: 4,
opacity: 0.5
};
var map = L.map(document.getElementById('map')).setView([48.8583736, 2.2922926], 15);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var drawnItems = new L.geoJson(null, {style: style}).addTo(map);
map.on(L.Draw.Event.CREATED, function (event) {
var layer = event.layer;
drawnItems.addLayer(layer);
});
var polylineDrawer = new L.Draw.Polyline(map, {})
polylineDrawer.enable();
var latlng = L.latLng(48.8583736, 2.2922926);
polylineDrawer.addVertex(latlng);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 100%;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js" integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log==" crossorigin=""></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.12/leaflet.draw.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.12/leaflet.draw.js"></script>
<div id='map'></div>

Google Piechart

i try to create a pie chart on my Website, i found the example code
<div id="piechart"></div>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
// Load google charts
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
// Draw the chart and set the chart values
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Task', 'Hours per Day'],
['Work', 8],
['Eat', 2],
['TV', 4],
['Gym', 2],
['Sleep', 8]
]);
// Optional; add a title and set the width and height of the chart
var options = {'title':'My Average Day', 'width':550, 'height':400};
// Display the chart inside the <div> element with id="piechart"
var chart = new google.visualization.PieChart(document.getElementById('piechart'));
chart.draw(data, options);
}
</script>
(https://www.w3schools.com/howto/tryit.asp?filename=tryhow_google_pie_chart)
But i only get a Error Message :
Table has no columns.
Can someone help me pls?
Thanks
unfortunatelly I cannot comment.
This code works - fiddle. Could you give more details about this project?
sample of code for fiddle
<div id="piechart"></div>
edit:
Table has no columns.
Is this error message from browser console?

how to create a jsfiddle using leaflet

I am struggling with jsfiddle trying to create a running example which uses leaflet.
because I was not successful I searched for some examples and found the following one working:
http://jsfiddle.net/kedar2a/LnzN2/2/
I then copied the example in a new fiddle
https://jsfiddle.net/aLn3ut5z/1/
but it is still not working...
when inserting the external resources, there was the following error:
jsfiddle.net says:
You're loading resources over HTTP not HTTPS, your fiddle will not
work. Do you wish to continue?
any suggestions what is wrong here?
p.s.: below is the code of the jsfiddle windows:
HTML:
<div id="map"></div>
CSS:
#map {
height: 500px;
width: 80%;
}
JAVASCRIPT:
// We’ll add a tile layer to add to our map, in this case it’s a OSM tile layer.
// Creating a tile layer usually involves setting the URL template for the tile images
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([19.04469, 72.9258], 12).addLayer(osm);
// Script for adding marker on map click
function onMapClick(e) {
var marker = L.marker(e.latlng, {
draggable: true,
title: "Resource location",
alt: "Resource Location",
riseOnHover: true
}).addTo(map)
.bindPopup(e.latlng.toString()).openPopup();
// Update marker on changing it's position
marker.on("dragend", function(ev) {
var chagedPos = ev.target.getLatLng();
this.bindPopup(chagedPos.toString()).openPopup();
});
}
map.on('click', onMapClick);
The Leaflet CDN doesn't support SSL yet. You can use something not requiring https, like playground-leaflet which is just a fork of JSBin with leaflet libraries easily selectable.
Alternatively, you could use Leaflet from cdnjs.net, which does support https.

How to make KendoUI grid.setOptions working with MVVM?

In latest release kendo introduced ability for saving grid state and layout which I can't make working with the javascript MVVM declared grid.
My problem can be reproduced by performing few simple steps with bellow given jsfiddle code
Resize columns
Save the state
Move the columns to some other width
Load the state
What I would expect to be the outcome is that after step #4, column width will be reset to saved state.
What I see in my repro is that grid.setOptions just reset the grid to initial unmodified state.
Here's the jsfiddle repro link also given as inline code snippet here...
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
data: [
{name: 'John', surname: 'Smith'},
{name: 'John', surname: 'Doe'}
]
});
var dataContext = new kendo.data.ObservableObject({
dataSource: self.remoteDataSource
});
var viewTemplate =
"<div id='grid' data-role='grid' data-sortable='true' data-editable='true' " +
"data-resizable='true' data-reorderable='true' data-navigatable='true' " +
"data-columns=\"[{'field':'name', 'title':'Name'}, {'field': 'surname', 'title': 'Surname'}]\"" +
" data-bind='source: dataSource' />";
// now get the main view
var kendoView = new kendo.View(viewTemplate, {
wrap: false,
model: dataContext
});
kendoView.render($("body"));
var grid = $("#grid").data("kendoGrid");
$("#save").click(function (e) {
e.preventDefault();
var options = grid.getOptions();
console.log(options);
localStorage["kendo-grid-options"] = kendo.stringify(options);
});
$("#load").click(function (e) {
e.preventDefault();
var optionsString = localStorage["kendo-grid-options"];
if (optionsString) {
var options= JSON.parse(optionsString);
console.log(options);
grid.setOptions(options);
}
});
});
<link href="http://cdn.kendostatic.com/2014.3.1119/styles/kendo.common.min.css" rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2014.3.1119/styles/kendo.metro.min.css" rel="stylesheet" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.3.1119/js/kendo.all.min.js"></script>
<body>
<div class="box">
Save State
Load State
</div>
</body>
I have just received the answer from Telerik customer support with a working resolution tip
This weird behavior is coming from the fact that the options are first provided through data-attributes and then the setOptions method of the Grid new options are passed through JavaScript, however the data-attribute options are still on the element and they are still considered options higher priority at this point.
As a temporary work-around you can remove the data-attribute that gives the column options and then the new options should be applied.