earthjs
Version:
D3 Earth JS using SVG, Canvas & THREE js, build with some plugins.
1,575 lines (1,463 loc) • 262 kB
JavaScript
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 : ' - ');
});
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) {