Public
Edited
Feb 2, 2023
1 fork
Insert cell
Insert cell
mutable nodes = [{index: 0, x:15*5 , y:-20*10,vx:0,vy:0},{index: 1, x:15*5 , y:-10*10,vx:0,vy:0}];
Insert cell
Insert cell
Insert cell
Insert cell
viewof keyframe_sim = sim_scrubber(1000)
Insert cell
Insert cell
nodes[0].x
Insert cell
md`${75 + (objB.velocity*(keyframe_sim/100) + 0.5*objB.force/objB.mass*(keyframe_sim/100)**2)*96/2.54}`
Insert cell
chart = {
//const root = d3.hierarchy(data);
//const links = root.links();
//const nodes = root.descendants();

var liveticks = 0;
//if (external) {liveticks.push(ticks);}

var objAx = 75 + (0.5*objA.force/objA.mass*(keyframe_sim/100)**2)*96/2.54;
var objBx = 75 + (objB.velocity*(keyframe_sim/100) + 0.5*objB.force/objB.mass*(keyframe_sim/100)**2)*96/2.54;
var objAvel = objA.force/objA.mass*(keyframe_sim/100)*96/2.54
var objBvel = (objB.velocity + objB.force/objB.mass*(keyframe_sim/100))*96/2.54
var objAaccel = objA.force/objA.mass*96/2.54

var objAvelText = objA.force/objA.mass*(keyframe_sim/100);
var objBvelText = (objB.velocity + objB.force/objB.mass*(keyframe_sim/100));

const svg = d3.create("svg")
//.attr("viewBox", [-width / 2, -height / 2, width, height]);
.attr("viewBox", [0,-height, width, height]);

const keyframe = keyframe_sim;

const node = svg.append("g")
.attr("fill", "#fff")
.attr("stroke", "#000")
.attr("stroke-width", 1.5)
.selectAll("circle")
.data(nodes)
.join("circle")
//.attr("fill", d => d.children ? null : "#000")
//.attr("stroke", d => d.children ? null : "#fff")
.attr("r", d=> (d.index == 0) ? (objA.mass*5): objB.mass*5);
node
//.attr("cx", d=> (d.index == 0) ?
// 75 + (0.5*objA.force/objA.mass*(keyframe_sim/100)**2)*96/2.54:
// 75 + (objB.velocity*(keyframe_sim/100) + 0.5*objB.force/objB.mass*(keyframe_sim/100)**2)*96/2.54)
.attr("cx", d=> (d.index == 0) ? objAx: objBx)
//.attr("cx", d => d.x)
.attr("cy", d => d.y-margin.top);
//.enter();
//.attr("vx", d => (d.index == 0) ? 0.0 : objB.velocity);
var texts = svg
.selectAll(".texts")
.data(nodes)
.enter()
.append("text")
.attr("x", d=> (d.index == 0) ?
objAx + Math.sign(objAvel)*objA.mass*7 + (Math.sign(objAvel) > 0 ? -14*Math.abs(objA.mass)-95:9*objA.mass+ 8) :
objBx + Math.sign(objBvel)*objB.mass*7 + (Math.sign(objBvel) > 0 ? -14*Math.abs(objB.mass)-95:9*objB.mass + 8))
.attr("y", d => d.y-margin.top)
// .attr("x", function(d) { return x(d) + 30; })
//.attr("y", function(d) { return y(d);})
.attr("dx", 10)
.attr("dy", 3)
//.attr('stroke', '#fff')
//.attr("dy", ".35em")
.text(d=> (d.index == 0) ? ("v= "+ formatter.format(objAvelText) + " m/s"):("v= " + formatter.format(objBvelText) + " m/s"));
//.text(function(d) { return d; });

svg
.append('defs')
.append('marker')
.attr('id', 'arrow')
.attr('viewBox', [0, 0, 10, 10])
.attr('refX', 2)
.attr('refY', 2)
.attr('markerWidth', 10)
.attr('markerHeight', 10)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d', d3.line()([[0,0],[0,4],[4,2]]))
//.attr("d", 'M0,-5L10,0L0,5')
.attr('stroke', 'black');

svg
.append('path')
.attr('d', d3.line()([[objAx + objA.mass*5*Math.sign(objAvel),-200 - margin.top],[objAx + objA.mass*5*Math.sign(objAvel) + objAvel,-200 - margin.top]]))
.attr('stroke-width', '3px')
.attr('stroke', 'black')
//.attr('marker-start', 'url(#arrow)')
.attr('marker-end', 'url(#arrow)')
.attr('fill', 'none');

svg
.append('path')
.attr('d', d3.line()([[objBx + objB.mass*5*Math.sign(objBvel),-100 - margin.top],[objBx + objB.mass*5*Math.sign(objBvel) + objBvel,-100 - margin.top]]))
.attr('stroke-width', '3px')
.attr('stroke', 'black')
//.attr('marker-start', 'url(#arrow)')
.attr('marker-end', 'url(#arrow)')
.attr('fill', 'none');

//simulation.force("test",(external ? constantForce(nodes,objA.force/objA.mass,0,objB.force/objB.mass,0) : constantForce(nodes,0,0,0,0)))
// .tick(ticks);
//.on("tick",ticked);

// const sim = d3.forceSimulation(nodes)
// .force("test",(external ? constantForce(nodes,objA.force/objA.mass,0,objB.force/objB.mass,0,objB.velocity,keyframe) : constantForce(nodes,0,0,0,0,objB.velocity,keyframe)))
// .stop()
// .tick(keyframe);

//const simulate = (external ? constantForce(nodes,objA.force/objA.mass,0,objB.force/objB.mass,0,objB.velocity,keyframe) : constantForce(nodes,0,0,0,0,objB.velocity,keyframe))


//const sim = d3.forceSimulation(nodes)
// .force("x",d3.forceX(100))
// .stop()
// .tick(keyframe);
//sim.on("tick",() => {node
// .attr("cx", d => d.x)
// .attr("cy", d => d.y-margin.top)} );
//function ticked() {
//simulation.nodes(nodes);
//simulation.force("test",(external ? constantForce(1,0,2,0) : constantForce(0,0,0,0)));
//simulation.alpha(1).restart();
//simulation.force("test").initialize(simulation.nodes());
// node
// .attr("cx", d => d.x)
// .attr("cy", d => d.y-margin.top)
//.attr("vx", d => (d.index == 0) ? 0.0 : objB.velocity);
//}

//svg.append("g")
// .call(xAxis);
//svg.append("g")
// .call(yAxis);

//simulation.nodes(nodes);

//simulation.tick(ticks);
//while(ticks < 301){
//simulation.stop();
//ticked();

//yield svg.node();
//await Promises.tick(1000);

// node
// .attr("cx", d => d.x)
// .attr("cy", d => d.y-margin.top);
//}
return svg.node();
}
Insert cell
formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
Insert cell
function constantForce(nods,accelxin1,accelyin1,accelxin2,accelyin2,oBvel,frame){
//const window.devicePixelRatio;
for (var i = 0, n = nods.length, nod; i<n; ++ i){
nod = nods[i];
if (i == 0){
//nod.vx += accelxin1;
//(external ? nod.vx += accelxin1/50000 : nod.vx = nod.vx);
//nod.vy += accelyin1;
//nod.x = 49*5 + 0.5*accelxin1*(liveticks/100)**2;
//nod.x += nod.vx;
//nod.x = 75 + (0.5*accelxin1*(frame)**2)*2.54/96*100;
nod.x = 75 + 0.5*accelxin1*(frame)**2;
//nod.vx = accelxin1/10*(frame/100)
}
if (i == 1){
//nod.vx += accelxin2;
//nod.vx = objB.velocity/100;
//(external ? nod.vx += accelxin2/100 : nod.vx = nod.vx);
//nod.vy += accelyin2;
//nod.x = 49*5 + 0.5*accelxin2*(liveticks/100)**2;
//nod.x += nod.vx;
//nod.x = 75 + (oBvel*(frame) + 0.5*accelxin2*(frame)**2)*2.54/96*100;
nod.x = 75 + oBvel*(frame) + 0.5*accelxin2*(frame)**2;
}
}
}
Insert cell
Insert cell
margin = ({top: 25, right: 0, bottom: 25, left: 0})
Insert cell
x = d3.scaleLinear()
.domain([0,width/10])
.range([0,width])
Insert cell
xAxis = svg=>svg
.attr("transform", `translate(0,${-margin.bottom})`)
.call(d3.axisBottom(x))
Insert cell
y=d3.scaleLinear()
.domain([height/10,0])
.range([-height,0])
Insert cell
yAxis = svg => svg
.attr("transform",`translate(0,${-margin.bottom})`)
.call(d3.axisRight(y))
Insert cell
height = 300
Insert cell
d3 = require("d3@6")
Insert cell
sim_scrubber = (n_frames) => Scrubber(Array.from({length: n_frames}, (_, i) => i), {
format: i => "Time: " + (i/100),
delay: 10,
autoplay: false,
loop: false
})
Insert cell
import {Scrubber} from "@mbostock/scrubber"
Insert cell
import {slider,checkbox,select,text,button} from "@jashkenas/inputs"
Insert cell
import { knob } from "@toja/knob-input"
Insert cell
import { view } from "@tomlarkworthy/view"
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