I'm close to finish my first project with d3.js. It calculates the potential energy available to a skier and I want to calculate the expected speed of the skier if all this energy is converted to kinetic energy. The final thing I want is to add a transition to the skier when he is dropped. I want the skier to always transit to the black circle on the right (p2). The duration of the transition doesn't matter right now. Is there an easy way to accomplish this task?
const height = 500;
const width = 800;
const skierIconSvg = 'https://image.flaticon.com/icons/svg/94/94150.svg';
const gate =
'https://docs.google.com/drawings/d/1k-mtzjW05U6KZKNt0kAI2pWqKsXFobptsa9kz6grYzA/edit?usp=sharing';
const [p1, p2, p3] = [
[80, 130],
[600, 170],
[750, 190],
];
const svg = d3.select('svg');
// Store a reference to the span we're going to update
const skierHeight = d3.select('#skier-height');
const vek = document.querySelector('#vekt');
console.log(vek.value);
const line = svg.append('line').attr('stroke', 'black');
const connection = svg.append('line').attr('stroke', 'green');
const projection = svg
.append('circle')
.attr('r', 5)
.attr('stroke', 'red')
.attr('fill', 'none');
const g = svg
.append('g')
.attr('cursor', 'move')
.attr('pointer-events', 'all')
.attr('stroke', 'transparent')
.attr('stroke-width', 30);
const point = g
.selectAll('image')
.data([p1, p2])
.enter()
.append('circle')
.attr('r', 10)
.call(
d3
.drag()
.subject(([x, y]) => ({
x,
y,
}))
.on('drag', dragged)
);
const skier = g
.append('image')
.attr('id', 'skier')
.datum(p3)
.attr('href', skierIconSvg)
.attr('width', 100)
.attr('height', 100)
.attr('transform', 'translate(-50, -40)')
.call(
d3
.drag()
.subject(([x, y]) => ({
x,
y,
}))
.on('drag', dragged)
);
update();
function dragged(d) {
d[0] = d3.event.x;
d[1] = d3.event.y;
update();
potensiellEnergi();
}
function update() {
const t = (width + height) / distance(p1, p2);
const l1 = interpolate(p1, p2, t);
const l2 = interpolate(p2, p1, t);
const p = interpolate(p1, p2, project(p1, p2, p3));
connection.attr('x1', p3[0]).attr('y1', p3[1]);
connection.attr('x2', p[0]).attr('y2', p[1]);
projection.attr('cx', p[0]).attr('cy', p[1]);
line.attr('x1', l1[0]).attr('y1', l1[1]);
line.attr('x2', l2[0]).attr('y2', l2[1]);
point.attr('cx', (d) => d[0]).attr('cy', (d) => d[1]);
skier.attr('x', (d) => d[0]).attr('y', (d) => d[1]);
skierHeight.text(`${getHeight(p, p1, p2).toFixed(2)} meter`);
}
function distance([x1, y1], [x2, y2]) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}
function interpolate([x1, y1], [x2, y2], t) {
return [x1 + (x2 - x1) * t, y1 + (y2 - y1) * t];
}
function project([x1, y1], [x2, y2], [x3, y3]) {
const x21 = x2 - x1,
y21 = y2 - y1;
const x31 = x3 - x1,
y31 = y3 - y1;
return (x31 * x21 + y31 * y21) / (x21 * x21 + y21 * y21);
}
function getHeight([xp, yp], [x1, y1], [x2, y2]) {
// Note that y is counted from top to bottom, so higher y means
// a point is actually lower.
// First, the total height is 100 metres.
const pxPerMeter = (y2 - y1) / 100;
// Calculate the height diff in pixels
const heightDiffPx = y2 - yp;
// Now transform it to meters
return heightDiffPx / pxPerMeter;
}
function vektVelger() {
const vektVerdi = document.querySelector('#vekt');
const vektDisplay = document.querySelector('#skier-vekt');
vektDisplay.innerHTML = vektVerdi.value;
}
function potensiellEnergi() {
const vektVerdi = parseInt(document.querySelector('#skier-vekt').textContent);
const skierHeight = parseInt(
document.querySelector('#skier-height').textContent
);
const potEDisplay = document.querySelector('#skier-potentialenergi');
const potEnergi = `${vektVerdi * skierHeight * 9.8}`;
return (potEDisplay.innerHTML = `${potEnergi}`);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://d3js.org/d3-path.v1.min.js"></script>
<script src="https://d3js.org/d3-shape.v1.min.js"></script>
<script src="https://d3js.org/d3-scale.v3.min.js"></script>
<script src="https://d3js.org/d3-axis.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@300&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Amatic+SC:wght@700&display=swap" rel="stylesheet" />
</head>
<body>
<h1>Forsøk på å lage en tutorial i JavaScript og D3.js</h1>
<h2>Høydeforskjell: <span id="skier-height"></span></h2>
<h2>Vekt: <span id="skier-vekt">70</span> kg</h2>
<h2>
Gravitasjonskraft (fg): <span id="skier-gravitasjon">9.8</span> m/sek/sek
</h2>
<h2>Potential Energy: <span id="skier-potentialenergi">0</span> KJOULE</h2>
<svg width="800" height="300"></svg>
<form>
Velg utøverens vekt:
<input type="number" id="vekt" placeholder="Velg utøverens vekt" />
</form>
<input type="button" value="velg" onclick="vektVelger()" />
<script src="skier.js"></script>
</body>
</html>
