earthjs
Version:
D3 Earth JS using SVG, Canvas & THREE js, build with some plugins.
171 lines (164 loc) • 6.07 kB
JavaScript
export default (worldUrl, flexbox='.ej-flexbox') => {
/*eslint no-console: 0 */
const _ = {
q: null,
svg:null,
world: null,
land: null,
onCountry: {},
onCountryVals: [],
selectedCountry: null,
lakes: {type: 'FeatureCollection', features:[]},
selected: {type: 'FeatureCollection', features:[]},
countries: {type: 'FeatureCollection', features:[]},
};
const $ = {};
_.mapTooltip = d3.select('body').append('div').attr('class', 'ej-country-tooltip');
function init() {
_.svg = this._.svg;
const {width, height} = this._.options;
const scale = width/6.279;
_.zoom = d3.zoom().on('zoom', () => $.g.attr('transform', d3.event.transform));
_.proj = d3.geoEquirectangular().scale(scale).translate([width/2, height/2]);
_.path = d3.geoPath().projection(_.proj).context(_.context);
_.svg.call(_.zoom);
}
function show(data, tooltip) {
const props = data.properties;
const title = Object.keys(props).map(k => k+': '+props[k]).join('<br/>');
return tooltip.html(title)
}
function create() {
const _this = this;
const klas = _.me.name;
_.flexBox = d3.selectAll(flexbox);
_.svg.selectAll(`.countries.${klas}`).remove();
if (this._.options.showMap) {
$.g = _.svg.append('g').attr('class',`countries ${klas}`);
$.countries = $.g.selectAll('path')
.data(_.countries.features).enter().append('path')
.attr('class', d => `cid-${d.properties.cid}`)
.attr('id', d => `x${d.id}`);
$.countries
.on('click', function(d) {
const cid = d.properties.cid;
$.countries.classed('selected', false);
if (_this.choroplethCsv) {
let oscale = -1;
const v = _this.choroplethCsv.colorScale();
const vscale = v.scale(d.properties.value);
if (_.selectedCountry) {
oscale = v.scale(_.selectedCountry.properties.value);
}
if (oscale!==vscale || _.selectedCountry===d) {
_this.choroplethCsv.setSelectedColor(vscale-1);
}
_this.choroplethCsv.cid(cid);
d3.selectAll(`.color-countries-item`).classed('selected', false);
d3.selectAll(`.color-countries-item.cid-${cid}`).classed('selected', true);
}
if (_.selectedCountry!==d) {
_.selectedCountry = d;
$.countries.filter(`#x${d.id}`).classed('selected', true);
} else {
_.selectedCountry = null;
}
_.onCountryVals.forEach(v => {
v.call(this, d3.event, d);
});
})
.on('mouseover', function(data) {
const {pageX, pageY} = d3.event;
(_.me.show || show)(data, _.mapTooltip)
.style('display', 'block')
.style('left', (pageX + 7) + 'px')
.style('top', (pageY - 15) + 'px');
_.flexBox.style('display', 'flex');
})
.on('mouseout', function(data) {
if (_.me.hide) {
_.me.hide(data, _.mapTooltip);
}
_.mapTooltip.style('display', 'none');
if (_.selectedCountry===null) {
_.flexBox.style('display', 'none');
}
})
.on('mousemove', function() {
const {pageX, pageY} = d3.event;
_.mapTooltip
.style('left', (pageX + 7) + 'px')
.style('top', (pageY - 15) + 'px')
});
refresh.call(this);
}
}
function refresh() {
const __ = this._;
if (__.options.showMap) {
$.countries.attr('d', _.path);
}
}
return {
name: 'mapSvg',
urls: worldUrl && [worldUrl],
onReady(err, data) {
_.me.data(data);
},
onInit(me) {
_.me = me;
const __ = this._;
const options = __.options;
options.showMap = true;
init.call(this);
},
onCreate() {
if (this.worldJson && !_.world) {
_.me.allData(this.worldJson.allData());
}
create.call(this);
},
onRefresh() {
refresh.call(this);
},
onCountry(obj) {
Object.assign(_.onCountry, obj);
_.onCountryVals = Object.keys(_.onCountry).map(k => _.onCountry[k]);
},
selectedCountry() {
return _.selectedCountry;
},
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(all) {
if (all) {
_.world = all.world;
_.land = all.land;
_.lakes = all.lakes;
_.countries = all.countries;
} else {
const {world, land, lakes, countries} = _;
return {world, land, lakes, countries};
}
},
selectAll(q) {
if (q) {
_.q = q;
_.svg = d3.selectAll(q);
}
return _.svg;
},
resetZoom() {
_.svg.call(_.zoom.transform, d3.zoomIdentity);
}
}
}