Skip to content

Instantly share code, notes, and snippets.

@headwinds
Last active February 25, 2020 15:37
Show Gist options
  • Save headwinds/99aa4034f423531642343127115d1185 to your computer and use it in GitHub Desktop.
Save headwinds/99aa4034f423531642343127115d1185 to your computer and use it in GitHub Desktop.
Segment path study
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: Helvetica;
font-size: 16px;
}
ol li {
margin-bottom: 10px;
}
li.highlight {
background: yellow;
}
pre {
display: inline;
background: lightgray;
}
#viewport {
width: 960px;
height: 350px;
}
path {
fill: none;
stroke: #999;
}
path.hidden {
display: none;
}
path.init {
stroke-width: 2;
}
path.piece {
stroke-width: 6;
stroke: none;
}
line.sep {
stroke-width: 2;
stroke: none;
}
</style>
<body>
<h2>Think Oregon Trail as Cards</h2>
<div id="viewport"></div>
<h2>Quest</h2>
<ol id="instructions">
<li data-id="1">Embark on your new adventure</li>
<li data-id="2">Engage the Wampas and Collect gold and other trinkets</li>
<li data-id="3">Pass through the Valley of Many Moons</li>
<li data-id="4">Arrive at New Port Gultch and trade your cargo</li>
<li data-id="5">Return home</li>
</ol>
<h4>Dev Log</h4>
<p>Sept 5 2018<p>
<p>Sept 23 2018 - upgraded to D3 v5<p>
<h4>To Do</h4>
<p>show a party progressing along the trail</p>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script>
// State
const margin = {top: 0, right: 20, bottom: 0, left: 20};
const width = 1300 - margin.left - margin.right;
const height = 350 - margin.top - margin.bottom;
// generates an array of 12 colors but I only need 5
// and each color should have a theme ie forest is green
const colorsGen = d3.schemePaired;
const water = "lightblue";
const beach = "#fdbf6f";
const forest = "#33a02c";
const burn = "#b15928";
const colors = [water,
beach,
forest,
burn,
beach]
console.log(colors);
let pts = [];
const numPts = 7;
// this is interesting but I don't want a random color order but I could possibly re-purpose the random sort for other things
/*
function randomSort(a, b) {
return Math.random() > .5 ? 1 : -1;
}
colors.sort(randomSort);
*/
function getPoints(numPts){
const halfHeight = height / 2;
const heights = [ halfHeight - 50,
halfHeight - 75,
halfHeight - 100,
halfHeight - 25,
halfHeight -10];
function getHeight(height){
return Math.random() * ( height - 100 );
}
let newPts = [];
_.times( numPts, function(num){
newPts.push([num*(width/numPts), heights[num]]);
newPts.push([num*(width/numPts)+50, heights[num]]);
});
return newPts;
}
pts = getPoints(numPts);
const path = d3.line()
.curve(d3.curveCardinal);
const svg = d3.select("#viewport").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
const g = svg.append("g")
.attr("id","world")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
const world = g;
const line = g.append("path")
.attr("class", "hidden init")
.attr("d", path(pts));
const p = line.node();
const pLength = p.getTotalLength();
let cumu = 0;
const sampleInterval = .25;
// Main Functions
function showLine(callback, line) {
line.classed("hidden", false)
.attr("stroke-dasharray", pLength + " " + pLength)
.attr("stroke-dashoffset", pLength)
.transition()
.duration(1500)
.ease(d3.easeLinear)
.attr("stroke-dashoffset", 0)
.on("end", function() {
callback();
});
}
function splitPath() {
const numPieces = 5;
const pieceSizes = [];
const pieces = [];
for (let i=0; i<numPieces; i++) {
pieceSizes.push({i: i, size: Math.floor(Math.random() * 20) + 5});
}
const size = pieceSizes.reduce(function(a, b) {
return a + b.size;
}, 0);
const pieceSize = pLength / size;
pieceSizes.forEach(function(x, j) {
var segs = [];
for (let i=0; i<=x.size+sampleInterval; i+=sampleInterval) {
pt = p.getPointAtLength((i*pieceSize)+(cumu*pieceSize));
segs.push([pt.x, pt.y]);
}
angle = Math.atan2(segs[1][1] - segs[0][1], segs[1][0] - segs[0][0]) * 180 / Math.PI;
pieces.push({id: j, segs: segs, angle: angle});
cumu += x.size;
});
return pieces;
}
function drawSegments(pieces) {
function hiliteStoryPoint(i) {
function hilite() {
return this.getAttribute("data-id") === String(i);
}
d3.selectAll("#instructions li")
.classed("highlight", hilite);
}
const lines = g.selectAll("path.piece")
.data(pieces)
.enter().append("path")
.attr("class", "piece")
.attr("d", function(d, i) {
return path(d.segs);
});
// end of each segment there should be a goal icon
const seps = g.selectAll("line.sep")
.data(pieces)
.enter().append("line")
.attr("class", "sep")
.attr("transform", function(d, i) {
return "translate("
+ d.segs[0][0] + ","
+ d.segs[0][1] + ")rotate("
+ (d.angle-90) + " 0 0)";
})
.attr("x1", -12)
.attr("y1", 0)
.attr("x2", 12)
.attr("y2", 0);
const drawLineEverySec = 1000;
let tickCount = 1;
lines.transition()
.duration(0)
.delay(function(d, i) {
return i * drawLineEverySec;
})
.style("stroke", function(d, i) {
return colors[i];
})
.tween("tick", function(){
hiliteStoryPoint(tickCount);
tickCount++;
})
.on("end", function(d, i) {
if (i === pieces.length-1) {
// turns off story point hilites
setTimeout( function(){
d3.selectAll("#instructions li")
.classed("highlight", false);
}, drawLineEverySec)
}
})
// seperations
seps.transition()
.duration(0)
.delay(function(d, i) {
return i * drawLineEverySec;
})
.style("stroke-width", "10px")
.style("stroke", "#fff");
}
let hiliteCount = 0;
function defineLine() {
const pieces = splitPath();
const segments = g.selectAll("g.segment")
.data(pieces)
.enter().append("g"),
pts = [];
pieces.forEach(function(x) {
x.segs.forEach(function(seg, i) {
if (i > 0 && i % 2 === 0) {
pts.push({id: x.id, seg});
}
});
});
const dots = g.selectAll("circle")
.data(pts)
.enter().append("circle")
.attr("cx", function(d, i) {
return d.seg[0];
})
.attr("cy", function(d, i) {
return d.seg[1];
})
.style("fill", function(d, i, j) {
return colors[d.id];
})
.attr("r", 0);
dots.transition()
.duration(0)
.delay(function(d, i) {
return i * 10;
})
.attr("r", 3)
.on("end", function(d, i, j) {
if (i === pts.length-1) {
drawSegments(pieces);
}
});
}
function init(){
showLine(defineLine, line);
}
init();
/* Icon experiment
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100">
<defs>
<g id="Layer0_0_FILL">
<path fill="#009999" stroke="none" d="
M 90 48.05
L 90 32.05 80 32.05 80 16.05 22.05 16.05 22.05 29.05 14.05 29.05 14.05 43.05 22.05 43.05 22.05 71.05 35.05 71.05 35.05 88.05 67 88.05 67 71.05 80 71.05 80 48.05 90 48.05 Z"/>
</g>
</defs>
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
<use xlink:href="#Layer0_0_FILL"/>
</g>
</svg>
*/
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment