import React from 'react'; import { connect } from 'react-redux'; import { debounce, pick } from 'lodash'; import { fromJS } from 'immutable'; import { event as d3Event, select } from 'd3-selection'; import { zoom, zoomIdentity } from 'd3-zoom'; import Logo from '../components/logo'; import NodesChartElements from './nodes-chart-elements'; import { clickBackground, cacheZoomState } from '../actions/app-actions'; import { activeLayoutZoomSelector } from '../selectors/nodes-chart-zoom'; import { activeTopologyZoomCacheKeyPathSelector } from '../selectors/topology'; import { ZOOM_CACHE_DEBOUNCE_INTERVAL } from '../constants/timer'; const ZOOM_CACHE_FIELDS = [ 'zoomScale', 'minZoomScale', 'maxZoomScale', 'panTranslateX', 'panTranslateY', ]; class NodesChart extends React.Component { constructor(props, context) { super(props, context); this.state = { zoomScale: 0, minZoomScale: 0, maxZoomScale: 0, panTranslateX: 0, panTranslateY: 0, }; this.debouncedCacheZoom = debounce(this.cacheZoom.bind(this), ZOOM_CACHE_DEBOUNCE_INTERVAL); this.handleMouseClick = this.handleMouseClick.bind(this); this.zoomed = this.zoomed.bind(this); } componentDidMount() { // distinguish pan/zoom from click this.isZooming = false; this.zoomRestored = false; this.zoom = zoom().on('zoom', this.zoomed); this.svg = select('.nodes-chart svg'); this.svg.call(this.zoom); this.restoreCachedZoom(this.props); } componentWillUnmount() { // undoing .call(zoom) this.svg .on('mousedown.zoom', null) .on('onwheel', null) .on('onmousewheel', null) .on('dblclick.zoom', null) .on('touchstart.zoom', null); this.debouncedCacheZoom.cancel(); } componentWillReceiveProps(nextProps) { const layoutChanged = nextProps.layoutId !== this.props.layoutId; // If the layout has changed (either active topology or its options) or // relayouting has been requested, stop pending zoom caching event and // ask for the new zoom settings to be restored again from the cache. if (layoutChanged || nextProps.forceRelayout) { this.debouncedCacheZoom.cancel(); this.zoomRestored = false; } if (!this.zoomRestored) { this.restoreCachedZoom(nextProps); } } render() { // Not passing transform into child components for perf reasons. const { panTranslateX, panTranslateY, zoomScale } = this.state; const transform = `translate(${panTranslateX}, ${panTranslateY}) scale(${zoomScale})`; const svgClassNames = this.props.isEmpty ? 'hide' : ''; const markerOffset = this.props.selectedNodeId ? '35' : '40'; const markerSize = this.props.selectedNodeId ? '10' : '30'; return (