diff --git a/CHANGES.md b/CHANGES.md index 378cfa8c..2ee6947e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,21 @@ ## dev +## 0.10.0 (unreleased) + +Breaking changes + +* Polymer element `the-graph-thumb` has been removed. +Should instead use the JavaScript API `TheGraph.thumb.render()`, +as shown in `examples/demo-thumbnail.html`. +* Polymer element `the-graph-nav` has been removed. +Should instead use the new React component `TheGraph.nav.Component`, +as shown in `examples/demo-full.html` + +Internal changes + +* All dependencies except Polymer (deprecated) are installed via NPM +* Some more modules have been converted to proper CommonJS + ## 0.9.0 (2017 May 6) New features diff --git a/examples/demo-full.html b/examples/demo-full.html index 1f293de3..7ceb963e 100644 --- a/examples/demo-full.html +++ b/examples/demo-full.html @@ -18,7 +18,6 @@ - @@ -76,7 +75,7 @@ theme="dark"> - +
@@ -113,22 +112,40 @@ // Remove loading message var loading = document.getElementById("loading"); loading.parentNode.removeChild(loading); + + renderNav(); }); // Attach nav - var nav = document.getElementById('nav'); - editor.addEventListener('viewchanged', function(e) { - nav.view = e.detail; - }); - nav.addEventListener('panto', function(e) { - var pan = e.detail; + function fitGraphInView() { + editor.triggerFit(); + } + function panEditorTo(pan) { editor.pan[0] = pan.x; editor.pan[1] = pan.y; - }); - nav.addEventListener('tap', function() { - editor.triggerFit(); - }); - + } + function renderNav() { + var props = { + height: 162, + width: 216, + graph: editor.graph, + onTap: fitGraphInView, + onPanTo: panEditorTo, + viewrectangle: [ + -editor.pan[0], + -editor.pan[1], + editor.width, + editor.height + ], + viewscale: editor.scale, + }; + + var element = React.createElement(TheGraph.nav.Component, props); + ReactDOM.render(element, document.getElementById('nav')); + } + editor.graph.on('endTransaction', renderNav); // graph changed + editor.addEventListener('viewchanged', renderNav); // editor viewport changed + // Simulate a library update setTimeout(function () { var originalComponent = editor.getComponent('core/Split'); @@ -206,7 +223,6 @@ document.getElementById("theme").addEventListener("click", function () { theme = (theme==="dark" ? "light" : "dark"); editor.theme = theme; - nav.theme = theme; }); // Focus a node diff --git a/examples/demo-thumbnail.html b/examples/demo-thumbnail.html index c7eb36c2..6717494f 100644 --- a/examples/demo-thumbnail.html +++ b/examples/demo-thumbnail.html @@ -1,36 +1,42 @@ - the-graph-thumb documentation + the-graph-thumb example - - - - - + diff --git a/spec/runner.html b/spec/runner.html index 0356d283..64938c72 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -50,8 +50,6 @@ theme="dark"> - - diff --git a/the-graph-nav/the-graph-nav.html b/the-graph-nav/the-graph-nav.html deleted file mode 100644 index c40d0419..00000000 --- a/the-graph-nav/the-graph-nav.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - diff --git a/the-graph-nav/the-graph-nav.js b/the-graph-nav/the-graph-nav.js index 7c3e0a25..275f8ee7 100644 --- a/the-graph-nav/the-graph-nav.js +++ b/the-graph-nav/the-graph-nav.js @@ -1,4 +1,6 @@ +var thumb = require('../the-graph-thumb/the-graph-thumb.js'); + function calculateStyleFromTheme(theme) { var style = {}; if (theme === "dark") { @@ -86,7 +88,175 @@ function renderViewRectangle(context, viewrect, props) { } +function renderThumbnailFromProps(context, props) { + var style = {}; + for (var name in props) { + style[name] = props[name]; + } + style.graph = null; + style.lineWidth = props.nodeLineWidth; + var info = thumb.render(context, props.graph, style); + return info; +} +function renderViewboxFromProps(context, viewbox, thumbInfo, props) { + var style = {}; + for (var name in props) { + style[name] = props[name]; + } + style.graph = null; + style.scale = props.viewscale; + var thumbW = thumbInfo.rectangle[2]; + var thumbH = thumbInfo.rectangle[3]; + style.thumbscale = (thumbW>thumbH) ? props.width/thumbW : props.height/thumbH; + style.thumbrectangle = thumbInfo.rectangle; + var info = renderViewRectangle(context, viewbox, style); + return info; +} + +// https://toddmotto.com/react-create-class-versus-component/ +var Component = React.createClass({ + propTypes: { + }, + getDefaultProps: function() { + return { + width: 200, + height: 150, + hidden: false, // FIXME: drop?? + backgroundColor: "hsla(184, 8%, 75%, 0.9)", + outsideFill: "hsla(0, 0%, 0%, 0.4)", + nodeSize: 60, + nodeLineWidth: 1, + viewrectangle: [0, 0, 0, 0], + viewscale: 1.0, + viewBoxBorder: "hsla(190, 100%, 80%, 0.4)", + viewBoxBorder2: "hsla( 10, 60%, 32%, 0.3)", + viewBoxBorderStyle: 'dotted', + graph: null, // NOTE: should not attach to events, that is responsibility of outer code + }; + }, + getInitialState: function() { + return { + thumbscale: 1.0, + currentPan: [0.0, 0.0], + }; + }, + render: function() { + var p = this.props; + var thumbStyle = { + position: 'absolute', + top: 0, + left: 0, + }; + var wrapperStyle = { + height: p.height, + width: p.width, + overflow: "hidden", + cursor: "move", + backgroundColor: p.backgroundColor, + }; + var thumbProps = { + key: 'thumb', + ref: this._refThumbCanvas, + width: p.width, + height: p.height, + style: thumbStyle, + }; + var viewboxCanvas = { + key: 'viewbox', + ref: this._refViewboxCanvas, + width: p.width, + height: p.height, + style: thumbStyle, + }; + // FIXME: find better way to populate the props from render function + var viewboxDiv = { + key: 'viewboxdiv', + ref: this._refViewboxElement, + style: { + position: 'absolute', + top: 0, + left: 0, + width: p.width, + height: p.height, + borderStyle: 'dotted', + borderWidth: 1, + }, + }; + // Elements + var d = React.DOM; + return d.div( { key: 'nav', style: wrapperStyle, ref: this._refTopElement }, [ + d.div( viewboxDiv ), + d.canvas( viewboxCanvas ), + d.canvas( thumbProps ), + ]); + }, + componentDidUpdate: function() { + this._updatePan(); + this._renderElements(); + }, + componentDidMount: function() { + this._updatePan(); + this._renderElements(); + this._setupEvents(); + }, + _refThumbCanvas: function(canvas) { + this._thumbContext = canvas.getContext('2d'); + }, + _refViewboxCanvas: function(canvas) { + this._viewboxContext = canvas.getContext('2d'); + }, + _refViewboxElement: function(el) { + this._viewboxElement = el; + }, + _refTopElement: function(el) { + this._topElement = el; + }, + _renderElements: function() { + var t = renderThumbnailFromProps(this._thumbContext, this.props); + //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]), + ]; + }, + _setupEvents: function() { + this.hammer = new Hammer.Manager(this._topElement, { + recognizers: [ + [ Hammer.Tap ], + [ Hammer.Pan, { direction: Hammer.DIRECTION_ALL } ], + ], + }); + 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; + console.log('panmove', event.deltaX, event.deltaY, 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)); + } +}); + + module.exports = { render: renderViewRectangle, calculateStyleFromTheme: calculateStyleFromTheme, + Component: Component, }; diff --git a/the-graph-thumb/the-graph-thumb.html b/the-graph-thumb/the-graph-thumb.html deleted file mode 100644 index 3623a2bd..00000000 --- a/the-graph-thumb/the-graph-thumb.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - -