Related
I am trying to draw svg markers on a PixiOverlay.js (a drawing overlay using Pixi.js). Completely new to Pixi myself, I think I have put something together that draws a diamond shape, see first code snippet (if it is not correct, or needs improvement let me know)
On pixiOverlay github page there is a nice demo that renders lots of polygons on a map. I have stripped this demo down to its bare minimum (see second code snippet below). In this code there is a drawPoly function which as the name suggests, draws the polygons.
I want to replace that with another function that just draws the diamond-shaped svg marker at some predefined point (could be the first point in the polygon coordinates for example, or just a random one)
How can I do this please?
In real life I have quite a few of these markers, all some geometric shape like triangles, stars, squares, circles, etc, and in total there will be several thousands of them (like 100K or even more, depending on the zoom level ofcourse. At zoom=0 could be close to a million)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src='https://d157l7jdn8e5sf.cloudfront.net/dev/pixi.js'></script>
<!--<script src="https://cdn.rawgit.com/manubb/Leaflet.PixiOverlay/master/docs/js/example.min.js">--></script>
<script id="rendered-js">
var renderer;
renderer = PIXI.autoDetectRenderer();
document.body.appendChild(renderer.view);
var graphics = new PIXI.Graphics();
graphics.lineStyle(5, 0x00FF00, 1);
graphics.moveTo(0, 75);
graphics.lineTo(50, 0);
graphics.lineTo(100, 75);
graphics.lineTo(50, 150);
graphics.lineTo(0, 75);
graphics.cacheAsBitmap = true;
renderer.render(graphics);
</script>
</body>
</html>
<!DOCTYPE html>
<html style="height: 100%; margin: 0;">
<head>
<title>Leaflet.PixiOverlay example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<!--jquery -->
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!--d3 -->
<script src='https://d3js.org/d3.v4.min.js'></script>
<!-- leaflet v 1.0.3 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.3/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet#1.0.3/dist/leaflet-src.js"></script>
<!-- I think this Pixi.js and PixiOverlay.js in one file?? -->
<script src="https://cdn.rawgit.com/manubb/Leaflet.PixiOverlay/master/docs/js/example.min.js"></script>
</head>
<body style="height: 100%; margin: 0; overflow: hidden;">
<div id="mymap" style="height: 100%; width: 100%;" >
</div>
<script>
var countries =
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "UK"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-4.965, 58.58], [-5.97, 57.58], [-6.459, 56.31], [-5.05, 54.72],[-3.47, 54.36], [-4.08, 53.27],[-5.22, 51.78],[-3.38, 51.37],[-5.58, 50.12], [1.31, 51.09],[0.61, 51.42], [1.66, 52.69],[0.04, 52.88], [0.39, 53.40],[-2.32, 55.97], [-1.80, 57.53],[-3.95, 57.58], [-3.03, 58.60], [-4.96, 58.58],
]
]
}
},
{
"type": "Feature",
"properties": {"name": "France"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[2.54, 51.09],[-4.65, 48.37],[-1.23, 46.01],[-1.49, 43.61],[3.03, 42.45],[3.64, 43.45],[7.69, 43.77], [5.97, 46.37],[8.04, 48.98],[2.54, 51.09],
]
]
}
}
]
};
function drawPoly(color, alpha, project, container) {
return function (poly) {
var shape = new PIXI.Polygon(poly[0].map(function (point) {
var proj = project([point[1], point[0]]);
return new PIXI.Point(proj.x, proj.y);
}));
container.beginFill(color, alpha);
container.drawShape(shape);
};
}
function renderChart() {
var map = L.map('mymap').setView(new L.LatLng(50, 1.0), 5);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
minZoom: 0,
maxZoom: 9
}).addTo(map);
map.zoomControl.setPosition('bottomright');
var firstDraw = true;
var pixiContainer = new PIXI.Graphics();
var doubleBuffering = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
var pixiOverlay = L.pixiOverlay(function (utils) {
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var bounds;
if (firstDraw) {
countries.features.forEach(function (feature, index) {
var color = 0xFF0000,
alpha = 0.8;
if (feature.geometry === null) return;
if (feature.geometry.type === 'Polygon') {
bounds = L.bounds(feature.geometry.coordinates[0]);
drawPoly(color, alpha, project, container)(feature.geometry.coordinates);
}
});
}
firstDraw = false;
renderer.render(container);
}, pixiContainer, {
doubleBuffering: doubleBuffering,
destroyInteractionManager: true
});
pixiOverlay.addTo(map);
};
renderChart()
</script>
</body>
</html>
Just as drawPoly() make another function for drawMarker(), put your marker code in it and pass the container (as done in the example you gave).
I have used your example:
<!DOCTYPE html>
<html style="height: 100%; margin: 0;">
<head>
<title>Leaflet.PixiOverlay example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<!--jquery -->
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<!--d3 -->
<script src='https://d3js.org/d3.v4.min.js'></script>
<!-- leaflet v 1.0.3 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.3/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet#1.0.3/dist/leaflet-src.js"></script>
<!-- I think this Pixi.js and PixiOverlay.js in one file?? -->
<script src="https://cdn.rawgit.com/manubb/Leaflet.PixiOverlay/master/docs/js/example.min.js"></script>
</head>
<body style="height: 100%; margin: 0; overflow: hidden;">
<div id="mymap" style="height: 100%; width: 100%;" >
</div>
<script>
var countries =
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name": "UK"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-4.965, 58.58], [-5.97, 57.58], [-6.459, 56.31], [-5.05, 54.72],[-3.47, 54.36], [-4.08, 53.27],[-5.22, 51.78],[-3.38, 51.37],[-5.58, 50.12], [1.31, 51.09],[0.61, 51.42], [1.66, 52.69],[0.04, 52.88], [0.39, 53.40],[-2.32, 55.97], [-1.80, 57.53],[-3.95, 57.58], [-3.03, 58.60], [-4.96, 58.58],
]
]
}
},
{
"type": "Feature",
"properties": {"name": "France"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[2.54, 51.09],[-4.65, 48.37],[-1.23, 46.01],[-1.49, 43.61],[3.03, 42.45],[3.64, 43.45],[7.69, 43.77], [5.97, 46.37],[8.04, 48.98],[2.54, 51.09],
]
]
}
}
]
};
function drawMarker(container, coords)
{
var graphics = new PIXI.Graphics();
graphics.lineStyle(10, 0xFFF0000, 1);
graphics.moveTo(0, 75);
graphics.lineTo(50, 0);
graphics.lineTo(100, 75);
graphics.lineTo(50, 150);
graphics.lineTo(0, 75);
graphics.cacheAsBitmap = true;
//graphics.width = 1000;
posX = 3000; //just a temp value
posY = 2000; // just a temp value
graphics.x = posX;
graphics.y = posY;
console.log(graphics.y);
container.addChild(graphics);
}
function drawPoly(color, alpha, project, container) {
return function (poly) {
var shape = new PIXI.Polygon(poly[0].map(function (point) {
var proj = project([point[1], point[0]]);
return new PIXI.Point(proj.x, proj.y);
}));
container.beginFill(color, alpha);
container.drawShape(shape);
};
}
function renderChart() {
var map = L.map('mymap').setView(new L.LatLng(50, 1.0), 5);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
minZoom: 0,
maxZoom: 9
}).addTo(map);
map.zoomControl.setPosition('bottomright');
var firstDraw = true;
var pixiContainer = new PIXI.Graphics();
var doubleBuffering = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
var pixiOverlay = L.pixiOverlay(function (utils) {
var container = utils.getContainer();
var renderer = utils.getRenderer();
var project = utils.latLngToLayerPoint;
var bounds;
if (firstDraw) {
countries.features.forEach(function (feature, index) {
var color = 0xFF0000,
alpha = 0.8;
if (feature.geometry === null) return;
if (feature.geometry.type === 'Polygon') {
bounds = L.bounds(feature.geometry.coordinates[0]);
// drawPoly(color, alpha, project, container)(feature.geometry.coordinates);
drawMarker(container, feature.geometry.coordinates);
}
});
}
firstDraw = false;
renderer.render(container);
}, pixiContainer, {
doubleBuffering: doubleBuffering,
destroyInteractionManager: true
});
pixiOverlay.addTo(map);
};
renderChart()
</script>
</body>
</html>
I'm processing a multi-polygon geojson, but some polygons are not rendered with mapbox-gl-js, generating some gaps. The use of mapbox-js features renders correctly.
This problem only occurs with the mapbox-gl-js API.
This problem also occurs in Mapbox Studio when rederizing a tileset in a style even though the polygon exists in the dataset.
That's the link to the geojson:
geojson
This is the code snippet where I add the layer, with mapbox-gl-js:
map.addSource( < id > , {
type: 'vector',
url: < url >
});
map.addLayer({
"id": < id > ,
"type": "fill",
"source": < id > ,
"source-layer": < id > ,
"layout": {},
"paint": {
"fill-color": ["interpolate", ["linear"],
["get", "title"], 0.00, "red", 0.30, "#8aac75", 0.60, "#00e6e6", 0.90, "#00c0cc", 1.20, "#00a5cc", 1.50, "#007fcc", 1.80, "#000066", 2.10, "#0018cc", 2.40, "#0000ba", 2.70, "#000099", 3.00, "#000076", 3.30, "#000066", 3.60, "purple"
]
}
}, < layerId > );
This is the code snippet where I add the layer, with mapbox-js:
var featureLayer = L.mapbox.featureLayer().addTo(tmap);
featureLayer.loadURL('/geojson');
Would anyone know what may be generating this error?
I use the following libraries:
leaflet.js
leaflet.markercluster.js
leaflet.subgroup.js
and my own script.
I have 3 marker types, all in a different subgroups. 11 Markers are on the same location. When I open the cluster the spider is shown, on unchecking 1 marker type, the spider is closed and the counter shows the right value. When I reopen the cluster, modified spider is shown.
Checking the marker type does not put the extra spider-marker on the screen, but also does not close the spider.
How can I force the spider to be closed?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Bee-Idees kaart</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css" />
<script type='text/javascript' src='https://unpkg.com/leaflet#1.3.1/dist/leaflet.js'></script>
<script type='text/javascript' src='https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster.js'></script>
<script type='text/javascript' src='https://unpkg.com/leaflet.featuregroup.subgroup#1.0.2/dist/leaflet.featuregroup.subgroup.js'></script>
</head>
<body>
<div id="map" style="height: 580px; border: 1px solid #AAA;"></div>
</body>
<script>
markers = [
{
"name": "Moordrecht",
"lat": 52.019716,
"lng": 5.183973,
"marker": "green"
},
{
"name": "Zoetermeer",
"lat": 52.046985,
"lng": 4.478968,
"marker": "red"
},
{
"name": "Gouda",
"lat": 52.021616,
"lng": 4.687917,
"marker": "green"
},
{
"name": "Gouda 2",
"lat": 52.021616,
"lng": 4.687917,
"marker": "blue"
},
{
"name": "Gouda 3",
"lat": 52.021616,
"lng": 4.687917,
"marker": "red"
}
];
</script>
<script>
var iconBase = 'css\\icons\\';
// Standard fields
var groupLabel = [];
groupLabel[0] = "Red";
groupLabel[1] = "Blue";
groupLabel[2] = "Green";
var map = L.map('map', {
center: [52.021616, 4.85],
zoom: 10
});
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
subdomains: ['a', 'b', 'c']
}).addTo(map);
var mcg = L.markerClusterGroup(),
group0 = L.featureGroup.subGroup(mcg),
group1 = L.featureGroup.subGroup(mcg),
group2 = L.featureGroup.subGroup(mcg),
control = L.control.layers(null, null, { collapsed: false }), i, a, title, m;
mcg.addTo(map);
var markerClusters = L.markerClusterGroup();
for (var i = 0; i < markers.length; ++i) {
var iconName = iconBase + markers[i].marker + ".png";
var myIcon = L.icon({ iconUrl: iconName, iconAnchor: [20, 40] })
var popup = '<h2>' + markers[i].name + '</h2>';
var m = L.marker( [markers[i].lat, markers[i].lng], {icon: myIcon, title: markers[i].name} )
.bindPopup( popup );
if (markers[i].marker === "red") { m.addTo(group0);}
else if (markers[i].marker === "blue") { m.addTo(group1); }
else if (markers[i].marker === "green") { m.addTo(group2); }
}
control.addOverlay(group0, groupLabel[0]);
control.addOverlay(group1, groupLabel[1]);
control.addOverlay(group2, groupLabel[2]);
control.addTo(map);
group0.addTo(map);
group1.addTo(map);
group2.addTo(map);
map.addLayer(mcg);
map.on('overlayadd', function() {
// How can I close the spider
});
map.on('overlayremove', function() {
});
</script>
</html>
Pasted the code provided in your question into Plunker for a live demo: https://plnkr.co/edit/ZzKRs5NnrJeWfBKWOA3R?p=preview
Hum looks like you are hitting a bug in Leaflet.markercluster.
When you tick in your SubGroup in the Layers Control, the former will use the parent group's (mcg in your case) addLayers method if it exists.
While MCG addLayer (single) correctly unspiderfies, this step is missing in addLayers (batch).
Reproducing the bug with a more simple example: https://plnkr.co/edit/G4GAjax5fi3LUqJRLLPN?p=preview (without Leaflet.FeatureGroup.SubGroup plugin)
Then it should be quite simple to fix this bug: simply unspiderfy, similarly to how it is done in addLayer:
if (this._map && this._unspiderfy) {
this._unspiderfy();
}
Updated simple example: https://plnkr.co/edit/lgvRtiRo7nh9VaWuI0RM?p=preview
Updated your code: https://plnkr.co/edit/CjjcHlZW6vpJ6075Ma3F?p=preview
I have issues when trying to show a route on my leaflet map:
L.Routing.control({
router: L.Routing.mapbox(''),
profile:"mapbox/driving",
addWaypoints:false,
waypointMode:'snap',
routeWhileDragging: true,
show:false,
fitSelectedRoutes:false,
plan:false,
draggableWaypoints:false,
lineOptions:{
styles:[ {color: 'black', opacity: 0.8, weight: 6}, {color: 'red', opacity: 1, weight: 2}]
},
waypoints: [
L.Routing.waypoint(L.latLng(28.6114741,77.2112497),"New Dehli"),
L.Routing.waypoint(L.latLng(30.7304186,76.7789926),"Chandigarh"),
L.Routing.waypoint(L.latLng(31.1047637,77.1717752),"Shimla"),
L.Routing.waypoint(L.latLng(31.4493988,77.629702),"Rampur"),
L.Routing.waypoint(L.latLng(31.9755409,78.5961753),"Changoa"),
L.Routing.waypoint(L.latLng(32.2251899,78.0610693),"Kaza"),
L.Routing.waypoint(L.latLng(32.4513357,77.860656),"Hanse"),
L.Routing.waypoint(L.latLng(32.4386919,77.7497997),"losar gompa"),
],
}).addTo(map);
At the 7th waypoint (Hanse), the route is doing a U turn, adding a thousand kms to reach the 8th point that is only a few kms away.
What's going on here? I can't figure it out. Any help is welcome!
Welcome to SO!
This is reproducible with OSMR service instead of Mapbox:
var map = L.map("map").setView([32.4513357, 77.860656], 10);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
L.Routing.control({
//router: L.Routing.mapbox(''),
//profile: "mapbox/driving",
addWaypoints: false,
waypointMode: 'snap',
routeWhileDragging: true,
show: false,
fitSelectedRoutes: false,
plan: false,
draggableWaypoints: false,
lineOptions: {
styles: [{
color: 'black',
opacity: 0.8,
weight: 6
}, {
color: 'red',
opacity: 1,
weight: 2
}]
},
waypoints: [
/*L.Routing.waypoint(L.latLng(28.6114741, 77.2112497), "New Dehli"),
L.Routing.waypoint(L.latLng(30.7304186, 76.7789926), "Chandigarh"),
L.Routing.waypoint(L.latLng(31.1047637, 77.1717752), "Shimla"),
L.Routing.waypoint(L.latLng(31.4493988, 77.629702), "Rampur"),
L.Routing.waypoint(L.latLng(31.9755409, 78.5961753), "Changoa"),
L.Routing.waypoint(L.latLng(32.2251899, 78.0610693), "Kaza"),*/
L.Routing.waypoint(L.latLng(32.4513357, 77.860656), "Hanse"),
L.Routing.waypoint(L.latLng(32.4386919, 77.7497997), "losar gompa"),
],
}).addTo(map);
#map {
height: 200px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css">
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet-src.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine#3.2.7/dist/leaflet-routing-machine.css">
<script src="https://unpkg.com/leaflet-routing-machine#3.2.7/dist/leaflet-routing-machine.js"></script>
<div id="map"></div>
It looks like the OSM database thinks there is a "barrier" obstacle near your arrival point ("losar gompa"):
If this obstacle type cannot be crossed by car, that would explain why the router takes another (very long…) route instead.
If you think this obstacle no longer exists, please feel free to create an account on OpenStreetMap and edit the map! There is a very high chance that Mapbox router uses OSM data, therefore your modifications would be reflected some time later in Mapbox.
I am trying to load a number of google charts on one page, however I am falling over trying to add the second.
I am testing the new Google Analytics SuperProxy feature, so the Data is being drawn in from a dataSourceURL
My code is below, as is the code works, however as soon as I uncomment out the section everything fails to load and for the life of me I cannot figure out how to fix this.
Hope someone can help.
<html>
<head>
<title>jmit</title>
<script type="text/javascript"
src='https://www.google.com/jsapi?autoload={"modules":[{"name":"visualization","version":"1","packages":["corechart","geochart"]}]}'>
</script>
<script type="text/javascript">
google.setOnLoadCallback(drawCharts);
function drawCharts(){
/*var data1 = new google.visualization.ChartWrapper({
"containerId":"Chart1_div",
"dataSourceUrl":"https://alexandalexaanalytics.appspot.com/query?id=ahdzfmFsZXhhbmRhbGV4YWFuYWx5dGljc3IVCxIIQXBpUXVlcnkYgICAgIDwiwoM&format=data-table-response",
"refreshInterval":3600,
"chartType":"GeoChart",
"options":{
"width": 630,
"height": 440,
"title": "test"
}
});
data1.draw();
}
*/
var data2 = new google.visualization.ChartWrapper({
"containerId":"Chart2_div",
"dataSourceUrl":"https://alexandalexaanalytics.appspot.com/query?id=ahdzfmFsZXhhbmRhbGV4YWFuYWx5dGljc3IVCxIIQXBpUXVlcnkYgICAgIDwiwoM&format=data-table-response",
"refreshInterval":3600,
"chartType":"ColumnChart",
"options":{
"width": 630,
"height": 440,
"title": "test"
}
});
data2.draw();
}
</script>
</head>
<body>
<h1>Test</h1>
<div id="Chart1_div"></div>
<p></p>
<div id="Chart2_div"></div>
</body>
</html>
You have an extra "}" after the data1.draw(); line, which is closing the drawCharts function. Removing that allows the queries to run, but you end up with conflicts between the two charts sending out queries to the same source for the same data. Since they are both running off the same data, it makes sense to use one query that populates both charts at the same time:
function drawCharts(){
var query = new google.visualization.Query('https://alexandalexaanalytics.appspot.com/query?id=ahdzfmFsZXhhbmRhbGV4YWFuYWx5dGljc3IVCxIIQXBpUXVlcnkYgICAgIDwiwoM&format=data-table-response');
query.setRefreshInterval(3600);
query.send(function (response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var dataTable = response.getDataTable();
var data1 = new google.visualization.ChartWrapper({
"containerId":"Chart1_div",
"dataTable":dataTable,
"refreshInterval":3600,
"chartType":"GeoChart",
"options":{
"width": 630,
"height": 440,
"title": "test"
}
});
data1.draw();
var data2 = new google.visualization.ChartWrapper({
"containerId":"Chart2_div",
"dataTable":dataTable,
"refreshInterval":3600,
"chartType":"ColumnChart",
"options":{
"width": 630,
"height": 440,
"title": "test"
}
});
data2.draw();
});
}
see it working here: http://jsfiddle.net/asgallant/j5eea/
There was a bug in the Google Analytics SuperProxy code which stopped multiple charts from running on a single page. This has now been updated, example html from githb is below.
Loads of thanks to asgallant for looking into this without his comments I wouldnt have know what to search for to answer this.
<! --
Based on demo video: https://www.youtube.com/watch?v=8Or8KIhpsqg
This shows you how to power 2 Pie Charts using the Google Analytics
superProxy. Each chart uses, as a data source, a public superProxy URL
with the format set to Data Table Response.
-->
<html>
<head>
<title>Pie!</title>
<!--Load the AJAX API-->
<script type="text/javascript"
src='https://www.google.com/jsapi?autoload={"modules":[{"name":"visualization","version":"1"}]}'>
</script>
<!-- Visualization -->
<!-- https://developers.google.com/chart/interactive/docs/reference#google.visualization.drawchart -->
<script type="text/javascript">
google.setOnLoadCallback(drawVisualization);
function drawVisualization() {
var browserWrapper = new google.visualization.ChartWrapper({
// Example Browser Share Query
"containerId": "browser",
// Example URL: http://your-application-id.appspot.com/query?id=QUERY_ID&format=data-table-response
"dataSourceUrl": "REPLACE WITH Google Analytics superProxy PUBLIC URL, DATA TABLE RESPONSE FORMAT",
"refreshInterval": REPLACE_WITH_A_TIME_INTERVAL,
"chartType": "PieChart",
"options": {
"showRowNumber" : true,
"width": 630,
"height": 440,
"is3D": true,
"title": "REPLACE WITH TITLE"
}
});
var countryWrapper = new google.visualization.ChartWrapper({
// Example Country Share Query
"containerId": "country",
"dataSourceUrl": "REPLACE WITH Google Analytics superProxy PUBLIC URL, DATA TABLE RESPONSE FORMAT",
"refreshInterval": REPLACE_WITH_A_TIME_INTERVAL,
"chartType": "PieChart",
"options": {
"showRowNumber" : true,
"width": 630,
"height": 440,
"is3D": true,
"title": "REPLACE WITH TITLE"
}
});
browserWrapper.draw();
countryWrapper.draw();
}
</script>
</head>
<body>
<h1>Pie!</h1>
<div id="browser" style="margin:auto;width:630px;"></div>
<div id="country" style="margin:auto;width:630px;"></div>
</body>
</html>