diff --git a/client/app/scripts/components/zoomable-canvas.js b/client/app/scripts/components/zoomable-canvas.js
index 205b4f2c1..1f5264795 100644
--- a/client/app/scripts/components/zoomable-canvas.js
+++ b/client/app/scripts/components/zoomable-canvas.js
@@ -1,14 +1,15 @@
import React from 'react';
import { connect } from 'react-redux';
-import { debounce, pick } from 'lodash';
+import { clamp, debounce, pick } from 'lodash';
import { fromJS } from 'immutable';
+import { drag } from 'd3-drag';
import { event as d3Event, select } from 'd3-selection';
-import { zoom, zoomIdentity } from 'd3-zoom';
import Logo from '../components/logo';
import ZoomControl from '../components/zoom-control';
import { cacheZoomState } from '../actions/app-actions';
+import { zoomFactor } from '../utils/zoom-utils';
import { transformToString } from '../utils/transform-utils';
import { activeTopologyZoomCacheKeyPathSelector } from '../selectors/zooming';
import {
@@ -19,6 +20,15 @@ import {
import { ZOOM_CACHE_DEBOUNCE_INTERVAL } from '../constants/timer';
+const transformF = ({ x, y }, t) => ({
+ x: t.translateX + (t.scaleX * x),
+ y: t.translateY + (t.scaleY * y),
+});
+
+const inverseTransform = ({ x, y }, t) => ({
+ x: (x - t.translateX) / t.scaleX,
+ y: (y - t.translateY) / t.scaleY,
+});
class ZoomableCanvas extends React.Component {
constructor(props, context) {
@@ -40,27 +50,26 @@ class ZoomableCanvas extends React.Component {
this.debouncedCacheZoom = debounce(this.cacheZoom.bind(this), ZOOM_CACHE_DEBOUNCE_INTERVAL);
this.handleZoomControlAction = this.handleZoomControlAction.bind(this);
this.canChangeZoom = this.canChangeZoom.bind(this);
- this.zoomed = this.zoomed.bind(this);
+ this.handleZoom = this.handleZoom.bind(this);
+ this.handlePan = this.handlePan.bind(this);
}
componentDidMount() {
this.zoomRestored = false;
- this.zoom = zoom().on('zoom', this.zoomed);
this.svg = select('svg#canvas');
+ this.drag = drag().on('drag', this.handlePan);
+ this.svg.call(this.drag);
- this.setZoomTriggers(!this.props.disabled);
this.updateZoomLimits(this.props);
this.restoreZoomState(this.props);
}
componentWillUnmount() {
- this.setZoomTriggers(false);
this.debouncedCacheZoom.cancel();
}
componentWillReceiveProps(nextProps) {
const layoutChanged = nextProps.layoutId !== this.props.layoutId;
- const disabledChanged = nextProps.disabled !== this.props.disabled;
// If the layout has changed (either active topology or its options) or
// relayouting has been requested, stop pending zoom caching event and
@@ -70,11 +79,6 @@ class ZoomableCanvas extends React.Component {
this.zoomRestored = false;
}
- // If the zooming has been enabled/disabled, update its triggers.
- if (disabledChanged) {
- this.setZoomTriggers(!nextProps.disabled);
- }
-
this.updateZoomLimits(nextProps);
if (!this.zoomRestored) {
this.restoreZoomState(nextProps);
@@ -83,14 +87,12 @@ class ZoomableCanvas extends React.Component {
handleZoomControlAction(scale) {
// Update the canvas scale (not touching the translation).
- this.svg.call(this.zoom.scaleTo, scale);
-
- // Update the scale state and propagate to the global cache.
- this.setState(this.cachableState({
- scaleX: scale,
- scaleY: scale,
- }));
- this.debouncedCacheZoom();
+ const { top, bottom, left, right } = this.svg.node().getBoundingClientRect();
+ const centerOfCanvas = {
+ x: (left + right) / 2,
+ y: (top + bottom) / 2,
+ };
+ this.zoomAtPosition(centerOfCanvas, scale / this.state.scaleX);
}
render() {
@@ -103,7 +105,9 @@ class ZoomableCanvas extends React.Component {
return (
-