Published
Edited
Oct 25, 2020
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
// const width=1587/2, height=1123/2
const width=900, height=500
const viewBoxWidth=500, viewBoxHeight=500
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr('viewBox', `${-viewBoxWidth/2} ${-viewBoxHeight/2} ${viewBoxWidth} ${viewBoxHeight}`)
.attr('style', 'background: #1E1225')
let rand = makeRandomGenerator(inputSeed);
// Every point is a trace.
let points = (new Array(lineCount)).fill(0).map(p => {
let x, y, z
x = (rand.random()-.5)*512
y = (rand.random()-.5)*512
z = (rand.random()-.5)*512
let source = new THREE.Vector3(x, y, z)
// trace of a point moving over time
let path = d3.path();
let d, norm, diff, target = source.clone();
let visible = false//, visiblePrev;
let speed = new THREE.Vector3(rand.random(),
rand.random(),
rand.random()).normalize()
for(let i = 0; i < stepsNumber; i+=.1) {
d = distance(target);

// flying to the surface along the normal
norm = normal(target).multiplyScalar(-1);
diff = norm.clone().multiplyScalar(d);
source = target.clone();
target.add(diff);
// tracing the particle path on the surface
if(Math.abs(d)<1){
i++
if (!getVisibility(target) && flags.includes('visibleSide')) continue

else {
if(path['_'].length == 0)
path.moveTo(target.x, target.y);
else
path.lineTo(target.x, target.y);
}
// remove from speed part that is collinear to normal (projecting to the surface)
speed.sub(norm.clone().multiplyScalar(norm.clone().dot(speed))).normalize()
speed.applyAxisAngle(norm, curvicity)
// let slide = getParticleForce(target)
target.add(speed.multiplyScalar(minSlide));
}


}
return path;
})
// drawing traces
if (flags.includes('l')) {
svg.selectAll('path')
.data( points )
.enter()
.append('path')
.attr('d', p => p.toString())
.attr('stroke', '#FCE000')
.attr('fill', 'none')
.attr('stroke-width', 1.1)
// .attr('opacity', .1)
}

// drawing points
if (flags.includes('d')) {
svg.selectAll('circle')
.data( points )
.enter()
.append('circle')
.attr('cx', p => p['_x0'])
.attr('cy', p => p['_y0'])
.attr('r', p => 2)
.attr('fill', p => '#FCE000')
}

return svg.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
distance = p => {
p = p.clone();
// rotation of the shape
p.applyAxisAngle(new THREE.Vector3(0,1,0).normalize(), sceneRotationX)
.applyAxisAngle(new THREE.Vector3(0,0,1).normalize(), sceneRotationY)

p.applyAxisAngle(new THREE.Vector3(1,0,0).normalize(), p.x*twistness)
p.x /= 2

// let distortion = new THREE.Vector3(0,0,0)
// // distortion.x = Math.sin(p.y/30)
// distortion.x = new noise('01').noise3D(p.x/200, p.y/200, p.z/200)
// distortion.y = new noise('02').noise3D(p.x/200, p.y/200, p.z/200)
// distortion.z = new noise('03').noise3D(p.x/200, p.y/200, p.z/200)
// distortion.multiplyScalar(100)
// p.add(distortion)

let q
switch(object){
case 'cage':
p.x = Math.abs(p.x) - 120
p.y = Math.abs(p.y) - 120
p.z = Math.abs(p.z) - 120
q = new THREE.Vector3(
Math.abs(p.x+1)-1,
Math.abs(p.y+1)-1,
Math.abs(p.z+1)-1)
let p1 = new THREE.Vector3(p.x,q.y,q.z).max(new THREE.Vector3(0,0,0)).length() +
Math.min(Math.max(p.x,q.y,q.z), 0)
let p2 = new THREE.Vector3(q.x,p.y,q.z).max(new THREE.Vector3(0,0,0)).length() +
Math.min(Math.max(q.x,p.y,q.z), 0)
let p3 = new THREE.Vector3(q.x,q.y,p.z).max(new THREE.Vector3(0,0,0)).length() +
Math.min(Math.max(q.x,q.y,p.z), 0)
return Math.min(p1,p2,p3)-40

case 'torus':
q = new THREE.Vector2(new THREE.Vector2(p.x, p.y).length()-80,p.z)
return q.length()-40

case 'sphere':
return p.length()-150
case 'octahedron':
let s = 100 // size
p.x = Math.abs(p.x)
p.y = Math.abs(p.y)
p.z = Math.abs(p.z)
let m = p.x + p.y + p.z - s
if( 3*p.x < m ) q = new THREE.Vector3(p.x, p.y, p.z)
else if( 3*p.y < m ) q = new THREE.Vector3(p.y, p.z, p.x)
else if( 3*p.z < m ) q = new THREE.Vector3(p.z, p.x, p.y)
else return m*0.57735027
let k = 0.5*(q.z-q.y+s)
k = k<0?0:k
k = k>s?s:k
return new THREE.Vector3(q.x,q.y-s+k,q.z-k).length()
// float sdOctahedron( vec3 p, float s)
// {
// // p = abs(p);
// // float m = p.x+p.y+p.z-s;
// // vec3 q;
// // if( 3.0*p.x < m ) q = p.xyz;
// // else if( 3.0*p.y < m ) q = p.yzx;
// // else if( 3.0*p.z < m ) q = p.zxy;
// // else return m*0.57735027;
// float k = clamp(0.5*(q.z-q.y+s),0.0,s);
// return length(vec3(q.x,q.y-s+k,q.z-k));
// }
}
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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