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