Public
Edited
Nov 4, 2023
Fork of Earthquakes
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
particleSystem = {
const geometry = new THREE.BufferGeometry();
const positions = [];
const atDepth = [];
const colors = [];
const sizes = [];
const time = [];
let color = new THREE.Color(0xffffff);

const depthScale = d3
.scaleLinear()
.domain(d3.extent(earthquakes, (d) => d.depth))
.range([radius, radius * 0.3]);
console.log(depthScale.domain());
const colorScale = d3
.scaleSequential(d3[`interpolate${colorScheme}`])
.domain(d3.extent(earthquakes, (d) => d.depth));

const sizeScale = d3
.scaleSqrt()
.domain(d3.extent(earthquakes, (d) => d.magnitude))
.range([1, 10]);

const timeScale = d3
.scaleLinear()
.domain(d3.extent(earthquakes, (d) => d.date))
.range([0, 1]);

earthquakes.forEach((d) => {
const pos = vertex([d.longitude, d.latitude], radius);
const atDepthPos = vertex([d.longitude, d.latitude], depthScale(d.depth));

positions.push(pos.x, pos.y, pos.z);
atDepth.push(atDepthPos.x, atDepthPos.y, atDepthPos.z);
color = color.setStyle(colorScale(d.depth));
colors.push(color.r, color.g, color.b);
sizes.push(sizeScale(d.magnitude) * scaleFactor);
time.push(timeScale(d.date));
});

geometry.addAttribute(
"position",
new THREE.Float32BufferAttribute(positions, 3)
);
geometry.setAttribute(
"atDepth",
new THREE.Float32BufferAttribute(atDepth, 3)
);
geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute("time", new THREE.Float32BufferAttribute(time, 1));
geometry.setAttribute(
"size",
new THREE.Float32BufferAttribute(sizes, 1).setUsage(THREE.DynamicDrawUsage)
);

const material = new THREE.ShaderMaterial({
uniforms: {
progress: { value: 0 }
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
// transparent: true,
vertexColors: true,
blending: THREE.AdditiveBlending,
opacity: 0.9
});

const particleSystem = new THREE.Points(geometry, material);
return particleSystem;
}
Insert cell
vertexShader = `
attribute vec3 atDepth;
attribute float size;
attribute float time;
varying vec3 vColor;
uniform float progress;
float timeWindow = ${timeWindow};

// Simplex 2D noise
//
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }

float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

float random (float seed) {
return fract(sin(seed)*100000.0);
}

float nearTime(float eventTime, float progress) {
float distance = abs(eventTime - (progress - floor(progress)));
if (distance <= timeWindow) {
return cos((1.0 - (distance / timeWindow)) * 3.1415);
}
return 0.0;
}

void main() {
vColor = color;
float nearTime = nearTime(time, progress);
gl_PointSize = max(size, size * nearTime);
float noise = snoise(vec2(size, progress));

float shakeStrength = float(${shaking});
float xShake = snoise(vec2(progress * 0.1/${speed}, atDepth.x));
float yShake = snoise(vec2(progress * 0.1/${speed}, atDepth.y));
float zShake = snoise(vec2(progress * 0.1/${speed}, atDepth.z));
vec3 shake = vec3(xShake, yShake, zShake);
vec3 newPosition = atDepth + shake * shakeStrength * nearTime;

gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition , 1.0);
}
`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function wireframe(multilinestring, radius, material) {
const geometry = new THREE.Geometry();

for (const P of multilinestring.coordinates) {
for (let p0, p1 = vertex(P[0], radius), i = 1; i < P.length; ++i) {
geometry.vertices.push(p0 = p1, p1 = vertex(P[i], radius));
}
}
return new THREE.LineSegments(geometry, material);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
EF = import("https://unpkg.com/three@0.117.0/examples/jsm/postprocessing/EffectComposer.js?module")
Insert cell
EffectComposer = EF.EffectComposer
Insert cell
UBP = import("https://unpkg.com/three@0.117.0/examples/jsm/postprocessing/UnrealBloomPass.js?module")
Insert cell
UnrealBloomPass = UBP.UnrealBloomPass
Insert cell
RP = import("https://unpkg.com/three@0.117.0/examples/jsm/postprocessing/RenderPass.js?module")
Insert cell
RenderPass = RP.RenderPass
Insert cell
GP = import(
"https://unpkg.com/three@0.117.0/examples/jsm/postprocessing/GlitchPass.js?module"
)
Insert cell
GlitchPass = GP.GlitchPass
Insert cell
THREE = {
const THREE = window.THREE = await require('three@0.115.0');
await require('three/examples/js/controls/OrbitControls.js').catch(() => {});
// await require("three/examples/js/postprocessing/EffectComposer.js").catch(() => {});
// await require("three/examples/js/postprocessing/UnrealBloomPass.js").catch(() => {});
await require("three/examples/js/postprocessing/GlitchPass.js").catch(() => {});
await require("three/examples/js/shaders/DigitalGlitch.js").catch(() => {});
await require("three/examples/js/postprocessing/ShaderPass.js").catch(() => {});
// await require("three/examples/js/postprocessing/RenderPass.js").catch(() => {});
await require("three/examples/js/controls/OrbitControls.js").catch(() => {});
// await require("three/examples/js/postprocessing/EffectComposer.js").catch(() => {});
await require("three/examples/js/postprocessing/ShaderPass.js").catch(() => {});
// await require("three/examples/js/postprocessing/SSAARenderPass.js").catch(() => {});
// await require("three/examples/js/postprocessing/UnrealBloomPass.js").catch(() => {});
await require("three/examples/js/shaders/LuminosityHighPassShader.js").catch(() => {});
await require("three/examples/js/shaders/CopyShader.js").catch(() => {});
return THREE;
}
Insert cell
Insert cell
Insert cell
Insert cell
pointBuffer = [1, 0, 1,0, 1, 0, 1, 0, 0,-1, 0, 1,0, 1, 1,1, 0, 1]
Insert cell
b = new Float32Array(pointBuffer)
Insert cell
b.length
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