svg-paths-and-d3js
line block
shapes
coastline
Built with blockbuilder.org
license: mit |
svg-paths-and-d3js
line block
shapes
coastline
Built with blockbuilder.org
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<script> | |
const svg = d3.select("body").append("svg") | |
.attr("width", 960) | |
.attr("height", 500) | |
const drawGridLines = () => { | |
const gridContainer = svg.append('g') | |
.attr('id', 'grid'); | |
const width = window.innerWidth; | |
const height = window.innerHeight; | |
const gap = 10; | |
const totalHLines = Math.floor(height / gap); | |
const totalVLines = Math.floor(width / gap); | |
let hCount = 0; | |
while (hCount < totalHLines) { | |
const y = gap * hCount; | |
gridContainer | |
.append("line") | |
.style("stroke", "#f1f1f1") | |
.attr("x1",0) | |
.attr("y1",y) | |
.attr("x2",width) | |
.attr("y2",y); | |
hCount++ | |
} | |
let vCount = 0; | |
while (vCount < totalVLines) { | |
const x = gap * vCount; | |
gridContainer | |
.append("line") | |
.style("stroke", "#f1f1f1") | |
.attr("x1",x) | |
.attr("y1",0) | |
.attr("x2",x) | |
.attr("y2",height); | |
vCount++ | |
} | |
} | |
drawGridLines() | |
svg.append("text") | |
.text("Who doesn't 🖤 sci fi reticles?!") | |
.attr("y", 200) | |
.attr("x", 120) | |
.attr("font-size", 36) | |
.attr("font-family", "monospace"); | |
const getDestinationVector = ( originVector, angle, distance) => { | |
const destinationVector = {x: 0, y: 0}; | |
destinationVector.x = Math.round(Math.cos(angle * Math.PI / 180) * distance + originVector.x); | |
destinationVector.y = Math.round(Math.sin(angle * Math.PI / 180) * distance + originVector.y); | |
return destinationVector; | |
} | |
const createDirections = (command, originVector, curAngle, distance) => { | |
const dV = getDestinationVector(originVector, curAngle, distance ); | |
const X = dV.x; | |
const Y = dV.y; | |
previousVector = dV; | |
return `${command}${X} ${Y}` | |
} | |
const drawTriRecticle = (coordinates, id) => { | |
const triangleContainer = svg.append('g') | |
.attr('id', `triangleContainer${id}`); | |
triangleContainer.append('rect') | |
.attr("width",100) | |
.attr('height',90) | |
.style('stroke','none') | |
.style('fill','none'); | |
const triangle = triangleContainer.append('g') | |
.attr('id',`triangle${id}`); | |
triangle.append("path") | |
.attr("fill", "none"); | |
const symbol = d3.symbol().type(d3.symbolTriangle).size(64); | |
const plusX = coordinates.x + 10; | |
const plusY = coordinates.y + 60; | |
const triData = symbol(); | |
triangleContainer | |
.append('g') | |
.attr("transform","translate(" + plusX + "," + plusY + ")") | |
.attr('class', 'tri') | |
.attr('id','target') | |
.append('path') | |
.style("fill","#CCC") | |
.attr("d", triData); | |
let pathDirections = ''; | |
pathDirections += createDirections('M',previousVector,60,20);; | |
pathDirections += createDirections('L',previousVector,60,20); | |
pathDirections += createDirections('M',previousVector,60,40); | |
pathDirections += createDirections('L',previousVector,60,20); | |
pathDirections += createDirections('L',previousVector,180,20); | |
pathDirections += createDirections('M',previousVector,180,40); | |
pathDirections += createDirections('L',previousVector,180,20); | |
pathDirections += createDirections('L',previousVector,300,20); | |
pathDirections += createDirections('M',previousVector,300,40); | |
pathDirections += createDirections('L',previousVector,300,20); | |
const pathData = pathDirections; | |
triangle.select('path') | |
.attr('d', pathData) | |
.attr('stroke','#ddd') | |
.attr('stroke-width','1') | |
triangleContainer.attr('transform','translate(100,50)'); | |
} | |
let previousVector = {x:40,y:-10}; | |
drawTriRecticle(previousVector,0); | |
previousVector = {x:160,y:-10}; | |
drawTriRecticle(previousVector,1); | |
previousVector = {x:280,y:-10}; | |
drawTriRecticle(previousVector,2); | |
// need to figure out how to miter the caps! | |
// to add | |
// - animate flash | |
const drawSquareRecticle = (coordinates,id) => { | |
const squareContainer = svg.append('g') | |
.attr('id', `squareContainer${id}`); | |
squareContainer.append('rect') | |
.attr("width",100) | |
.attr('height',90) | |
.style('stroke','none') | |
.style('fill','none'); | |
const square = squareContainer.append('g') | |
.attr('id',`square${id}`); | |
square.append("path") | |
.attr("fill", "none"); | |
const symbol = d3.symbol().type(d3.symbolCross).size(40); | |
const plusX = coordinates.x + 50; | |
const plusY = coordinates.y + 50; | |
const plusData = symbol(); | |
squareContainer | |
.append('g') | |
.attr("transform","translate(" + plusX + "," + plusY + ")") | |
.attr('class', 'plus') | |
.attr('id','target') | |
.append('path') | |
.style("fill","#CCC") | |
.attr("d", plusData); | |
let pathDirections = ''; | |
pathDirections += createDirections('M',previousVector,0,0);; | |
pathDirections += createDirections('L',previousVector,0,20); | |
pathDirections += createDirections('M',previousVector,0,60); | |
pathDirections += createDirections('L',previousVector,0,20); | |
pathDirections += createDirections('L',previousVector,90,20); | |
pathDirections += createDirections('M',previousVector,90,60); | |
pathDirections += createDirections('L',previousVector,90,20); | |
pathDirections += createDirections('L',previousVector,180,20); | |
pathDirections += createDirections('M',previousVector,180,60); | |
pathDirections += createDirections('L',previousVector,180,20); | |
pathDirections += createDirections('L',previousVector,90,-20); | |
pathDirections += createDirections('M',previousVector,90,-60); | |
pathDirections += createDirections('L',previousVector,90,-20); | |
const pathData = pathDirections; | |
square.select('path') | |
.attr('d', pathData) | |
.attr('stroke','#ddd') | |
.attr('stroke-width','1') | |
squareContainer.attr('transform','translate(100,50)'); | |
} | |
previousVector = {x:10,y:200}; | |
drawSquareRecticle(previousVector,0); | |
previousVector = {x:150,y:200}; | |
drawSquareRecticle(previousVector,1); | |
previousVector = {x:300,y:200}; | |
drawSquareRecticle(previousVector,2); | |
const strobeReticle = (id, containerId) => { | |
const path = d3.select(`#${id}`).select('path') | |
const target = d3.select(`#${containerId}`).select('#target').select('path') | |
let repeatCount = 0; | |
function repeat() { | |
repeatCount++; | |
if (repeatCount < 3) { | |
d3 | |
.active(this) | |
.style('stroke', 'white') | |
.transition() | |
.style('stroke', 'red') | |
.transition() | |
.style('stroke', 'darkred') | |
.transition() | |
.style('stroke', 'red') | |
.transition() | |
.style('stroke', '#CCC') | |
.transition() | |
.on('start', repeat); | |
} | |
} | |
function repeatTarget() { | |
repeatCount++; | |
if (repeatCount < 3) { | |
d3 | |
.active(this) | |
.style('fill', 'white') | |
.transition() | |
.style('fill', 'red') | |
.transition() | |
.style('fill', 'darkred') | |
.transition() | |
.style('fill', 'red') | |
.transition() | |
.style('fill', '#CCC') | |
.transition() | |
.on('start', repeat); | |
} | |
} | |
path | |
.transition() | |
.duration(250) | |
.ease(d3.easeLinear) | |
.style('stroke', 'blue') | |
.on('start', repeat); | |
target | |
.transition() | |
.duration(250) | |
.ease(d3.easeLinear) | |
.style('stroke', 'none') | |
.style('fill', 'blue') | |
.on('start', repeatTarget); | |
} | |
const disco = () => { | |
let count = 0; | |
let triDelay = 200; | |
let squareDelay = 500; | |
setInterval( () => { | |
const targetTri = `triangle${count}`; | |
const targetTriContainer = `triangleContainer${count}`; | |
const targetSquare = `square${count}`; | |
const targetSquareContainerTri = `squareContainer${count}`; | |
strobeReticle(targetTri, targetTriContainer); | |
strobeReticle(targetSquare, targetSquareContainerTri); | |
if (count > 2) count = -1; | |
count++; | |
},2000) | |
} | |
//strobeReticle('triangle0','triangleContainer0'); | |
disco(); | |
</script> | |
</body> |