为什么在setInterval循环之外找不到这些函数? (JavaScript的)

时间:2015-08-14 03:58:13

标签: javascript

我使用planetaryjs包在js中绘制地球。

有一个功能planetary.plugins.pings.add。它在这个循环中有效:

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);

但我只想绘制一个ping,所以我做了

    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 });

但是firefox告诉我

TypeError: globe.plugins.pings is undefined

有人知道为什么会这样吗?这里有完整的代码(见第67-77行)。来源是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>

3 个答案:

答案 0 :(得分:3)

用setTimeout替换setInterval。

直接调用失败的原因是global_plugins.pings在调用globe.draw(canvas);之前未初始化。你也可以在此之后移动它。

与通过代码块替换它相比,setTimeout将代码块的执行移动到执行队列的末尾,即直到globe.draw(canvas)之后;调用并调整globe.plugins.pings - 但与setInterval不同,它只运行一次。

答案 1 :(得分:3)

最好使用某种回调而不是仅仅回复随机超时。 像这样的东西。 planet.onInit( function([done]){} )

答案 2 :(得分:1)

在执行时没有初始化DOM,你应该将初始化包装在document.addEventListener('DOMContentLoaded', function () { /* your code here */ });