|
<!DOCTYPE html> |
|
<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; |
|
} |
|
.count-display { |
|
color: #3d3d3d; |
|
font-size: 10em; |
|
font-family: sans; |
|
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> |
|
|
|
// A component that renders the count. |
|
var countDisplay = d3.component("div", "count-display") |
|
.render(function (selection, d){ |
|
selection.text(d.count); |
|
}); |
|
|
|
// A generic Button component. |
|
var button = d3.component("button") |
|
.render(function (selection, d){ |
|
selection |
|
.text(d.text) |
|
.on("click", d.onClick); |
|
}); |
|
|
|
// The panel that contains the two buttons. |
|
var buttonPanel = d3.component("div", "button-panel") |
|
.render(function (selection, d){ |
|
selection.call(button, [ |
|
{ |
|
text: "+", |
|
onClick: d.actions.increment |
|
},{ |
|
text: "-", |
|
onClick: d.actions.decrement |
|
}, |
|
]); |
|
}); |
|
|
|
// The top-level app component. |
|
var app = d3.component("div") |
|
.render(function (selection, d){ |
|
selection |
|
.call(countDisplay, d) |
|
.call(buttonPanel, d); |
|
}); |
|
|
|
|
|
function main(){ |
|
var store = Redux.createStore(reducer), |
|
actions = actionsFromDispatch(store.dispatch); |
|
|
|
render(); |
|
store.subscribe(render); |
|
|
|
function reducer (state, action){ |
|
var count = state || 0; |
|
switch (action.type) { |
|
case "INCREMENT": return count + 1; |
|
case "DECREMENT": return count - 1; |
|
default: return count; |
|
} |
|
} |
|
|
|
function actionsFromDispatch(dispatch){ |
|
return { |
|
increment: function (){ |
|
dispatch({ type: "INCREMENT" }); |
|
}, |
|
decrement: function (){ |
|
dispatch({ type: "DECREMENT" }); |
|
} |
|
} |
|
} |
|
|
|
function render(){ |
|
d3.select("body").call(app, { |
|
count: store.getState(), |
|
actions: actions |
|
}); |
|
} |
|
} |
|
main(); |
|
|
|
</script> |
|
</body> |