diff --git a/the-graph/the-graph-app.js b/the-graph/the-graph-app.js index 08aa19642e811c336fdc5c1ea99b6b9906109d5b..c21d6f9470d4ebd609c6553688a7074bc4657391 100644 --- a/the-graph/the-graph-app.js +++ b/the-graph/the-graph-app.js @@ -167,6 +167,7 @@ module.exports.register = function (context) { onPanScale: null, onNodeSelection: null, onEdgeSelection: null, + getEditorRef: null, }; }, getInitialState: function() { @@ -424,6 +425,10 @@ module.exports.register = function (context) { this.hideContext(); }, componentDidMount: function () { + // make sure user side parent context can access methods defined here + if (this.props.getEditorRef !== undefined) { + this.props.getEditorRef.current = this; + } var domNode = ReactDOM.findDOMNode(this.refs.svg); // Unselect edges and nodes diff --git a/the-graph/the-graph-edge.js b/the-graph/the-graph-edge.js index 9d658061b85ebb47eb5a8c3e16d765150ea17033..ece77b909a96e9f6c7db61535d81e5a00d5709c7 100644 --- a/the-graph/the-graph-edge.js +++ b/the-graph/the-graph-edge.js @@ -79,7 +79,7 @@ module.exports.register = function (context) { mixins: [ TooltipMixin ], - componentWillMount: function() { + UNSAFE_componentWillMount: function() { }, componentDidMount: function () { var domNode = ReactDOM.findDOMNode(this); diff --git a/the-graph/the-graph-graph.js b/the-graph/the-graph-graph.js index 803b63b8cd42682f230172e015acfea2574b2919..bdf9bff23349781e36d8a1f0c61b182b035e6035 100644 --- a/the-graph/the-graph-graph.js +++ b/the-graph/the-graph-graph.js @@ -121,7 +121,7 @@ module.exports.register = function (context) { componentWillUnmount: function () { this.mounted = false; }, - componentWillReceiveProps: function(nextProps) { + UNSAFE_componentWillReceiveProps: function(nextProps) { this.subscribeGraph(this.props.graph, nextProps.graph); this.markDirty(); }, diff --git a/the-graph-nav/the-graph-nav.js b/the-graph-nav/the-graph-nav.js index 206975d0fc2b3efb89d18b2543830c1922cd740d..cdbcbd1b9e5f1fc60cafa0f105c32dd40b0d25f1 100644 --- a/the-graph-nav/the-graph-nav.js +++ b/the-graph-nav/the-graph-nav.js @@ -1,7 +1,9 @@ var React = require('react'); +const ReactDOM = require('react-dom'); var createReactClass = require('create-react-class'); -var Hammer = require('hammerjs'); +const Hammer = require('hammerjs'); +const hammerhacks = require('../the-graph/hammer.js'); var thumb = require('../the-graph-thumb/the-graph-thumb.js'); function calculateStyleFromTheme(theme) { @@ -20,19 +22,19 @@ function calculateStyleFromTheme(theme) { return style; } -function renderViewRectangle(context, viewrect, props) { +function renderViewRectangle(context, viewrect, style) { - context.clearRect(0, 0, props.width, props.height); - context.fillStyle = props.outsideFill; + context.clearRect(0, 0, style.width, style.height); + context.fillStyle = style.outsideFill; // Scaled view rectangle - var x = Math.round( (props.viewrectangle[0]/props.scale - props.thumbrectangle[0]) * props.thumbscale ); - var y = Math.round( (props.viewrectangle[1]/props.scale - props.thumbrectangle[1]) * props.thumbscale ); - var w = Math.round( props.viewrectangle[2] * props.thumbscale / props.scale ); - var h = Math.round( props.viewrectangle[3] * props.thumbscale / props.scale ); + var x = Math.round( (style.viewrectangle[0]/style.scale - style.thumbrectangle[0]) * style.thumbscale ); + var y = Math.round( (style.viewrectangle[1]/style.scale - style.thumbrectangle[1]) * style.thumbscale ); + var w = Math.round( style.viewrectangle[2] * style.thumbscale / style.scale ); + var h = Math.round( style.viewrectangle[3] * style.thumbscale / style.scale ); var hide = false; - if (x<0 && y<0 && w>props.width-x && h>props.height-y) { + if (x<0 && y<0 && w>style.width-x && h>style.height-y) { // Hide map hide = true; return { @@ -48,35 +50,35 @@ function renderViewRectangle(context, viewrect, props) { if (x < 0) { w += x; x = 0; - viewrect.style.borderLeftColor = props.viewBoxBorder2; + viewrect.style.borderLeftColor = style.viewBoxBorder2; } else { - viewrect.style.borderLeftColor = props.viewBoxBorder; - context.fillRect(0, 0, x, props.height); + viewrect.style.borderLeftColor = style.viewBoxBorder; + context.fillRect(0, 0, x, style.height); } // Top if (y < 0) { h += y; y = 0; - viewrect.style.borderTopColor = props.viewBoxBorder2; + viewrect.style.borderTopColor = style.viewBoxBorder2; } else { - viewrect.style.borderTopColor = props.viewBoxBorder; + viewrect.style.borderTopColor = style.viewBoxBorder; context.fillRect(x, 0, w, y); } // Right - if (w > props.width-x) { - w = props.width-x; - viewrect.style.borderRightColor = props.viewBoxBorder2; + if (w > style.width-x) { + w = style.width-x; + viewrect.style.borderRightColor = style.viewBoxBorder2; } else { - viewrect.style.borderRightColor = props.viewBoxBorder; - context.fillRect(x+w, 0, props.width-(x+w), props.height); + viewrect.style.borderRightColor = style.viewBoxBorder; + context.fillRect(x+w, 0, style.width-(x+w), style.height); } // Bottom - if (h > props.height-y) { - h = props.height-y; - viewrect.style.borderBottomColor = props.viewBoxBorder2; + if (h > style.height-y) { + h = style.height-y; + viewrect.style.borderBottomColor = style.viewBoxBorder2; } else { - viewrect.style.borderBottomColor = props.viewBoxBorder; - context.fillRect(x, y+h, w, props.height-(y+h)); + viewrect.style.borderBottomColor = style.viewBoxBorder; + context.fillRect(x, y+h, w, style.height-(y+h)); } // Size and translate rect @@ -139,8 +141,7 @@ var Component = createReactClass({ }, getInitialState: function() { return { - thumbscale: 1.0, - currentPan: [0.0, 0.0], + panStartPoint: [0.0, 0.0], }; }, render: function() { @@ -193,19 +194,17 @@ var Component = createReactClass({ ]); }, componentDidUpdate: function() { - this._updatePan(); this._renderElements(); }, componentDidMount: function() { - this._updatePan(); this._renderElements(); this._setupEvents(); }, _refThumbCanvas: function(canvas) { - this._thumbContext = canvas.getContext('2d'); + this._thumbContext = canvas?.getContext?.('2d'); }, _refViewboxCanvas: function(canvas) { - this._viewboxContext = canvas.getContext('2d'); + this._viewboxContext = canvas?.getContext?.('2d'); }, _refViewboxElement: function(el) { this._viewboxElement = el; @@ -218,40 +217,49 @@ var Component = createReactClass({ //this.state.thumbscale = t.scale; renderViewboxFromProps(this._viewboxContext, this._viewboxElement, t, this.props); }, - _updatePan: function() { - this.state.currentPan = [ - -(this.props.viewrectangle[0]), - -(this.props.viewrectangle[1]), - ]; + onDragOrPan: function ({ deltaX, deltaY }) { + if (this.props.onPanTo) { + // Calculate where event pans to, in editor coordinates + var x = this.state.panStartPoint[0]; + var y = this.state.panStartPoint[1]; + var panscale = 1 / this.props.viewscale; + const speedupFactorX = this.props.viewrectangle[2] / this.props.width * 2; + const speedupFactorY = this.props.viewrectangle[3] / this.props.height * 2; + x -= deltaX / panscale * speedupFactorX; + y -= deltaY / panscale * speedupFactorY; + var panTo = { x: Math.round(x), y: Math.round(y) }; + this.props.onPanTo(panTo, event); + } + }, + onTrackStart(event) { + this.state.panStartPoint[0] = -this.props.viewrectangle[0]; + this.state.panStartPoint[1] = -this.props.viewrectangle[1]; + this._topElement.addEventListener('panmove', this.onTrack); + this._topElement.addEventListener('panend', this.onTrackEnd); + }, + onTrack(event) { + this.onDragOrPan({ + deltaX: event.gesture.deltaX, + deltaY: event.gesture.deltaY, + }); + }, + onTrackEnd(event) { + // Don't click app (unselect) + event.stopPropagation(); + this._topElement.removeEventListener('panmove', this.onTrack); + this._topElement.removeEventListener('panend', this.onTrackEnd); }, _setupEvents: function() { this.hammer = new Hammer.Manager(this._topElement, { + domEvents: true, + inputClass: hammerhacks.Input, recognizers: [ - [ Hammer.Tap ], - [ Hammer.Pan, { direction: Hammer.DIRECTION_ALL } ], + [Hammer.Tap], + [Hammer.Pan, { direction: Hammer.DIRECTION_ALL, threshold: 5 }], ], }); - this.hammer.on('tap', (function(event) { - if (this.props.onTap) { - this.props.onTap(null, event); - } - }).bind(this)); - this.hammer.on('panmove', (function(event) { - if (this.props.onPanTo) { - // Calculate where event pans to, in editor coordinates - var x = this.state.currentPan[0]; - var y = this.state.currentPan[1]; - var panscale = this.state.thumbscale / this.props.viewscale; - x -= event.deltaX / panscale; - y -= event.deltaY / panscale; - var panTo = { x: Math.round(x), y: Math.round(y) }; - // keep track of the current pan, because prop/component update - // may be delayed, or never arrive. - this.state.currentPan[0] = panTo.x; - this.state.currentPan[1] = panTo.y; - this.props.onPanTo(panTo, event); - } - }).bind(this)); + this.hammer.on('tap', (event) => this.props.onTap(event)); + this._topElement.addEventListener('panstart', (event) => this.onTrackStart(event)); } });