index.html
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://unpkg.com/redux@3.6.0/dist/redux.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 360)
.attr("height", 300)
svg.append("text")
.text("****")
.attr("y", 100)
.attr("x", 120)
.style("font-size", 36)
.style("font-family", "monospace")
d3.select("body").append("button")
.html('Reset')
.on('click', () => store.dispatch({ type: 'RESET' }));
d3.select("body").append("button")
.html('Zero')
.on('click', () => store.dispatch({ type: 'ZERO' }));
const initialstate = { iteration: 0, counter: 0 };
function counter(_state = initialstate, action = null) {
let state = snapshot(_state);
switch (action.type) {
case 'INCREMENT':
state.iteration ++;
state.counter ++;
return state;
case 'DECREMENT':
state.iteration ++;
state.counter --;
return state;
case 'ZERO':
state.iteration ++;
state.counter = 0;
return state;
case 'RESET':
return initialstate;
default:
return _state;
}
}
let store = Redux.createStore(counter);
store.subscribe(() => {
var state = store.getState();
svg.select("text")
.text(`${state.iteration}: ${state.counter}`)
}
);
d3.interval(() => {
store.dispatch({ type: Math.random()>0.5 ?'INCREMENT' : 'DECREMENT' });
}, 100);
function snapshot (obj) {
if(obj == null || typeof(obj) != 'object') {
return obj;
}
var temp = new obj.constructor();
for(var key in obj) {
if (obj.hasOwnProperty(key)) {
temp[key] = snapshot(obj[key]);
}
}
return temp;
};
</script>
</body>