UNPKG

earthjs

Version:

D3 Earth JS using SVG, Canvas & THREE js, build with some plugins.

1,575 lines (1,463 loc) 262 kB
var earthjs = (function () { 'use strict'; // Version 0.0.0. Copyright 2017 Mike Bostock. var versorFn = (function () { var acos = Math.acos, asin = Math.asin, atan2 = Math.atan2, cos = Math.cos, max = Math.max, min = Math.min, PI = Math.PI, sin = Math.sin, sqrt = Math.sqrt, radians = PI / 180, degrees = 180 / PI; // Returns the unit quaternion for the given Euler rotation angles [λ, φ, γ]. function versor(e) { var l = e[0] / 2 * radians, sl = sin(l), cl = cos(l), // λ / 2 p = e[1] / 2 * radians, sp = sin(p), cp = cos(p), // φ / 2 g = e[2] / 2 * radians, sg = sin(g), cg = cos(g); // γ / 2 return [cl * cp * cg + sl * sp * sg, sl * cp * cg - cl * sp * sg, cl * sp * cg + sl * cp * sg, cl * cp * sg - sl * sp * cg]; } // Returns Cartesian coordinates [x, y, z] given spherical coordinates [λ, φ]. versor.cartesian = function (e) { var l = e[0] * radians, p = e[1] * radians, cp = cos(p); return [cp * cos(l), cp * sin(l), sin(p)]; }; // Returns the Euler rotation angles [λ, φ, γ] for the given quaternion. versor.rotation = function (q) { return [atan2(2 * (q[0] * q[1] + q[2] * q[3]), 1 - 2 * (q[1] * q[1] + q[2] * q[2])) * degrees, asin(max(-1, min(1, 2 * (q[0] * q[2] - q[3] * q[1])))) * degrees, atan2(2 * (q[0] * q[3] + q[1] * q[2]), 1 - 2 * (q[2] * q[2] + q[3] * q[3])) * degrees]; }; // Returns the quaternion to rotate between two cartesian points on the sphere. versor.delta = function (v0, v1) { var w = cross(v0, v1), l = sqrt(dot(w, w)); if (!l) return [1, 0, 0, 0]; var t = acos(max(-1, min(1, dot(v0, v1)))) / 2, s = sin(t); // t = θ / 2 return [cos(t), w[2] / l * s, -w[1] / l * s, w[0] / l * s]; }; // Returns the quaternion that represents q0 * q1. versor.multiply = function (q0, q1) { return [q0[0] * q1[0] - q0[1] * q1[1] - q0[2] * q1[2] - q0[3] * q1[3], q0[0] * q1[1] + q0[1] * q1[0] + q0[2] * q1[3] - q0[3] * q1[2], q0[0] * q1[2] - q0[1] * q1[3] + q0[2] * q1[0] + q0[3] * q1[1], q0[0] * q1[3] + q0[1] * q1[2] - q0[2] * q1[1] + q0[3] * q1[0]]; }; function cross(v0, v1) { return [v0[1] * v1[2] - v0[2] * v1[1], v0[2] * v1[0] - v0[0] * v1[2], v0[0] * v1[1] - v0[1] * v1[0]]; } function dot(v0, v1) { return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; } return versor; }); var versor = versorFn(); var earthjs$2 = function earthjs() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; /*eslint no-console: 0 */ cancelAnimationFrame(earthjs.ticker); options = Object.assign({ svgCanvasSelector: '.ej-svg,.ej-canvas', selector: '#earth-js', rotate: [130, -33, -11], transparent: false, map: false, padding: 0 }, options); var _ = { onCreate: {}, onCreateCall: 0, onCreateVals: [], onRefresh: {}, onRefreshVals: [], onResize: {}, onResizeVals: [], onInterval: {}, onIntervalVals: [], onTween: {}, onTweenVals: [], ready: null, plugins: [], promeses: [], loadingData: null, recreateSvgOrCanvas: function recreateSvgOrCanvas(allPlugins) { if (allPlugins) { globe.__plugins().forEach(function (g) { g.__on__.onCreate.call(globe); }); } else { _.onCreateVals.forEach(function (fn) { fn.call(globe); }); } if (_.onCreateCall === 0) { var plugins = Object.keys(_.onCreate).map(function (s) { return globe[s]; }).filter(function (g) { return g.__name__.match(/^((?!threejs).)*$/i); }); _.onCreate = {}; plugins.forEach(function (g) { return _.onCreate[g.name] = g.__on__.onCreate; }); _.onCreateVals = Object.keys(_.onCreate).map(function (k) { return _.onCreate[k]; }); } _.onCreateCall++; return globe; } }; window._ = _; var drag = false; var svg = d3.selectAll(options.selector); var width = +svg.attr('width'), height = +svg.attr('height'); if (!width || !height) { width = options.width || 700; height = options.height || 500; svg.attr('width', width).attr('height', height); } d3.selectAll(options.svgCanvasSelector).attr('width', width).attr('height', height); var center = [width / 2, height / 2]; Object.defineProperty(options, 'width', { get: function get() { return width; }, set: function set(x) { width = x; center[0] = x / 2; } }); Object.defineProperty(options, 'height', { get: function get() { return height; }, set: function set(x) { height = x; center[1] = x / 2; } }); var globe = { _: { svg: svg, drag: drag, versor: versor, center: center, options: options }, $slc: {}, ready: function ready(fn) { if (fn) { globe._.readyFn = fn; globe._.promeses = _.promeses; if (_.promeses.length > 0) { var q = d3.queue(); _.loadingData = true; _.promeses.forEach(function (obj) { obj.urls.forEach(function (url) { var ext = url.split('.').pop(); if (ext === 'geojson') { ext = 'json'; } q.defer(d3[ext], url); }); }); q.await(function () { var args = [].slice.call(arguments); var err = args.shift(); _.promeses.forEach(function (obj) { var ln = obj.urls.length; var ar = args.slice(0, ln); var ready = globe[obj.name].ready; ar.unshift(err); if (ready) { ready.apply(globe, ar); } else { obj.onReady.apply(globe, ar); } args = args.slice(ln); }); _.loadingData = false; fn.called = true; fn.call(globe); }); } } else if (arguments.length === 0) { return _.loadingData; } }, register: function register(obj, name) { var ar = { name: name || obj.name, __name__: obj.name, __on__: {} }; _.plugins.push(ar); globe[ar.name] = ar; Object.keys(obj).forEach(function (fn) { if (['urls', 'onReady', 'onInit', 'onTween', 'onCreate', 'onResize', 'onRefresh', 'onInterval'].indexOf(fn) === -1) { if (typeof obj[fn] === 'function') { ar[fn] = function () { return obj[fn].apply(globe, arguments); }; } } }); if (obj.onInit) { obj.onInit.call(globe, ar); } qEvent(obj, 'onTween', ar.name); qEvent(obj, 'onCreate', ar.name); qEvent(obj, 'onResize', ar.name); qEvent(obj, 'onRefresh', ar.name); qEvent(obj, 'onInterval', ar.name); if (obj.urls && obj.onReady) { _.promeses.push({ name: ar.name, urls: obj.urls, onReady: obj.onReady }); } return globe; } }; Object.defineProperty(globe, 'loading', { get: function get() { return _.loadingData; } }); //---------------------------------------- var earths = []; var ticker = null; var __ = globe._; globe.create = function (twinEarth) { var allPlugins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; earths = twinEarth || []; _.recreateSvgOrCanvas(allPlugins); earths.forEach(function (p) { p.create(null); }); if (ticker === null && earths !== []) { __.ticker(); } return globe; }; globe.$slc.defs = __.svg.append('defs'); __.ticker = function (intervalTicker) { var interval = __.interval; intervalTicker = intervalTicker || 10; var l1 = void 0, start1 = 0, p = void 0; var l2 = void 0, start2 = 0, fn = void 0; function step(timestamp) { if (timestamp - start1 > intervalTicker) { start1 = timestamp; if (!_.loadingData) { interval.call(globe, timestamp); if (timestamp - start2 > intervalTicker + 30) { start2 = timestamp; l2 = l1 = earths.length; while (l1) { p = earthjs[l2 - l1]; p._.interval.call(p, timestamp); l1--; } } } } l2 = l1 = _.onTweenVals.length; while (l1) { fn = _.onTweenVals[l2 - l1]; fn && fn.call(globe, timestamp); // length can changed! l1--; } earthjs.ticker = requestAnimationFrame(step); } earthjs.ticker = requestAnimationFrame(step); return globe; }; //---------------------------------------- // Helper __.scale = function (y) { __.proj.scale(y); __.resize(); __.refresh(); return globe; }; __.rotate = function (r) { __.proj.rotate(r); __.refresh(); return globe; }; __.interval = function (t) { var l = _.onIntervalVals.length; while (l--) { _.onIntervalVals[l].call(globe, t); } return globe; }; __.refresh = function (filter) { var l2 = void 0, l1 = void 0; if (filter) { var keys = filter ? _.onRefreshKeys.filter(function (d) { return filter.test(d); }) : _.onRefreshKeys; keys.forEach(function (fn) { _.onRefresh[fn].call(globe); }); } else { l2 = l1 = _.onRefreshVals.length; while (l1) { _.onRefreshVals[l2 - l1].call(globe); l1--; } } return globe; }; __.resize = function () { var l2 = void 0, l1 = void 0; l2 = l1 = _.onResizeVals.length; while (l1) { _.onResizeVals[l2 - l1].call(globe); l1--; } return globe; }; __.projection = function () { var _$options = __.options, scale = _$options.scale, width = _$options.width, height = _$options.height, padding = _$options.padding; if (__.options.map) { if (!scale) { scale = width / 6.279 - padding; } return d3.geoEquirectangular().translate(__.center).precision(0.1).scale(scale); } else { if (!scale) { var mins = d3.min([width, height]); scale = mins / 2 - padding; } var r = __.options.rotate; if (typeof r === 'number') { __.options.rotate = [r, -33, -11]; } return d3.geoOrthographic().rotate(__.options.rotate).translate(__.center).precision(0.1).clipAngle(90).scale(scale); } }; __.proj = __.projection(); __.path = d3.geoPath().projection(__.proj); globe.__addEventQueue = function (name, qname) { var obj = globe[name].__on__; if (qname) { AddQueueEvent(obj, qname, name); } else { obj && Object.keys(obj).forEach(function (qname) { return AddQueueEvent(obj, qname, name); }); } }; globe.__removeEventQueue = function (name, qname) { var obj = globe[name].__on__; if (obj) { if (qname) { delete _[qname][name]; _[qname + 'Keys'] = Object.keys(_[qname]); _[qname + 'Vals'] = _[qname + 'Keys'].map(function (k) { return _[qname][k]; }); } else { Object.keys(obj).forEach(function (qname) { delete _[qname][name]; _[qname + 'Keys'] = Object.keys(_[qname]); _[qname + 'Vals'] = _[qname + 'Keys'].map(function (k) { return _[qname][k]; }); }); } } }; globe.__plugins = function (filter) { if (filter === undefined) { return _.plugins; } else { return _.plugins.filter(function (obj) { return obj.__name__.match(filter); }); } }; return globe; //---------------------------------------- function AddQueueEvent(obj, qname, name) { _[qname][name] = obj[qname]; _[qname + 'Keys'] = Object.keys(_[qname]); _[qname + 'Vals'] = _[qname + 'Keys'].map(function (k) { return _[qname][k]; }); } function qEvent(obj, qname, name) { if (obj[qname]) { globe[name].__on__[qname] = obj[qname]; AddQueueEvent(obj, qname, name); } } }; if (window.d3 === undefined) { window.d3 = {}; } window.d3.earthjs = earthjs$2; var baseCsv = function () { /*eslint no-console: 0 */ var _ = { data: [] }; var args = arguments; return { name: 'baseCsv', urls: Array.prototype.slice.call(args), onReady: function onReady(err, csv) { _.me.data(csv); }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.data = _data; } else { return _.data; } }, message: function message(fn) { _.data = _.data.map(fn); }, allData: function allData(all) { if (all) { _.data = all.data; } else { var data = _.data; return { data: data }; } }, arrToJson: function arrToJson(k, v) { var json = {}; _.data.forEach(function (x) { return json[x[k]] = x[v]; }); return json; } }; }; var baseGeoJson = (function (jsonUrl) { /*eslint no-console: 0 */ var _ = { data: null }; return { name: 'baseGeoJson', urls: jsonUrl && [jsonUrl], onReady: function onReady(err, json) { _.me.data(json); }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.data = _data; } else { return _.data; } }, message: function message(fn) { _.data = _.data.map(fn); }, allData: function allData(all) { if (all) { _.data = all.data; } else { var data = _.data; return { data: data }; } } }; }); var worldJson = (function (jsonUrl) { /*eslint no-console: 0 */ var _ = { world: null, land: null, lakes: { type: 'FeatureCollection', features: [] }, selected: { type: 'FeatureCollection', features: [] }, countries: { type: 'FeatureCollection', features: [] } }; return { name: 'worldJson', urls: jsonUrl && [jsonUrl], onReady: function onReady(err, json) { _.me.data(json); }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.world = _data; _.land = topojson.feature(_data, _data.objects.land); _.countries.features = topojson.feature(_data, _data.objects.countries).features; if (_data.objects.ne_110m_lakes) _.lakes.features = topojson.feature(_data, _data.objects.ne_110m_lakes).features; } else { return _.world; } }, allData: function allData(all) { if (all) { _.world = all.world; _.land = all.land; _.lakes = all.lakes; _.countries = all.countries; } else { var world = _.world, land = _.land, lakes = _.lakes, countries = _.countries; return { world: world, land: land, lakes: lakes, countries: countries }; } }, countries: function countries(arr) { if (arr) { _.countries.features = arr; } else { return _.countries.features; } } }; }); var world3dJson = function () { // function is required for arguments works /*eslint no-console: 0 */ var _ = { data: {}, nm_to_id: {}, geometries: [] }; var args = arguments; return { name: 'world3dJson', urls: Array.prototype.slice.call(args), onReady: function onReady(err, json, nm_to_id) { _.me.data(json); if (nm_to_id) { _.me.arrayOfGeometry(nm_to_id); } }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.data = _data; } else { return _.data; } }, message: function message(fn) { _.data = _.data.map(fn); }, allData: function allData(all) { if (all) { _.data = all.data; } else { var data = _.data, geometries = _.geometries, nm_to_id = _.nm_to_id; return { data: data, geometries: geometries, nm_to_id: nm_to_id }; } }, arrayOfGeometry: function arrayOfGeometry(data) { var features = []; for (var name in _.data) { var geometry = _.data[name]; var cid = data[name.toUpperCase()]; var properties = { cid: cid }; geometry.properties = properties; features.push({ properties: properties, geometry: geometry }); } _.nm_to_id = data; _.geometries = { features: features }; } }; }; var toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; var choroplethCsv = (function (csvUrl) { var scheme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'schemeReds'; /*eslint no-console: 0 */ var _ = { cid: null, data: null, color: null, oldData: null, selectedColorId: null, selectedCountryId: null, countries: { type: 'FeatureCollection', features: [] } }; function getPath(path) { var v = this; path.split('.').forEach(function (p) { return v = v[p]; }); return v; } function updatePath(path, value) { var o = void 0, k = void 0, v = this; path.split('.').forEach(function (p) { o = v; k = p; v = v[p]; }); o[k] = value; } return { name: 'choroplethCsv', urls: csvUrl && [csvUrl], onReady: function onReady(err, csv) { _.me.data(csv); }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.data = _data; _.oldData = _data; _.data.getPath = getPath; _.data.updatePath = updatePath; } else { return _.data; } }, filter: function filter(fn) { _.data = _.oldData.filter(fn); }, mergeData: function mergeData(json, arr) { var cn = _.data; var id = arr[0].split(':'); var vl = arr[1].split(':'); json.features.forEach(function (obj) { var o = cn.find(function (src) { return getPath.call(obj, id[0]) === getPath.call(src, id[1]); }); if (o) { var v = getPath.call(o, vl[1]); updatePath.call(obj, vl[0], v); } }); }, // https://github.com/d3/d3-scale-chromatic colorize: function colorize(key) { var schemeKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scheme; var opacity = arguments[2]; var value = void 0, colorList = d3[schemeKey][9]; if (arguments.length > 1) { var arr = _.data.map(function (x) { return +x[key]; }); arr = [].concat(toConsumableArray(new Set(arr))); var r = [1, 8]; _.scheme = schemeKey; _.minMax = d3.extent(arr); _.range = d3.range.apply(d3, r); //_.scale(2990000) - 2 _.scale = d3.scaleLinear().domain(_.minMax).rangeRound(r); _.color = d3.scaleThreshold().domain(_.range).range(colorList); _.colorValues = colorList.map(function (color, id) { value = Math.floor(_.scale.invert(id + 1.45)); return { id: id, color: color, value: value, totalValue: 0 }; }); _.data.forEach(function (obj) { var vl = +obj[key]; var id = _.scale(vl); if (opacity === undefined) { obj.color = _.color(id); } else { var color = d3.color(_.color(id)); color.opacity = opacity; obj.color = color + ''; } obj.colorId = id - 1; _.colorValues[obj.colorId].totalValue += vl; }); } return _.colorValues; }, colorScale: function colorScale(value) { var result = void 0; if (value !== undefined) { result = _.color(_.scale(+value)); } else { result = { color: _.color, scale: _.scale, minMax: _.minMax }; } return result; }, setCss: function setCss(target, fl) { var hiden = void 0; if (fl === undefined && _.selectedColorId !== null) { fl = _.selectedColorId; } var texts = _.data.map(function (x) { if (fl === undefined || fl === x.colorId || fl === x.cid) { hiden = 'opacity:1;fill:' + x.color + ';stroke:black'; } else { hiden = ''; } return '.countries path.cid-' + x.cid + ' {' + hiden + ';}'; }); if (target) { _.targetCss = target; } d3.select(_.targetCss).text(texts.join("\n")); }, setColorcountries: function setColorcountries(colorId) { var selector = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'body'; var format = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.1f'; var data = _.me.countries(); var f = d3.format(format); d3.select(selector + ' .color-countries').remove(); var colorCountries = d3.select(selector).append('div').attr('class', 'color-countries'); colorCountries.append('div').attr('class', 'color-countries-title'); var colorList = data.filter(function (x) { var value = x.properties.value; var vscale = _.scale(value); return vscale - 1 === colorId; }); colorList.sort(function (a, b) { return b.properties.value - a.properties.value; }); colorCountries.selectAll('div.color-countries-item').data(colorList).enter().append('div').attr('data-cid', function (d) { return d.properties.cid; }).attr('class', function (d) { var selected = d.properties.cid === _.cid ? 'selected' : ''; return 'color-countries-item cid-' + d.properties.cid + ' ' + selected; }).html(function (d) { var _d$properties = d.properties, cid = _d$properties.cid, name = _d$properties.name, value = _d$properties.value; return name + ': ' + f(value) + ' - ' + (cid ? cid : '&nbsp;-&nbsp;'); }); colorCountries.on('mouseover', function () { _.me.setCss(_.targetCss, d3.event.target.dataset.cid); }).on('mouseout', function () { _.me.setCss(_.targetCss); }); }, setColorRange: function setColorRange() { var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'body'; var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '.1f'; var data = _.me.colorize(); var f = d3.format(format); data.sort(function (a, b) { return b.value - a.value; }); d3.select(selector + ' .color-range').remove(); var colorRange = d3.select(selector).append('div').attr('class', 'color-range'); colorRange.append('div').attr('class', 'color-range-title'); var colorList = data.filter(function (x) { return x.totalValue !== 0; }); _.colorItems = colorRange.selectAll('div.color-range-item').data(colorList).enter().append('div').attr('class', function (d) { return 'color-range-item s-' + d.id; }).style('background', function (d) { return d.color; }).text(function (d) { return f(d.totalValue); }); _.colorItems.on('click', function (data) { _.me.setSelectedColor(data.id); }).on('mouseover', function (data) { _.me.setCss(_.targetCss, data.id); _.me.setColorcountries(data.id); }).on('mouseout', function () { _.me.setCss(_.targetCss); if (_.selectedColorId === null) { _.me.setColorcountries(-2); } else { _.me.setColorcountries(_.selectedColorId); } }); }, setSelectedColor: function setSelectedColor(colorId) { _.colorItems.classed('selected', false); if (_.selectedColorId !== colorId) { _.colorItems.filter('.s-' + colorId).classed('selected', true); } else { colorId = null; } _.selectedColorId = colorId; _.me.setColorcountries(colorId); _.me.setCss(_.targetCss); }, countries: function countries(arr) { if (arr) { _.countries.features = arr; } else { return _.countries.features; } }, cid: function cid(id) { _.cid = id; } }; }); var countryNamesCsv = (function (csvUrl) { /*eslint no-console: 0 */ var _ = { countryNames: null }; return { name: 'countryNamesCsv', urls: csvUrl && [csvUrl], onReady: function onReady(err, csv) { _.me.data(csv); }, onInit: function onInit(me) { _.me = me; }, data: function data(_data) { if (_data) { _.countryNames = _data; } else { return _.countryNames; } }, mergeData: function mergeData(json, arr) { var cn = _.countryNames; var id = arr[0].split(':'); var vl = arr[1].split(':'); json.features.forEach(function (obj) { var o = cn.find(function (x) { return '' + obj[id[0]] === x[id[1]]; }); if (o) { obj[vl[0]] = o[vl[1]]; } }); } }; }); var colorScale = (function (data) { var _colorRange = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [d3.rgb('#FFAAFF'), d3.rgb("#FF0000")]; /*eslint no-console: 0 */ var _ = {}; return { name: 'colorScale', onInit: function onInit(me) { _.me = me; _.me.data(data); }, data: function data(_data) { _.mnMax = d3.extent(_data); _.color = d3.scaleLinear().domain(_.mnMax).interpolate(d3.interpolateHcl).range(_colorRange); }, color: function color(value) { return _.color(value); }, colors: function colors(arr) { return arr.map(function (x) { return _.color(x); }); }, colorScale: function colorScale(length) { var ttl = 0; var arr = [[0, _.me.color(0)]]; var max = _.mnMax[1] / length; for (var i = 0; i < length; i++) { ttl += max; arr.push([ttl, _.me.color(ttl)]); } return arr; }, colorRange: function colorRange(cRange) { if (cRange) { _colorRange = cRange; } else { return _colorRange; } } }; }); // http://bl.ocks.org/syntagmatic/6645345 var dotRegion = (function (jsonUrl) { var radius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1.5; // /*eslint no-console: 0 */ var _ = { recreate: true }; function rgb2num(str) { return str.split(',').reduce(function (i, n) { return +i * 256 + +n; }); } function num2rgb(num) { var d = num % 256; for (var i = 2; i > 0; i--) { num = Math.floor(num / 256); d = num % 256 + ',' + d; } return d; } function init() { var width = 1600; var height = 800; var center = [width / 2, height / 2]; _.canvas = d3.select('body').append('canvas').attr('class', 'ej-hidden').attr('width', width).attr('height', height).node(); _.context = _.canvas.getContext('2d'); _.proj = d3.geoEquirectangular().translate(center).scale(center[1] / 1.2); _.path = d3.geoPath().projection(_.proj).context(_.context); } function create() { if (_.recreate) { _.recreate = false; _.context.clearRect(0, 0, 1024, 512); var arr = _.dataDots.features; for (var i = 0; i < arr.length; i++) { _.context.beginPath(); // _.path(arr[i]); var xy = _.proj(arr[i].geometry.coordinates); _.context.arc(xy[0], xy[1], radius, 0, 2 * Math.PI); _.context.fillStyle = 'rgb(' + num2rgb(i + 2) + ')'; _.context.fill(); } } } return { name: 'dotRegion', urls: jsonUrl && [jsonUrl], onReady: function onReady(err, data) { _.me.data(data); }, onInit: function onInit(me) { _.me = me; init.call(this); }, onCreate: function onCreate() { create.call(this); }, data: function data(_data) { if (_data) { _.dataDots = _data; } else { return _.dataDots; } }, detect: function detect(latlong) { // g._.proj.invert(mouse); var hiddenPos = _.proj(latlong); if (hiddenPos[0] > 0) { var p = _.context.getImageData(hiddenPos[0], hiddenPos[1], 1, 1).data; var d = _.dataDots.features[rgb2num(p.slice(0, 3).join(',')) - 2]; if (d) { var coordinates = d.geometry.coordinates; if (Math.floor(coordinates[0]) === Math.floor(latlong[0]) && Math.floor(coordinates[1]) === Math.floor(latlong[1])) { // console.log(latlong, coordinates); return d; } } } } }; }); var zoomPlugin = (function () { /*eslint no-console: 0 */ var _ = {}; function init() { var __ = this._; var s0 = __.proj.scale(); var wh = [__.options.width, __.options.height]; __.svg.call(d3.zoom().on('zoom start end', zoom).scaleExtent([0.1, 5]).translateExtent([[0, 0], wh])); function zoom() { var t = d3.event.transform; __.proj.scale(s0 * t.k); __.resize(); __.refresh(); } } return { name: 'zoomPlugin', onInit: function onInit(me) { _.me = me; init.call(this); } }; }); // KoGor’s Block http://bl.ocks.org/KoGor/5994804 var hoverCanvas = (function () { /*eslint no-console: 0 */ var _ = { svg: null, mouse: null, country: null, ocountry: null, countries: null, hoverHandler: null, onCircle: {}, onCircleVals: [], onCountry: {}, onCountryVals: [] }; function init() { if (this.worldCanvas) { var world = this.worldCanvas.data(); if (world) { _.world = world; _.countries = topojson.feature(world, world.objects.countries); } } var __ = this._; var _this = this; _.hoverHandler = function (event, mouse) { var _this2 = this; if (__.drag || !event) { return; } if (event.sourceEvent) { event = event.sourceEvent; } var xmouse = [event.clientX, event.clientY]; var pos = __.proj.invert(mouse); _.pos = pos; _.dot = null; _.mouse = xmouse; _.country = null; if (__.options.showDots) { _.onCircleVals.forEach(function (v) { _.dot = v.call(_this2, event, pos); }); } if (__.options.showLand && _.countries && !_.dot) { if (!__.drag) { if (_this.countryCanvas) { _.country = _this.countryCanvas.detectCountry(pos); } else { _.country = findCountry(pos); } if (_.ocountry !== _.country && _this.canvasThreejs) { _.ocountry = _.country; _this.canvasThreejs.refresh(); } } _.onCountryVals.forEach(function (v) { if (v.tooltips) { v.call(_this2, event, _.country); } else if (_.ocountry2 !== _.country) { v.call(_this2, event, _.country); } }); _.ocountry2 = _.country; } }; _.svg.on('mousemove', function () { _.hoverHandler.call(this, d3.event, d3.mouse(this)); }); } function findCountry(pos) { return _.countries.features.find(function (f) { return f.geometry.coordinates.find(function (c1) { return d3.polygonContains(c1, pos) || c1.find(function (c2) { return d3.polygonContains(c2, pos); }); }); }); } return { name: 'hoverCanvas', onInit: function onInit(me) { _.me = me; _.svg = this._.svg; // need to be call once as init() used in 2 places this._.options.showSelectedCountry = false; init.call(this); }, selectAll: function selectAll(q) { if (q) { _.q = q; _.svg.on('mousemove', null); _.svg = d3.selectAll(q); init.call(this); } return _.svg; }, onCreate: function onCreate() { if (this.worldJson && !_.world) { _.me.data(this.worldJson.data()); } }, onCircle: function onCircle(obj) { Object.assign(_.onCircle, obj); _.onCircleVals = Object.keys(_.onCircle).map(function (k) { return _.onCircle[k]; }); }, onCountry: function onCountry(obj) { Object.assign(_.onCountry, obj); _.onCountryVals = Object.keys(_.onCountry).map(function (k) { return _.onCountry[k]; }); }, data: function data(_data) { if (_data) { _.world = _data; _.countries = topojson.feature(_data, _data.objects.countries); } else { return _.world; } }, allData: function allData(all) { if (all) { _.world = all.world; _.countries = all.countries; } else { var world = _.world, countries = _.countries; return { world: world, countries: countries }; } }, states: function states() { return { pos: _.pos, dot: _.dot, mouse: _.mouse, country: _.country }; } }; }); // KoGor’s Block http://bl.ocks.org/KoGor/5994804 var clickCanvas = (function () { /*eslint no-console: 0 */ var _ = { mouse: null, country: null, countries: null, onCircle: {}, onCircleVals: [], onCountry: {}, onCountryVals: [] }; function init() { if (this.worldCanvas) { var world = this.worldCanvas.data(); if (world) { _.world = world; _.countries = topojson.feature(world, world.objects.countries); } } var __ = this._; var _this = this; var mouseClickHandler = function mouseClickHandler(event, mouse) { var _this2 = this; if (!event) { return; } if (event.sourceEvent) { event = event.sourceEvent; } var xmouse = [event.clientX, event.clientY]; var pos = __.proj.invert(mouse); _.pos = pos; _.dot = null; _.mouse = xmouse; _.country = null; if (__.options.showDots) { _.onCircleVals.forEach(function (v) { _.dot = v.call(_this2, event, pos); }); } if (__.options.showLand && !_.dot) { if (!__.drag) { if (_this.countryCanvas) { _.country = _this.countryCanvas.detectCountry(pos); } else { _.country = findCountry(pos); } } _.onCountryVals.forEach(function (v) { v.call(_this2, event, _.country); }); } }; var clickPlugin = this.mousePlugin || this.inertiaPlugin; if (clickPlugin) { clickPlugin.onClick({ clickCanvas: mouseClickHandler }); } __.options.showLand = true; } function findCountry(pos) { return _.countries.features.find(function (f) { return f.geometry.coordinates.find(function (c1) { return d3.polygonContains(c1, pos) || c1.find(function (c2) { return d3.polygonContains(c2, pos); }); }); }); } return { name: 'clickCanvas', onInit: function onInit(me) { _.me = me; init.call(this); }, onCreate: function onCreate() { if (this.worldJson && !_.world) { _.me.data(this.worldJson.data()); } }, onCircle: function onCircle(obj) { Object.assign(_.onCircle, obj); _.onCircleVals = Object.keys(_.onCircle).map(function (k) { return _.onCircle[k]; }); }, onCountry: function onCountry(obj) { Object.assign(_.onCountry, obj); _.onCountryVals = Object.keys(_.onCountry).map(function (k) { return _.onCountry[k]; }); }, data: function data(_data) { if (_data) { _.world = _data; _.countries = topojson.feature(_data, _data.objects.countries); } else { return _.world; } }, allData: function allData(all) { if (all) { _.world = all.world; _.countries = all.countries; } else { var world = _.world, countries = _.countries; return { world: world, countries: countries }; } }, state: function state() { return { pos: _.pos, dot: _.dot, mouse: _.mouse, country: _.country }; } }; }); // Mike Bostock’s Block https://bl.ocks.org/mbostock/7ea1dde508cec6d2d95306f92642bc42 var mousePlugin = (function () { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { zoomScale: [0, 50000] }, zoomScale = _ref.zoomScale, intervalDrag = _ref.intervalDrag; /*eslint no-console: 0 */ var _ = { svg: null, wait: null, zoom: null, mouse: null, q: null, sync: [], onDrag: {}, onDragVals: [], onDragStart: {}, onDragStartVals: [], onDragEnd: {}, onDragEndVals: [], onClick: {}, onClickVals: [], onDblClick: {}, onDblClickVals: [] }; window._mouse = _; if (zoomScale === undefined) { zoomScale = [0, 50000]; } function onclick() { _.onClickVals.forEach(function (v) { v.call(_._this, _.event, _.mouse); }); } function ondblclick() { _.onDblClickVals.forEach(function (v) { v.call(_._this, _.event, _.mouse); }); } var v0 = void 0, // Mouse position in Cartesian coordinates at start of drag gesture. r0 = void 0, // Projection rotation as Euler angles at start. q0 = void 0; // Projection rotation as versor at start. function r(__) { var versor = __.versor; var v1 = versor.cartesian(__.proj.rotate(r0).invert(_.mouse)), q1 = versor.multiply(q0, versor.delta(v0, v1)); _.r = versor.rotation(q1); } function drag(__) { var _this = this; r(__); __.rotate(_.r); _.onDragVals.forEach(function (v) { v.call(_this, _.event, _.mouse); }); } function init() { var __ = this._; var versor = __.versor; var s0 = __.proj.scale(); var wh = [__.options.width, __.options.height]; _.scale = d3.scaleLinear().domain([30, __.proj.scale()]).range([0.1, 1]); _.svg.call(d3.drag().on('start', onStartDrag).on('drag', onDragging).on('end', onEndDrag)); _.zoom = d3.zoom().on('zoom', zoom).scaleExtent([0.1, 160]).translateExtent([[0, 0], wh]).filter(function () { var _d3$event = d3.event, touches = _d3$event.touches, type = _d3$event.type; return type === 'wheel' || touches; }); _.svg.call(_.zoom); // todo: add zoom lifecycle to optimize plugins zoom-able // ex: barTooltipSvg, at the end of zoom, need to recreate function zoom() { var z = zoomScale; var r1 = s0 * d3.event.transform.k; if (r1 >= z[0] && r1 <= z[1]) { __.scale(r1); _.sync.forEach(function (g) { return g._.scale(r1); }); } } function rotate(r) { var d = r[0] - r0[0]; r[0] = d + this._.proj.rotate()[0]; if (r[0] >= 180) r[0] -= 360; this._.rotate(r); } function onStartDrag() { var _this2 = this; var mouse = d3.mouse(this); v0 = versor.cartesian(__.proj.invert(mouse)); r0 = __.proj.rotate(); q0 = versor(r0); __.drag = null; _.onDragStartVals.forEach(function (v) { return v.call(_this2, _.event, mouse); }); _.onDragVals.forEach(function (v) { return v.call(_this2, _.event, mouse); }); __.refresh(); _.mouse = mouse; _._this = this; _.t1 = 0; _.t2 = 0; } function onDragging() { // DOM update must be onInterval! __.drag = true; _._this = this; _.mouse = d3.mouse(this); !intervalDrag && drag(__); // _.t1+=1; // twice call compare to onInterval } function onEndDrag() { var _this3 = this; var drag = __.drag; __.drag = false; if (drag === null) { _.event = d3.event; if (__.options.spin) { onclick(); } else if (_.wait) { _.wait = null; ondblclick(); } else if (_.wait === null) { _.wait = setTimeout(function () { if (_.wait) { _.wait = false; } }, 250); } } else if (drag) { r(__); __.rotate(_.r); _.onDragVals.forEach(function (v) { return v.call(_._this, _.event, _.mouse); }); _.sync.forEach(function (g) { return rotate.call(g, _.r); }); } _.onDragEndVals.forEach(function (v) { return v.call(_this3, _.event, _.mouse); }); __.refresh(); // console.log('ttl:',_.t1,_.t2); } } function interval() { var __ = this._; if (__.drag && intervalDrag) { if (_.oMouse[0] !== _.mouse[0] && _.oMouse[1] !== _.mouse[1]) { _.oMouse = _.mouse; drag(__); // _.t2+=1; } } else if (_.wait === false) { _.wait = null; onclick(); } } return { name: 'mousePlugin', onInit: function onInit(me) { _.me = me; _.oMouse = []; _.svg = this._.svg; init.call(this); }, onInterval: function onInterval() { interval.call(this); }, selectAll: function selectAll(q) { if (q) { _.q = q; _.svg.call(d3.drag().on('start', null).on('drag', null).on('end', null)); _.svg.call(d3.zoom().on('zoom', null)); _.svg = d3.selectAll(q); init.call(this); if (this.hoverCanvas) { this.hoverCanvas.selectAll(q); } } return _.svg; }, sync: function sync(arr) {