Published
Edited
Nov 19, 2020
2 stars
Insert cell
md`# D3, ThreeJS combination for Data Visualization`
Insert cell
Insert cell
globe = {
// Render spherical map
renderer.render(scene, camera);
yield renderer.domElement;
}
Insert cell
//controls = new THREE.OrbitControls(camera, renderer.domElement);

Insert cell
md`### Constants and functions`
Insert cell
height = 512
Insert cell
width = 1024
Insert cell
projection = d3.geoEquirectangular().translate([width/2, height/2]).scale(163);
Insert cell
worldFeatures = await FileAttachment("world.json").json()
Insert cell
createMap = () =>{
// Set canvas 2d context to start drawing
const context = DOM.context2d(width, height);
// Creates a new geographic path generator with projection and context
const path = d3.geoPath(projection, context);
const scale = 163;
// Draw canvas background
context.beginPath();
context.rect(0, 0, width, height);
context.fillStyle = "#333";
context.fill();
// Set styling for countries
context.beginPath();
context.strokeStyle = "#333";
context.lineWidth = 0.25;

path(worldFeatures);
context.fillStyle = "#fff";
context.fill();
context.stroke();
// Return canvas element
return context.canvas;
}
Insert cell
worldStatus= (vizOption,dataType)=>{
const svg = d3.create("svg")
.style("display", "block")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);
svg.append("rect").attr("width",width).attr("height",height).attr("fill","lightgray");
const dateText = svg.append("text")
.attr("id","date")
//.attr("x", margin.left)
//.attr("y", margin.top/2)
.attr("font-size","15")
.style("stroke","black")
.style("fill","black")
.text("Test");
const chartContainer = svg.append("g")
//.attr("transform", `translate(${margin.left},${margin.top})`);

const outline = ({type: "Sphere"});
//const projection = d3.geoEqualEarth().fitExtent([[0, 0], [Width, Height]], outline);
//const projection = d3.geoNaturalEarth1().fitExtent([[0, 0], [width, height]], outline);
const geoPathGenerator = d3.geoPath().projection(projection);
chartContainer.append("path").attr("d",geoPathGenerator(outline)).attr("fill","#c9e8fd");

const bubbleColor = "red";

let radScale=undefined;
if (vizOption == "bubble") radScale = d3.scaleSqrt().domain(dataExtent.deaths).range([1, width/50]);
const container = chartContainer.append("g");
//const slider = createSlider(svg, 0, dates.length-1,dates.length-1, Height+margin.top/2, drawChart);
let dateIndex = dates.length-1;//slider.value();
drawChart();
return svg.node();
function drawChart(){
//dateIndex =slider.value();
dateText.text((dataType=="deaths"?"Deaths ":"Confirmed cases ")+" by "+ dates[dateIndex]);
let data = {};
let dData = {};
Object.keys(confirmed_n_death).forEach(function(d){
if (dataType == "confirmed")
data[d] = confirmed_n_death[d].confirmed[dateIndex];
else data[d] = confirmed_n_death[d].deaths[dateIndex];
});
(vizOption=="choropleth")?drawChoropleth(container, worldMap, "name", data, World_choropleth_colorScale,projection)
:drawBubbleChart(container, worldMap, "name", data, radScale, bubbleColor, projection);
}
}
Insert cell
camera.position.z=options.position
Insert cell
camera = {
const fov = 45;
const aspect = width / height;
const near = 1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 500;
return camera;
}
Insert cell
renderer = {
// Set and return the renderer object
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
return renderer;
}
Insert cell
map = rasterize(chart)// createMap()
Insert cell
chart = worldStatus(options.visOption, options.dataType)
Insert cell
url = URL.createObjectURL(serialize(chart))
Insert cell
function rasterize(svg) {
return new Promise(resolve => {
const im = new Image();
im.src = url;
im.onload = () => {
const rect = svg.getBoundingClientRect();
const context = DOM.context2d(rect.width, rect.height);
context.drawImage(im, 0, 0, rect.width, rect.height);
resolve(context.canvas);
}
})
}
Insert cell
scene = {
// Here we are creating a basic THREE.js scene with just one grey sphere in it.
const scene = new THREE.Scene();
const light = new THREE.HemisphereLight('#fff', '#666', 1.5);
light.position.set(0, 500, 0);
scene.add(light);
const waterMaterial = new THREE.MeshBasicMaterial({color: '#555', transparent: true});
const sphere = new THREE.SphereGeometry(200, 100, 100);
const baseLayer = new THREE.Mesh(sphere, waterMaterial);
// Here we are adding our map as a texture for the sphere
const mapTexture = new THREE.Texture(map);
mapTexture.needsUpdate = true;
const mapMaterial = new THREE.MeshBasicMaterial({ map: mapTexture, transparent: true });
const mapLayer = new THREE.Mesh(sphere, mapMaterial);
var root = new THREE.Object3D(map);
root.add(baseLayer);
root.add(mapLayer);
scene.add(root);
let frame;
(function render() {
root.rotation.y += 0.005;
frame = requestAnimationFrame(render);
renderer.render(scene, camera);
})();
invalidation.then(() => cancelAnimationFrame(frame));
return scene;
}
Insert cell
md`### Imports and Libraries`
Insert cell
import {confirmed_n_death, dataExtent, dates, hideToolTip, moveToolTip, drawChoropleth, drawBubbleChart, worldMap, World_choropleth_colorScale, showToolTip} from "@spattana/covid-19-update"
Insert cell
import {slider,radio} from "@jashkenas/inputs"
Insert cell
import {columns} from "@bcardiff/observable-columns"
Insert cell
THREE.REVISION
Insert cell
THREE = {
const THREE = window.THREE = await require("three/build/three.min.js");
await require("three/examples/js/controls/OrbitControls.js").catch(() => {});
//const THREE = window.THREE = await require("three@0.99.0/build/three.min.js");
//await require("three@0.99.0/examples/js/controls/OrbitControls.js").catch(() => {});
return window.THREE ;
}//require("three/build/three.min.js")
Insert cell
import {serialize} from "@mbostock/saving-svg"
Insert cell
d3 = require("d3@5")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more