Files
weave-scope/client/app/scripts/charts/edge-container.js
David Kaltschmidt d520cffec7 Performance tweaks
Add debug.html to show toolbar

Perfjankie test runner

Playing w/ the pure mixin for perf. improvements

* Works well! Smoother zooming/panning when things have settled.
* Extract node movement to node-container, make nodes pure

Extracted node chart elements into own components

Keep control objects immutable while in components

Keep layout state objects alive

Made other components pure, removed mixin from stateless components

Remove font size adjustment from scaling

Fix zoomscale

Move node transform to node

* makes more sense there because the coords are rounded in the container

dynamic coords precision based on topology size

Make edge points immutable

Remove nodes maximum for layout engine

Dont send all canvas state down to next component

moving layout handling back to nodes-chart.js

Omit some props for edges/nodes, dont animate edges on low precision

Moved AppStore access out of lower components
2016-04-05 15:45:13 +02:00

97 lines
2.6 KiB
JavaScript

import _ from 'lodash';
import d3 from 'd3';
import React from 'react';
import { Motion, spring } from 'react-motion';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import reactMixin from 'react-mixin';
import { Map as makeMap } from 'immutable';
import Edge from './edge';
const animConfig = [80, 20]; // stiffness, damping
const pointCount = 30;
const line = d3.svg.line()
.interpolate('basis')
.x(d => d.x)
.y(d => d.y);
const buildPath = (points, layoutPrecision) => {
const extracted = [];
_.each(points, (value, key) => {
const axis = key[0];
const index = key.slice(1);
if (!extracted[index]) {
extracted[index] = {};
}
extracted[index][axis] = d3.round(value, layoutPrecision);
});
return extracted;
};
export default class EdgeContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
pointsMap: makeMap()
};
}
componentWillMount() {
this.preparePoints(this.props.points);
}
componentWillReceiveProps(nextProps) {
this.preparePoints(nextProps.points);
}
render() {
const { layoutPrecision, points } = this.props;
const other = _.omit(this.props, 'points');
if (layoutPrecision === 0) {
const path = line(points.toJS());
return <Edge {...other} path={path} />;
}
return (
<Motion style={this.state.pointsMap.toJS()}>
{(interpolated) => {
// convert points to path string, because that lends itself to
// JS-equality checks in the child component
const path = line(buildPath(interpolated, layoutPrecision));
return <Edge {...other} path={path} />;
}}
</Motion>
);
}
preparePoints(nextPoints) {
// Spring needs constant field count, hoping that dagre will insert never more than `pointCount`
let { pointsMap } = this.state;
// filling up the map with copies of the first point
const filler = nextPoints.first();
const missing = pointCount - nextPoints.size;
let index = 0;
if (missing > 0) {
while (index < missing) {
pointsMap = pointsMap.set(`x${index}`, spring(filler.get('x'), animConfig));
pointsMap = pointsMap.set(`y${index}`, spring(filler.get('y'), animConfig));
index++;
}
}
nextPoints.forEach((point, i) => {
pointsMap = pointsMap.set(`x${index + i}`, spring(point.get('x'), animConfig));
pointsMap = pointsMap.set(`y${index + i}`, spring(point.get('y'), animConfig));
});
this.setState({ pointsMap });
}
}
reactMixin.onClass(EdgeContainer, PureRenderMixin);