UNPKG

earthjs

Version:

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

237 lines (225 loc) 7.75 kB
// http://davidscottlyons.com/threejs/presentations/frontporch14/offline-extended.html#slide-79 export default (worldUrl, scw=6.279, height=2048) => { /*eslint no-console: 0 */ const _ = { world: null, sphereObject:null, onHover: {}, onHoverVals: [], style: {}, onDraw: {}, onDrawVals: [], countries: {type: 'FeatureCollection', features:[]}, selected: {type: 'FeatureCollection', features:[]}, material: new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, transparent: true, alphaTest: 0.5 }) }; function init() { const r = this._.proj.scale() + (this.__plugins('3d').length>0 ? 4 : 0); _.geometry = new THREE.SphereGeometry(r, 30, 30); _.newCanvas = d3.select('body').append('canvas') // document.createElement('canvas'); .style('display','none') .attr('class','ej-canvas-new') .node(); _.newContext = _.newCanvas.getContext('2d'); _.texture = new THREE.Texture(_.newCanvas); _.texture.transparent = true; _.material.map = _.texture; const width = height * 2; _.canvas = d3.select('body').append('canvas') .style('display','none') .attr('width', width) .attr('height',height) .attr('class','ej-canvas-ctx') .node(); _.context = _.canvas.getContext('2d'); _.proj = d3.geoEquirectangular().scale(width/scw).translate([width/2, height/2]); _.path = d3.geoPath().projection(_.proj).context(_.context); _.path2 = d3.geoPath().projection(_.proj).context(_.newContext); //set dimensions _.newCanvas.width = _.canvas.width; _.newCanvas.height = _.canvas.height; _.me._ = _; // only for debugging } function hover(event){ for (let v of _.onHoverVals) { v.call(event.target, event); } } function create() { const tj = this.threejsPlugin; if (!_.sphereObject) { resize.call(this); _.sphereObject= new THREE.Mesh(_.geometry, _.material); // _.sphereObject.scale.set(1.02,1.02,1.02); _.sphereObject.name = _.me.name; if (tj.domEvents) { tj.domEvents.addEventListener(_.sphereObject, 'mousemove', hover, false); } } _.onDrawVals.forEach(v => { v.call(this, _.newContext, _.path); }); _.texture.needsUpdate = true; tj.addGroup(_.sphereObject); } // stroke adjustment when zooming const scale10 = d3.scaleLinear().domain([30, 450]).range([10, 2]); function choropleth() { const o = this._.options; if (o.choropleth) { let i = _.countries.features.length; while (i--) { const obj = _.countries.features[i]; const color = obj.properties.color || _.style.countries || 'rgba(2, 20, 37,0.8)'; _.context.beginPath(); _.path(obj); _.context.fillStyle = color; _.context.strokeStyle = color; _.context.fill(); _.context.stroke(); } return true; } else { _.path(_.countries); _.context.fillStyle = _.style.countries || 'rgba(2, 20, 37,0.8)'; _.context.fill(); return false; } } function resize() { const o = this._.options; if (_.style.ocean) { _.context.fillStyle = _.style.ocean; _.context.fillRect(0, 0, _.canvas.width, _.canvas.height); } else { _.context.clearRect(0, 0, _.canvas.width, _.canvas.height); } let border = o.showBorder; _.context.beginPath(); if (!border) { choropleth.call(this); } if (!o.choropleth && (o.showBorder || o.showBorder===undefined)) { let sc = scale10(this._.proj.scale()); if (sc < 1) sc = 1; if (border) { _.path(_.allCountries); } _.context.lineWidth = sc; _.context.strokeStyle = _.style.border || 'rgb(239, 237, 234)'; _.context.stroke(); } //apply the old canvas to the new one _.newContext.drawImage(_.canvas, 0, 0); _.refresh = true; } function refresh() { if (_.refresh && this.hoverCanvas && this._.options.showSelectedCountry) { _.refresh = false; _.newContext.clearRect(0, 0, _.canvas.width, _.canvas.height); _.newContext.drawImage(_.canvas, 0, 0); if (_.selected.features.length>0) { _.newContext.beginPath(); _.path2(_.selected); _.newContext.fillStyle = _.style.selected || 'rgba(87, 255, 99, 0.5)'; // 0.4 'rgba(255, 235, 0, 0.4)'; // 'rgba(87, 255, 99, 0.4)'; _.newContext.fill(); } const {country} = this.hoverCanvas.states(); if (country && !_.selected.features.find(obj=>obj.id===country.id)) { _.newContext.beginPath(); _.path2(country); _.newContext.fillStyle = _.style.hover || 'rgba(117, 0, 0, 0.5)'; // 0.4 'rgb(137, 138, 34)'; _.newContext.fill(); } _.texture.needsUpdate = true; this.threejsPlugin.renderThree(); } } return { name: 'canvasThreejs', urls: worldUrl && [worldUrl], onReady(err, data) { _.me.data(data); }, onInit(me) { _.me = me; init.call(this); }, onCreate() { if (this.worldJson && !_.world) { _.me.data(this.worldJson.data()); } create.call(this); }, onResize() { resize.call(this); }, onRefresh() { refresh.call(this); }, onDraw(obj) { Object.assign(_.onDraw, obj); _.onDrawVals = Object.keys(_.onDraw).map(k => _.onDraw[k]); }, countries(arr) { if (arr) { _.countries.features = arr; } else { return _.countries.features; } }, selectedCountries(arr) { if (arr) { _.selected.features = arr; } else { return _.selected.features; } }, data(data) { if (data) { _.world = data; _.allCountries = topojson.feature(data, data.objects.countries); _.countries.features = _.allCountries.features; } else { return _.world; } }, allData(all) { if (all) { _.world = all.world; _.countries = all.countries; } else { const {world, countries} = _; return {world, countries}; } }, style(s) { if (s) { _.style = s; } return _.style; }, reload() { resize.call(this); refresh.call(this); }, refresh() { _.refresh = true; refresh.call(this); }, onHover(obj) { Object.assign(_.onHover, obj); _.onHoverVals = Object.keys(_.onHover).map(k => _.onHover[k]); }, sphere() { return _.sphereObject; }, } }