I'm using planetaryjs package to draw a globe in js.
There's a function planetary.plugins.pings.add. It works when it's in this loop:
setInterval(function() {
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
}, 200);
But I only want to draw one ping, so I did
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
But firefox tells me
TypeError: globe.plugins.pings is undefined
Does somebody know why is this? Complete code is here (see line 67-77). Source is here
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type='text/javascript' src='http://d3js.org/d3.v3.min.js'></script>
<script type='text/javascript' src="http://d3js.org/topojson.v1.min.js"></script>
<script type='text/javascript' src="http://labs.rivendellweb.net/data-vis/planetary/planetaryjs.js"></script>
</head>
<body>
<canvas id='rotatingGlobe' width='800' height='600' style='width: 800px; height: 600px; cursor: move;'></canvas>
<script>
(function() {
var globe = planetaryjs.planet();
// Load our custom `autorotate` plugin; see below.
globe.loadPlugin(autorotate(0));
// The `earth` plugin draws the oceans and the land; it's actually
// a combination of several separate built-in plugins.
// Note that we're loading a special TopoJSON file
// (world-110m-withlakes.json) so we can render lakes.
globe.loadPlugin(planetaryjs.plugins.earth({
topojson: { file: 'world-110m-withlakes.json' },
oceans: { fill: '#000080' },
land: { fill: '#339966' },
borders: { stroke: '#008000' }
}));
// Load our custom `lakes` plugin to draw lakes; see below.
globe.loadPlugin(lakes({
fill: '#000080'
}));
// The `pings` plugin draws animated pings on the globe.
globe.loadPlugin(planetaryjs.plugins.pings());
// The `zoom` and `drag` plugins enable
// manipulating the globe with the mouse.
globe.loadPlugin(planetaryjs.plugins.zoom({
scaleExtent: [100, 2000]
}));
globe.loadPlugin(planetaryjs.plugins.drag({
// Dragging the globe should pause the
// automatic rotation until we release the mouse.
onDragStart: function() {
this.plugins.autorotate.pause();
},
onDragEnd: function() {
this.plugins.autorotate.resume();
}
}));
// Set up the globe's initial scale, offset, and rotation.
globe.projection
.scale(400)
.translate([400, 300])
.rotate([-100, -30, 0]);
// Every few hundred milliseconds, we'll draw another random ping.
//var colors = ['red', 'yellow', 'white', 'orange', 'green', 'cyan', 'pink'];
setInterval(function() {
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
}, 200);
var lat = 30.2500;
var lng = 120.1667;
var color = 'white';
globe.plugins.pings.add(lng, lat, { color: color, ttl: 30000, angle: Math.random() * 10 });
var canvas = document.getElementById('rotatingGlobe');
// Special code to handle high-density displays (e.g. retina, some phones)
// In the future, Planetary.js will handle this by itself (or via a plugin).
if (window.devicePixelRatio == 2) {
canvas.width = 800;
canvas.height = 800;
context = canvas.getContext('2d');
context.scale(2, 2);
}
// Draw that globe!
globe.draw(canvas);
// This plugin will automatically rotate the globe around its vertical
// axis a configured number of degrees every second.
function autorotate(degPerSec) {
// Planetary.js plugins are functions that take a `planet` instance
// as an argument...
return function(planet) {
var lastTick = null;
var paused = false;
planet.plugins.autorotate = {
pause: function() { paused = true; },
resume: function() { paused = false; }
};
// ...and configure hooks into certain pieces of its lifecycle.
planet.onDraw(function() {
if (paused || !lastTick) {
lastTick = new Date();
} else {
var now = new Date();
var delta = now - lastTick;
// This plugin uses the built-in projection (provided by D3)
// to rotate the globe each time we draw it.
var rotation = planet.projection.rotate();
rotation[0] += degPerSec * delta / 1000;
if (rotation[0] >= 180) rotation[0] -= 360;
planet.projection.rotate(rotation);
lastTick = now;
}
});
};
};
// This plugin takes lake data from the special
// TopoJSON we're loading and draws them on the map.
function lakes(options) {
options = options || {};
var lakes = null;
return function(planet) {
planet.onInit(function() {
// We can access the data loaded from the TopoJSON plugin
// on its namespace on `planet.plugins`. We're loading a custom
// TopoJSON file with an object called "ne_110m_lakes".
var world = planet.plugins.topojson.world;
lakes = topojson.feature(world, world.objects.ne_110m_lakes);
});
planet.onDraw(function() {
planet.withSavedContext(function(context) {
context.beginPath();
planet.path.context(context)(lakes);
context.fillStyle = options.fill || 'black';
context.fill();
});
});
};
};
})();
</script>
</body>
</html>
Replace setInterval by setTimeout.
The reason your direct call fails is because globe.plugins.pings is not initialized till after globe.draw(canvas); is called. You could also move it to after this.
When compared to replacing it by the code block, setTimeout moves the execution of the code block to the end of the execution queue i.e. till after globe.draw(canvas); is called and globe.plugins.pings is initialized - but unlike setInterval, it runs only once.
it would be better to use some sort of callback rather than just replying on a random timeout.
Something like this.
planet.onInit( function([done]){} )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With