A stopwatch app constructed using d3-component.
The following components are defined and used to construct the app:
app
buttonPanel
resetButton
reset
action when clicked. startStopButton
button
resetButton
and startStopButton
. timeDisplay
Built with blockbuilder.org
forked from curran's block: Posts with d3-component
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/d3@4"></script>
<script src="https://unpkg.com/d3-component@3"></script>
<script src="https://unpkg.com/redux@3/dist/redux.min.js"></script>
<style>
body {
text-align: center;
margin-top: 75px;
}
.time-display {
color: #3d3d3d;
font-size: 10em;
font-family: mono;
cursor: default;
}
button {
background-color: #7c7c7c;
border: solid 3px #7c7c7c;
border-radius: 11px;
color: white;
padding: 20px 60px;
margin: 20px;
font-size: 58px;
cursor: pointer;
}
button:hover {
border: solid 3px black;
}
button:focus {
outline: none;
}
</style>
</head>
<body>
<script>
// This function formats the stopwatch time.
var stopwatchFormat = (function (){
var twoDigits = d3.format("02.0f");
return function (milliseconds){
var centiseconds = Math.floor(milliseconds / 10),
centisecond = centiseconds % 100,
seconds = Math.floor(centiseconds /100),
second = seconds % 60,
minutes = Math.floor(seconds / 60),
minute = minutes % 60,
hours = Math.floor(minutes / 60);
return [
hours >= 1 ? hours + ":" : "",
minutes >= 1 ? (
(hours >= 1 ? twoDigits(minute) : minute) + ":"
) : "",
(minutes >= 1 ? twoDigits(second) : second),
hours < 1 ? ":" + twoDigits(centisecond) : "",
].join("").replace(/0/g, "O"); // Don't show the dot in the zeros.
}
}());
// A component that renders the formatted stopwatch time.
var timeDisplay = (function (){
var timerLocal = d3.local();
return d3.component("div", "time-display")
.render(function (selection, d){
var timer = timerLocal.get(selection.node());
timer && timer.stop();
if(d.stopped){
selection.text(stopwatchFormat(d.stopTime - d.startTime));
} else {
timerLocal.set(selection.node(), d3.timer(function (){
selection.text(stopwatchFormat(Date.now() - d.startTime));
}));
}
})
.destroy(function (selection){
var timer = timerLocal.get(selection.node());
timer && timer.stop();
});
}());
// A generic Button component.
var button = d3.component("button")
.render(function (selection, d){
selection
.text(d.text)
.on("mousedown", d.onClick);
});
// The button that either starts or stops (pauses) the stopwatch,
//depending on whether the stopwatch is running or not.
var startStopButton = d3.component("span")
.render(function (selection, d){
selection.call(button, {
text: d.stopped ? "Start" : "Stop",
onClick: d.stopped ? d.actions.start : d.actions.stop
});
});
// The reset button that stops and resets the stopwatch.
var resetButton = d3.component("span")
.render(function (selection, d){
selection.call(button, {
text: "Reset",
onClick: d.actions.reset
});
});
// The panel that contains the two buttons.
var buttonPanel = d3.component("div")
.render(function (selection, d){
selection
.call(startStopButton, d)
.call(resetButton, d);
});
// The top-level app component.
var app = d3.component("div")
.render(function (selection, d){
selection
.call(timeDisplay, d)
.call(buttonPanel, d);
});
function main(){
var store = Redux.createStore(reducer),
actions = actionsFromDispatch(store.dispatch);
store.subscribe(render);
actions.reset();
function reducer (state, action){
var state = state || {
stopped: true
};
switch (action.type) {
case "START":
return Object.assign({}, state, {
stopped: false,
startTime: Date.now() - (state.stopTime - state.startTime)
});
case "STOP":
return Object.assign({}, state, {
stopped: true,
stopTime: Date.now()
});
case "RESET":
var now = Date.now();
return Object.assign({}, state, {
stopped: true,
startTime: now,
stopTime: now
});
default:
return state;
}
}
function actionsFromDispatch(dispatch){
return {
start: function (){
dispatch({ type: "START" });
},
stop: function (){
dispatch({ type: "STOP" });
},
reset: function (){
dispatch({ type: "RESET" });
}
}
}
function render(){
console.log(store.getState());
d3.select("body").call(app, store.getState(), {
actions: actions
});
}
}
main();
</script>
</body>
https://unpkg.com/d3@4
https://unpkg.com/d3-component@3
https://unpkg.com/redux@3/dist/redux.min.js