Created
July 21, 2020 21:37
-
-
Save steveio/c298b173399ee9b3048595bb1c961a75 to your computer and use it in GitHub Desktop.
8bit Wind Compass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- adapted from http://bl.ocks.org/tomgp/6475678 --> | |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
background: #000000; | |
} | |
svg{ | |
stroke: #39ff14; | |
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; | |
} | |
#rim { | |
fill: none; | |
stroke: #39ff14; | |
stroke-width: 3px; | |
} | |
.second-hand{ | |
stroke-width:3; | |
} | |
.minute-hand{ | |
stroke-width:8; | |
stroke-linecap:round; | |
} | |
.hour-hand{ | |
stroke-width:12; | |
stroke-linecap:round; | |
} | |
.hands-cover{ | |
stroke-width:3; | |
fill:red; | |
} | |
.second-tick{ | |
stroke-width:2; | |
fill:#39ff14; | |
} | |
.hour-tick{ | |
stroke-width:8; //same as the miute hand | |
} | |
.second-label{ | |
font-size: 12px; | |
} | |
.hour-label{ | |
font-size: 24px; | |
} | |
</style> | |
<body> | |
<script src="https://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var radians = 0.0174532925, | |
clockRadius = 200, | |
margin = 50, | |
width = (clockRadius+margin)*2, | |
height = (clockRadius+margin)*2, | |
hourHandLength = 2*clockRadius/3, | |
minuteHandLength = clockRadius, | |
secondHandLength = clockRadius-12, | |
secondHandBalance = 30, | |
secondTickStart = clockRadius; | |
secondTickLength = -10, | |
hourTickStart = clockRadius, | |
hourTickLength = -18 | |
secondLabelRadius = clockRadius + 16; | |
secondLabelYOffset = 5 | |
hourLabelRadius = clockRadius - 40 | |
hourLabelYOffset = 7; | |
var hourScale = d3.scale.linear() | |
.range([0,360]) | |
.domain([0,8]); | |
var minuteScale = secondScale = d3.scale.linear() | |
.range([0,360]) | |
.domain([0,360]); | |
var directionLabel = ['N','NE','E','SE','S','SW','W','NW']; | |
// Map Arduino sensor index to direction label array position | |
var directionMap = []; | |
directionMap[0] = 4; | |
directionMap[1] = 6; | |
directionMap[2] = 5; | |
directionMap[3] = 7; | |
directionMap[4] = 0; | |
directionMap[5] = 2; | |
directionMap[6] = 3; | |
directionMap[7] = 1; | |
var handData = [ | |
{ | |
type:'hour', | |
value:0, | |
length:-hourHandLength, | |
scale:hourScale | |
} | |
/* | |
{ | |
type:'minute', | |
value:0, | |
length:-minuteHandLength, | |
scale:minuteScale | |
}, | |
{ | |
type:'second', | |
value:0, | |
length:-secondHandLength, | |
scale:secondScale, | |
balance:secondHandBalance | |
} | |
*/ | |
]; | |
var ws = null | |
var maxReconnectAttemps = 10; | |
var reconnectAttempts = 0; | |
// setup WebSocket | |
function setupWebSocket() | |
{ | |
reconnectAttempts = 0; | |
ws = new WebSocket('ws://127.0.0.1:5678',[]); | |
ws.onopen = function () { | |
console.log('WebSocket Open'); | |
}; | |
ws.onerror = function (error) { | |
console.log('WebSocket Error ' + error); | |
}; | |
ws.onmessage = function (e) { | |
var rawData = e.data; | |
if(rawData.trim().length > 1 && rawData.trim() != "undefined") | |
{ | |
try { | |
var a = rawData.split(" "); | |
var idx = a[0] -3; // shift arduino pin 3-10 to range 0-7 | |
updateData(directionMap[idx]); | |
moveHands(); | |
} catch(e) { | |
console.log("Invalid Data:"+rawData.toString()); | |
} | |
} | |
}; | |
} | |
// check connection status every 60sec, upto maxReconnectAttemps, try reconnect | |
const interval = setInterval(function checkConnectStatus() { | |
if (reconnectAttempts++ < maxReconnectAttemps) | |
{ | |
if (ws.readyState !== ws.OPEN) { | |
console.log("WS connection closed - try re-connect"); | |
setupWebSocket(); | |
} | |
} | |
}, 60000); | |
document.addEventListener("DOMContentLoaded", function() { | |
setupWebSocket(); | |
}); | |
function drawClock(){ //create all the clock elements | |
updateData(); //draw them in the correct starting position | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
svg.append("g") | |
.append("text") | |
.attr("y", 6) | |
.attr("dy", ".71em") | |
.attr("transform", "rotate(-90)") | |
.style("text-anchor", "end") | |
.text("8bit Arduino Wind Compass"); | |
var face = svg.append('g') | |
.attr('id','clock-face') | |
.attr('transform','translate(' + (clockRadius + margin) + ',' + (clockRadius + margin) + ')'); | |
//add marks for seconds | |
face.selectAll('.second-tick') | |
.data(d3.range(0,360)).enter() | |
.append('line') | |
.attr('class', 'second-tick') | |
.attr('x1',0) | |
.attr('x2',0) | |
.attr('y1',secondTickStart) | |
.attr('y2',secondTickStart + secondTickLength) | |
.attr('transform',function(d){ | |
return 'rotate(' + secondScale(d) + ')'; | |
}); | |
//and labels | |
face.selectAll('.second-label') | |
.data(d3.range(0,360,10)) | |
.enter() | |
.append('text') | |
.attr('class', 'second-label') | |
.attr('text-anchor','middle') | |
.attr('x',function(d){ | |
return secondLabelRadius*Math.sin(secondScale(d)*radians); | |
}) | |
.attr('y',function(d){ | |
return -secondLabelRadius*Math.cos(secondScale(d)*radians) + secondLabelYOffset; | |
}) | |
.text(function(d){ | |
return d; | |
}); | |
//... and hours | |
face.selectAll('.hour-tick') | |
.data(d3.range(0,360)).enter() | |
.append('line') | |
.attr('class', 'hour-tick') | |
.attr('x1',0) | |
.attr('x2',0) | |
.attr('y1',hourTickStart) | |
.attr('y2',hourTickStart + hourTickLength) | |
.attr('transform',function(d){ | |
return 'rotate(' + hourScale(d) + ')'; | |
}); | |
face.selectAll('.hour-label') | |
.data(d3.range(0,8)) | |
.enter() | |
.append('text') | |
.attr('class', 'hour-label') | |
.attr('text-anchor','middle') | |
.attr('x',function(d){ | |
return hourLabelRadius*Math.sin(hourScale(d)*radians); | |
}) | |
.attr('y',function(d){ | |
return -hourLabelRadius*Math.cos(hourScale(d)*radians) + hourLabelYOffset; | |
}) | |
.text(function(d){ | |
return directionLabel[d]; | |
}); | |
var hands = face.append('g').attr('id','clock-hands'); | |
face.append('g').attr('id','face-overlay') | |
.append('circle').attr('class','hands-cover') | |
.attr('x',0) | |
.attr('y',0) | |
.attr('r',clockRadius/20); | |
hands.selectAll('line') | |
.data(handData) | |
.enter() | |
.append('line') | |
.attr('class', function(d){ | |
return d.type + '-hand'; | |
}) | |
.attr('x1',0) | |
.attr('y1',function(d){ | |
return d.balance ? d.balance : 0; | |
}) | |
.attr('x2',0) | |
.attr('y2',function(d){ | |
return d.length; | |
}) | |
.attr('transform',function(d){ | |
return 'rotate('+ d.scale(d.value) +')'; | |
}); | |
} | |
function moveHands(){ | |
d3.select('#clock-hands').selectAll('line') | |
.data(handData) | |
.transition() | |
.attr('transform',function(d){ | |
return 'rotate('+ d.scale(d.value) +')'; | |
}); | |
} | |
function updateData(idx){ | |
handData[0].value = idx; | |
//var t = new Date(); | |
//handData[0].value = (t.getHours() % 12) + t.getMinutes()/60 ; | |
//handData[1].value = 90; | |
//handData[2].value = t.getSeconds(); | |
} | |
drawClock(); | |
/* | |
setInterval(function(){ | |
updateData(); | |
moveHands(); | |
}, 1000); | |
*/ | |
d3.select(self.frameElement).style("height", height + "px"); | |
</script> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment