blob: 07143f1a3c0f7f46886de90b43022117cd4bbf6b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { Component } from 'react';
import cytoscape from 'cytoscape';
import coseBilkent from 'cytoscape-cose-bilkent';
import dagre from 'cytoscape-dagre';
import cyCanvas from 'cytoscape-canvas';
cytoscape.use(coseBilkent);
cytoscape.use(dagre);
cytoscape.use(cyCanvas);
const config = {
layout: {
name: 'cose-bilkent',
animate: true,
idealEdgeLength: 200,
edgeElasticity: 0.1,
},
};
export default class Base extends Component {
static defaultProps = {
height: '600px',
display: 'block',
}
componentDidMount() {
const { elements, layout = config.layout } = this.props;
this.layout = layout;
let nextElements = this.transform(elements);
if (this.setUp) {
nextElements = this.setUp(nextElements);
}
this.cy = cytoscape({
container: this.container,
zoom: 1,
maxZoom: 1,
boxSelectionEnabled: true,
wheelSensitivity: 0.2,
layout,
elements: nextElements,
style: this.getStyle(),
});
if (this.bindEvent) {
this.bindEvent(this.cy);
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.elements === this.elements && nextProps.layout === this.layout) {
return;
}
const { elements, layout: nextLayout } = nextProps;
const nodes = this.cy.nodes();
let nextElements = this.transform(elements);
if (this.setUp) {
nextElements = this.setUp(nextElements);
}
this.cy.json({ elements: nextElements, style: this.getStyle() });
if (nextLayout === this.layout && this.isSame(nodes, this.cy.nodes())) {
return;
}
this.layout = nextLayout;
const layout = this.cy.layout(nextLayout);
layout.pon('layoutstop').then(() => {
this.cy.minZoom(this.cy.zoom() - 0.3);
});
layout.run();
}
shouldComponentUpdate() {
return false;
}
componentWillUnmount() {
this.cy.destroy();
}
getCy() {
return this.cy;
}
isSame = (nodes, nextNodes) => {
if (nodes.length !== nextNodes.length) {
return false;
}
const diff = nextNodes.diff(nodes);
return diff.left.length < 1 && diff.right.length < 1;
}
transform(elements) {
if (!elements) {
return [];
}
this.elements = elements;
const { nodes, calls } = elements;
return {
nodes: nodes.map(node => ({ data: node })),
edges: calls.filter(call => (nodes.findIndex(node => node.id === call.source) > -1
&& nodes.findIndex(node => node.id === call.target) > -1))
.map(call => ({ data: { ...call, id: `${call.source}-${call.target}` } })),
};
}
render() {
return (<div style={{ ...this.props }} ref={(el) => { this.container = el; }} />);
}
}