d3.hasChanged
Modifying particles with Redux
by IPWright83
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.js"></script>
<svg width="960" height="500"></svg>
https://jsfiddle.net/ak5p0y0L/33/#run
JavaScript
const nodes = 250;
const width = 960;
const height = 500;
const locals = {};
d3.selection.prototype.hasChanged = function(...keys) {
for (let key of keys) {
if (!locals[key]) {
locals[key] = d3.local();
}
}
return this.filter(function(d) {
for (let key of keys) {
const local = locals[key];
const oldValue = local.get(this);
let newValue = d[key];
if (oldValue !== newValue) {
local.set(this, newValue);
return true;
}
}
return false;
})
};
const initState = {};
d3.range(nodes).forEach((d, i) => initState[i] = {
xloc: 0,
yloc: 0,
xvel: 0,
yvel: 0
});
const x = d3.scaleLinear().domain([-5, 5]).range([0, width]);
const y = d3.scaleLinear().domain([-5, 5]).range([0, height]);
const circle = d3.select("svg")
.selectAll("circle")
.data(Object.values(initState)).enter()
.append("circle")
.attr("cx", 10)
.attr("cy", 10)
.attr("r", 1);
const reducer = (state = initState, action) => {
switch (action.type) {
case "VELOCITY":
{
const payload = action.payload;
const index = payload.i;
const datum = state[index];
const newDatum = {
xloc: datum.xloc + datum.xvel,
yloc: datum.yloc + datum.yvel,
xvel: datum.xvel + payload.vx,
yvel: datum.yvel + payload.vy,
};
return {
...state, [index]: newDatum
};
}
default:
return state;
}
};
const store = Redux.createStore(reducer);
store.subscribe(() => {
const data = Object.values(store.getState());
d3.select("svg")
.selectAll("circle")
.data(data)
//.hasChanged("xloc", "yloc", "xvel", "yvel")
.attr("transform", function(d) {
return "translate(" + x(d.xloc) + "," + y(d.yloc) + ")";
})
.attr("r", function(d) {
return Math.min(1 + 1000 * Math.abs(d.xvel * d.yvel), 10);
})
});
d3.timer(function() {
const data = Object.values(store.getState());
...