diff --git a/dist/planetaryjs-noplugins.js b/dist/planetaryjs-noplugins.js index 8a23f89..3d65f34 100644 --- a/dist/planetaryjs-noplugins.js +++ b/dist/planetaryjs-noplugins.js @@ -2,7 +2,7 @@ * Copyright (c) 2013 Brandon Tilley * * Released under the MIT license - * Date: 2013-12-21T08:56:23.017Z + * Date: 2013-12-21T19:00:54.881Z */ (function (root, factory) { if (typeof define === 'function' && define.amd) { @@ -28,24 +28,28 @@ }); }; - var startDraw = function(planet, canvas, localPlugins, hooks) { + var initPlugins = function(planet, localPlugins) { + // Add the global plugins to the beginning of the local ones for (var i = 0; i < plugins.length; i++) { localPlugins.unshift(plugins[i]); } - if (localPlugins.length == 0 && planetaryjs.plugins.earth) { - planet.loadPlugin(planetaryjs.plugins.earth()); + // Load the default plugins if none have been loaded so far + if (localPlugins.length == 0) { + if (planetaryjs.plugins.earth) + planet.loadPlugin(planetaryjs.plugins.earth()); + if (planetaryjs.plugins.pings) + planet.loadPlugin(planetaryjs.plugins.pings()); } for (var i = 0; i < localPlugins.length; i++) { - var plugin = localPlugins[i][0]; - var config = localPlugins[i][1]; - plugin(planet, config); + localPlugins[i](planet); } + }; - planet.canvas = canvas; - planet.context = canvas.getContext('2d'); - + var runOnInitHooks = function(planet, canvas, hooks) { + // onInit hooks can be asynchronous if they take a parameter; + // iterate through them one at a time if (hooks.onInit.length) { var completed = 0; var doNext = function(callback) { @@ -71,6 +75,15 @@ } }; + var startDraw = function(planet, canvas, localPlugins, hooks) { + initPlugins(planet, localPlugins); + + planet.canvas = canvas; + planet.context = canvas.getContext('2d'); + + runOnInitHooks(planet, canvas, hooks); + }; + var planetaryjs = { plugins: {}, @@ -79,8 +92,8 @@ return planetaryjs; }, - loadPlugin: function(plugin, defaultOptions) { - plugins.push([plugin, defaultOptions || {}]); + loadPlugin: function(plugin) { + plugins.push(plugin); }, planet: function() { @@ -103,8 +116,8 @@ hooks.onDraw.push(fn); }, - loadPlugin: function(plugin, defaultOptions) { - localPlugins.push([plugin, defaultOptions || {}]); + loadPlugin: function(plugin) { + localPlugins.push(plugin); }, withSavedContext: function(fn) { diff --git a/dist/planetaryjs-noplugins.min.js b/dist/planetaryjs-noplugins.min.js index 2f8787d..7a5ae86 100644 --- a/dist/planetaryjs-noplugins.min.js +++ b/dist/planetaryjs-noplugins.min.js @@ -1,2 +1,2 @@ /*! Planetary.js 0.0.0 | (c) 2013 Brandon Tilley | Released under MIT License */ -!function(n,t){"function"==typeof define&&define.amd?define(["d3","topojson"],t):"object"==typeof exports?module.exports=t(require("d3"),require("topojson")):n.planetaryjs=t(n.d3,n.topojson,n)}(this,function(n,t,o){"use strict";var e=null;o&&(e=o.planetaryjs);var i=[],r=function(t,o,e){n.timer(function(){t.context.clearRect(0,0,o.width,o.height);for(var n=0;n=e.onInit.length?r(n,t,e):h(l)};h(l)}else r(n,t,e)},c={plugins:{},noConflict:function(){return o.planetaryjs=e,c},loadPlugin:function(n,t){i.push([n,t||{}])},planet:function(){var t=[],o={onInit:[],onDraw:[]},e={draw:function(n){a(e,n,t,o)},onInit:function(n){o.onInit.push(n)},onDraw:function(n){o.onDraw.push(n)},loadPlugin:function(n,o){t.push([n,o||{}])},withSavedContext:function(n){if(!this.context)throw new Error("No canvas to fetch context for");this.context.save(),n(this.context),this.context.restore()}};return e.projection=n.geo.orthographic().clipAngle(90).precision(0),e.path=n.geo.path().projection(e.projection),e}};return c}); \ No newline at end of file +!function(n,t){"function"==typeof define&&define.amd?define(["d3","topojson"],t):"object"==typeof exports?module.exports=t(require("d3"),require("topojson")):n.planetaryjs=t(n.d3,n.topojson,n)}(this,function(n,t,o){"use strict";var e=null;o&&(e=o.planetaryjs);var i=[],r=function(t,o,e){n.timer(function(){t.context.clearRect(0,0,o.width,o.height);for(var n=0;n=o.onInit.length?r(n,t,o):i(u)};i(u)}else r(n,t,o)},a=function(n,t,o,e){u(n,o),n.canvas=t,n.context=t.getContext("2d"),c(n,t,e)},s={plugins:{},noConflict:function(){return o.planetaryjs=e,s},loadPlugin:function(n){i.push(n)},planet:function(){var t=[],o={onInit:[],onDraw:[]},e={draw:function(n){a(e,n,t,o)},onInit:function(n){o.onInit.push(n)},onDraw:function(n){o.onDraw.push(n)},loadPlugin:function(n){t.push(n)},withSavedContext:function(n){if(!this.context)throw new Error("No canvas to fetch context for");this.context.save(),n(this.context),this.context.restore()}};return e.projection=n.geo.orthographic().clipAngle(90).precision(0),e.path=n.geo.path().projection(e.projection),e}};return s}); \ No newline at end of file diff --git a/dist/planetaryjs.js b/dist/planetaryjs.js index bb204ca..5d96ccd 100644 --- a/dist/planetaryjs.js +++ b/dist/planetaryjs.js @@ -2,7 +2,7 @@ * Copyright (c) 2013 Brandon Tilley * * Released under the MIT license - * Date: 2013-12-21T08:56:22.909Z + * Date: 2013-12-21T19:00:54.985Z */ (function (root, factory) { if (typeof define === 'function' && define.amd) { @@ -28,24 +28,28 @@ }); }; - var startDraw = function(planet, canvas, localPlugins, hooks) { + var initPlugins = function(planet, localPlugins) { + // Add the global plugins to the beginning of the local ones for (var i = 0; i < plugins.length; i++) { localPlugins.unshift(plugins[i]); } - if (localPlugins.length == 0 && planetaryjs.plugins.earth) { - planet.loadPlugin(planetaryjs.plugins.earth()); + // Load the default plugins if none have been loaded so far + if (localPlugins.length == 0) { + if (planetaryjs.plugins.earth) + planet.loadPlugin(planetaryjs.plugins.earth()); + if (planetaryjs.plugins.pings) + planet.loadPlugin(planetaryjs.plugins.pings()); } for (var i = 0; i < localPlugins.length; i++) { - var plugin = localPlugins[i][0]; - var config = localPlugins[i][1]; - plugin(planet, config); + localPlugins[i](planet); } + }; - planet.canvas = canvas; - planet.context = canvas.getContext('2d'); - + var runOnInitHooks = function(planet, canvas, hooks) { + // onInit hooks can be asynchronous if they take a parameter; + // iterate through them one at a time if (hooks.onInit.length) { var completed = 0; var doNext = function(callback) { @@ -71,6 +75,15 @@ } }; + var startDraw = function(planet, canvas, localPlugins, hooks) { + initPlugins(planet, localPlugins); + + planet.canvas = canvas; + planet.context = canvas.getContext('2d'); + + runOnInitHooks(planet, canvas, hooks); + }; + var planetaryjs = { plugins: {}, @@ -79,8 +92,8 @@ return planetaryjs; }, - loadPlugin: function(plugin, defaultOptions) { - plugins.push([plugin, defaultOptions || {}]); + loadPlugin: function(plugin) { + plugins.push(plugin); }, planet: function() { @@ -103,8 +116,8 @@ hooks.onDraw.push(fn); }, - loadPlugin: function(plugin, defaultOptions) { - localPlugins.push([plugin, defaultOptions || {}]); + loadPlugin: function(plugin) { + localPlugins.push(plugin); }, withSavedContext: function(fn) { @@ -127,97 +140,154 @@ } }; - planetaryjs.plugins.topojson = function(planet, config) { - planet.onInit(function(done) { - if (config.world) { - planet.world = config.world; - setTimeout(done, 0); - } else { - var file = config.file || 'world-110m.json' - d3.json(file, function(err, world) { - if (err) { - throw new Error("Could not load JSON " + file); - } - planet.world = world; - done(); - }); - } - }) - }; - - planetaryjs.plugins.oceans = function(planet, config) { - planet.onDraw(function() { - planet.withSavedContext(function(context) { - context.beginPath(); - planet.path.context(context)({type: 'Sphere'}); - - context.fillStyle = config.fill || 'black'; - context.fill(); - - if (config.stroke != false) { - context.strokeStyle = config.stroke; - context.stroke(); + planetaryjs.plugins.topojson = function(config) { + return function(planet) { + planet.onInit(function(done) { + if (config.world) { + planet.world = config.world; + setTimeout(done, 0); + } else { + var file = config.file || 'world-110m.json' + d3.json(file, function(err, world) { + if (err) { + throw new Error("Could not load JSON " + file); + } + planet.world = world; + done(); + }); } }); - }); + }; }; - planetaryjs.plugins.land = function(planet, config) { - var land = null; + planetaryjs.plugins.oceans = function(config) { + return function(planet) { + planet.onDraw(function() { + planet.withSavedContext(function(context) { + context.beginPath(); + planet.path.context(context)({type: 'Sphere'}); - planet.onInit(function() { - land = topojson.feature(planet.world, planet.world.objects.land); - }) - - planet.onDraw(function() { - planet.withSavedContext(function(context) { - context.beginPath(); - planet.path.context(context)(land); - - if (config.fill != false) { - context.fillStyle = config.fill || 'white'; + context.fillStyle = config.fill || 'black'; context.fill(); - } - if (config.stroke) { - context.strokeStyle = config.stroke; + if (config.stroke != false) { + context.strokeStyle = config.stroke; + context.stroke(); + } + }); + }); + }; + }; + + planetaryjs.plugins.land = function(config) { + return function(planet) { + var land = null; + + planet.onInit(function() { + land = topojson.feature(planet.world, planet.world.objects.land); + }) + + planet.onDraw(function() { + planet.withSavedContext(function(context) { + context.beginPath(); + planet.path.context(context)(land); + + if (config.fill != false) { + context.fillStyle = config.fill || 'white'; + context.fill(); + } + + if (config.stroke) { + context.strokeStyle = config.stroke; + context.stroke(); + } + }); + }); + }; + }; + + planetaryjs.plugins.borders = function(config) { + return function(planet) { + var borders = null; + planet.onInit(function() { + var countries = planet.world.objects.countries; + borders = topojson.mesh(planet.world, countries, function(a, b) { + return a.id !== b.id; + }); + }); + + planet.onDraw(function() { + planet.withSavedContext(function(context) { + context.beginPath(); + planet.path.context(context)(borders); + context.strokeStyle = config.stroke || 'gray'; context.stroke(); + }); + }); + }; + }; + + planetaryjs.plugins.earth = function(config) { + var config = config || {}; + var topojsonOptions = config.topojson || {}; + var oceanOptions = config.oceans || {}; + var landOptions = config.land || {}; + var bordersOptions = config.borders || {}; + + return function(planet) { + planetaryjs.plugins.topojson(topojsonOptions)(planet); + planetaryjs.plugins.oceans(oceanOptions)(planet); + planetaryjs.plugins.land(landOptions)(planet); + planetaryjs.plugins.borders(bordersOptions)(planet); + }; + }; + + planetaryjs.plugins.pings = function(config) { + var pings = []; + + var addPing = function(lat, lng, options) { + var options = options || {}; + options.color = options.color || 'white'; + options.ttl = options.ttl || 2000; + options.size = options.size || 500; + pings.push({ lat: lat, lng: lng, time: new Date(), options: options }); + }; + + var drawPings = function(planet, context, now) { + var newPings = []; + for (var i = 0; i < pings.length; i++) { + var ping = pings[i]; + var alive = now - ping.time; + if (alive <= ping.options.ttl) { + newPings.push(ping); + drawPing(planet, context, now, ping); } + } + pings = newPings; + }; + + var drawPing = function(planet, context, now, ping) { + var dT = now - ping.time; + var alpha = 1 - (dT / ping.options.ttl); + var color = d3.rgb(ping.options.color); + color = "rgba(" + color.r + "," + color.g + "," + color.b + "," + alpha + ")"; + context.strokeStyle = color; + var circle = d3.geo.circle().origin([ping.lng, ping.lat]) + .angle(dT / ping.options.size)(); + context.beginPath(); + planet.path.context(context)(circle); + context.stroke(); + }; + + return function (planet) { + planet.addPing = addPing; + + planet.onDraw(function() { + var now = new Date(); + planet.withSavedContext(function(context) { + drawPings(planet, context, now); + }); }); - }); - }; - - planetaryjs.plugins.borders = function(planet, config) { - var borders = null; - planet.onInit(function() { - var countries = planet.world.objects.countries; - borders = topojson.mesh(planet.world, countries, function(a, b) { - return a.id !== b.id; - }); - }); - - planet.onDraw(function() { - planet.withSavedContext(function(context) { - context.beginPath(); - planet.path.context(context)(borders); - context.strokeStyle = config.stroke || 'gray'; - context.stroke(); - }); - }); - }; - - planetaryjs.plugins.earth = function(options) { - var options = options || {}; - var topojsonOptions = options.topojson || {}; - var oceanOptions = options.oceans || {}; - var landOptions = options.land || {}; - var bordersOptions = options.borders || {}; - - return function(planet, options) { - planetaryjs.plugins.topojson(planet, topojsonOptions); - planetaryjs.plugins.oceans(planet, oceanOptions); - planetaryjs.plugins.land(planet, landOptions); - planetaryjs.plugins.borders(planet, bordersOptions); }; }; diff --git a/dist/planetaryjs.min.js b/dist/planetaryjs.min.js index 1b52c4e..4d3a9fd 100644 --- a/dist/planetaryjs.min.js +++ b/dist/planetaryjs.min.js @@ -1,2 +1,2 @@ /*! Planetary.js 0.0.0 | (c) 2013 Brandon Tilley | Released under MIT License */ -!function(n,t){"function"==typeof define&&define.amd?define(["d3","topojson"],t):"object"==typeof exports?module.exports=t(require("d3"),require("topojson")):n.planetaryjs=t(n.d3,n.topojson,n)}(this,function(n,t,o){"use strict";var e=null;o&&(e=o.planetaryjs);var i=[],r=function(t,o,e){n.timer(function(){t.context.clearRect(0,0,o.width,o.height);for(var n=0;n=e.onInit.length?r(n,t,e):f(h)};f(h)}else r(n,t,e)},u={plugins:{},noConflict:function(){return o.planetaryjs=e,u},loadPlugin:function(n,t){i.push([n,t||{}])},planet:function(){var t=[],o={onInit:[],onDraw:[]},e={draw:function(n){l(e,n,t,o)},onInit:function(n){o.onInit.push(n)},onDraw:function(n){o.onDraw.push(n)},loadPlugin:function(n,o){t.push([n,o||{}])},withSavedContext:function(n){if(!this.context)throw new Error("No canvas to fetch context for");this.context.save(),n(this.context),this.context.restore()}};return e.projection=n.geo.orthographic().clipAngle(90).precision(0),e.path=n.geo.path().projection(e.projection),e}};return u.plugins.topojson=function(t,o){t.onInit(function(e){if(o.world)t.world=o.world,setTimeout(e,0);else{var i=o.file||"world-110m.json";n.json(i,function(n,o){if(n)throw new Error("Could not load JSON "+i);t.world=o,e()})}})},u.plugins.oceans=function(n,t){n.onDraw(function(){n.withSavedContext(function(o){o.beginPath(),n.path.context(o)({type:"Sphere"}),o.fillStyle=t.fill||"black",o.fill(),0!=t.stroke&&(o.strokeStyle=t.stroke,o.stroke())})})},u.plugins.land=function(n,o){var e=null;n.onInit(function(){e=t.feature(n.world,n.world.objects.land)}),n.onDraw(function(){n.withSavedContext(function(t){t.beginPath(),n.path.context(t)(e),0!=o.fill&&(t.fillStyle=o.fill||"white",t.fill()),o.stroke&&(t.strokeStyle=o.stroke,t.stroke())})})},u.plugins.borders=function(n,o){var e=null;n.onInit(function(){var o=n.world.objects.countries;e=t.mesh(n.world,o,function(n,t){return n.id!==t.id})}),n.onDraw(function(){n.withSavedContext(function(t){t.beginPath(),n.path.context(t)(e),t.strokeStyle=o.stroke||"gray",t.stroke()})})},u.plugins.earth=function(n){var n=n||{},t=n.topojson||{},o=n.oceans||{},e=n.land||{},i=n.borders||{};return function(n){u.plugins.topojson(n,t),u.plugins.oceans(n,o),u.plugins.land(n,e),u.plugins.borders(n,i)}},u}); \ No newline at end of file +!function(n,t){"function"==typeof define&&define.amd?define(["d3","topojson"],t):"object"==typeof exports?module.exports=t(require("d3"),require("topojson")):n.planetaryjs=t(n.d3,n.topojson,n)}(this,function(n,t,o){"use strict";var e=null;o&&(e=o.planetaryjs);var i=[],r=function(t,o,e){n.timer(function(){t.context.clearRect(0,0,o.width,o.height);for(var n=0;n=o.onInit.length?r(n,t,o):i(l)};i(l)}else r(n,t,o)},a=function(n,t,o,e){l(n,o),n.canvas=t,n.context=t.getContext("2d"),u(n,t,e)},s={plugins:{},noConflict:function(){return o.planetaryjs=e,s},loadPlugin:function(n){i.push(n)},planet:function(){var t=[],o={onInit:[],onDraw:[]},e={draw:function(n){a(e,n,t,o)},onInit:function(n){o.onInit.push(n)},onDraw:function(n){o.onDraw.push(n)},loadPlugin:function(n){t.push(n)},withSavedContext:function(n){if(!this.context)throw new Error("No canvas to fetch context for");this.context.save(),n(this.context),this.context.restore()}};return e.projection=n.geo.orthographic().clipAngle(90).precision(0),e.path=n.geo.path().projection(e.projection),e}};return s.plugins.topojson=function(t){return function(o){o.onInit(function(e){if(t.world)o.world=t.world,setTimeout(e,0);else{var i=t.file||"world-110m.json";n.json(i,function(n,t){if(n)throw new Error("Could not load JSON "+i);o.world=t,e()})}})}},s.plugins.oceans=function(n){return function(t){t.onDraw(function(){t.withSavedContext(function(o){o.beginPath(),t.path.context(o)({type:"Sphere"}),o.fillStyle=n.fill||"black",o.fill(),0!=n.stroke&&(o.strokeStyle=n.stroke,o.stroke())})})}},s.plugins.land=function(n){return function(o){var e=null;o.onInit(function(){e=t.feature(o.world,o.world.objects.land)}),o.onDraw(function(){o.withSavedContext(function(t){t.beginPath(),o.path.context(t)(e),0!=n.fill&&(t.fillStyle=n.fill||"white",t.fill()),n.stroke&&(t.strokeStyle=n.stroke,t.stroke())})})}},s.plugins.borders=function(n){return function(o){var e=null;o.onInit(function(){var n=o.world.objects.countries;e=t.mesh(o.world,n,function(n,t){return n.id!==t.id})}),o.onDraw(function(){o.withSavedContext(function(t){t.beginPath(),o.path.context(t)(e),t.strokeStyle=n.stroke||"gray",t.stroke()})})}},s.plugins.earth=function(n){var n=n||{},t=n.topojson||{},o=n.oceans||{},e=n.land||{},i=n.borders||{};return function(n){s.plugins.topojson(t)(n),s.plugins.oceans(o)(n),s.plugins.land(e)(n),s.plugins.borders(i)(n)}},s.plugins.pings=function(){var t=[],o=function(n,o,e){var e=e||{};e.color=e.color||"white",e.ttl=e.ttl||2e3,e.size=e.size||500,t.push({lat:n,lng:o,time:new Date,options:e})},e=function(n,o,e){for(var r=[],l=0;l