From 41fecea4ebbafb5219f9042baaa0e90609c9c525 Mon Sep 17 00:00:00 2001 From: cmwd Date: Mon, 13 Jun 2016 21:52:37 +0200 Subject: [PATCH 1/8] Introduction to moveable api (resolves #214) --- src/js/modules/plant/model.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/js/modules/plant/model.js b/src/js/modules/plant/model.js index 277fc57..faa1623 100644 --- a/src/js/modules/plant/model.js +++ b/src/js/modules/plant/model.js @@ -12,17 +12,34 @@ export default Model.extend({ userActivity: false, }, - getProjection: function() { - return this.manifesto() - .getProjectionsFor(this.get('objectId'))[ - this.get('currentProjection') || this.get('projection') || 0 - ]; + getProjection() { + return this.get('projections')[this.get('projection')]; }, - setProjection: function(at_) { + setProjection(at_) { const projections = this.get('projections'); let at = at_ > projections.length ? 0 : at_; at = at < 0 ? projections.length : at; this.set('projection', at); }, + + setPosX({ x, width }) { + this.set('x', x / width); + + return this; + }, + + getPosX({ width }) { + return width * this.get('x'); + }, + + setPosY({ y, height, width }) { + this.set('y', (y - (height / 2)) / width ); + + return this; + }, + + getPosY({ width, height }) { + return height / 2 + this.get('y') * width; + }, }); From 5f49580e5b43f9a76bcb47cbcfde85a9b927b4c4 Mon Sep 17 00:00:00 2001 From: cmwd Date: Mon, 13 Jun 2016 22:04:13 +0200 Subject: [PATCH 2/8] Add tests --- src/js/modules/components/moveable.js | 30 ++++++++++++++------ src/js/modules/plant/object.js | 16 +++++------ src/js/modules/plant/overlay.js | 11 +++---- test/component-movable-test.js | 41 ++++++++++++++++++++++----- 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/js/modules/components/moveable.js b/src/js/modules/components/moveable.js index 2fd3c38..3d79ac5 100644 --- a/src/js/modules/components/moveable.js +++ b/src/js/modules/components/moveable.js @@ -1,15 +1,26 @@ export const MOVE_END = 'moveend'; const PREVENT_SELECT_CLASS = 'noselect'; -export function moveableComponent({ view }) { +export function moveableComponent({ view, staticMode = false }) { const offset = {}; - const position = {}; + const position = { x: 0, y: 0 }; + + view.el.classList.add(PREVENT_SELECT_CLASS); + + function moveTo({ x, y }) { + position.x = x; + position.y = y; + view.el.style.transform = `translate3d(${x}px, ${y}px, 0)`; + } + + function getPosition() { + return position; + } function onMouseMove({ clientX, clientY }) { - position.x = clientX - offset.x; - position.y = clientY - offset.y; - view.el.style.transform = - `translate3d(${position.x}px, ${position.y}px, 0)`; + moveTo({ + x: clientX - offset.x, + y: clientY - offset.y }); } function onMouseUp() { @@ -26,6 +37,9 @@ export function moveableComponent({ view }) { document.addEventListener('mouseup', onMouseUp, false); } - view.delegate('mousedown', null, onMouseDown); - view.el.classList.add(PREVENT_SELECT_CLASS); + if (!staticMode) { + view.delegate('mousedown', null, onMouseDown); + } + + return Object.freeze({ moveTo, getPosition }); } diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index b4369cd..702d1fe 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -11,10 +11,12 @@ export default View.extend({ 'mouseover': 'setUserActivity', 'mouseleave': 'unsetUserActivity', }, + moveable: null, $img: null, initialize: function(options) { this.overlay = options.overlay; + this.moveable = moveableComponent({ view: this }); this.listenTo(this.model, 'change:scale', this.resize); this.render(); this.$img @@ -37,25 +39,23 @@ export default View.extend({ .on('change:layerIndex', this.setLayer, this); if (this.app.getState() !== Const.State.VIEWER) { - moveableComponent({ view: this }); this.on(MOVE_END, this.model.set, this.model); } }, render: function() { - const x = this.overlay.width() * this.model.get('x'); - const y = this.overlay.height() / 2 + this.model.get('y') * this.overlay.width(); + const x = this.model.getPosX({ width: this.overlay.width() }); + const y = this.model.getPosY({ + width: this.overlay.width(), + height: this.overlay.height() }); this.$el .html(this.template({ projectionUrl: this.model.getProjection(), })) .attr('data-cid', this.model.cid) - .css({ - zIndex: this.model.get('layerIndex'), - transform: `translate3d(${x}px, ${y}px, 0)`, - }); - + .css('zIndex', this.model.get('layerIndex')); + this.moveable.moveTo({ x, y }); this.$img = this.$el.children('img'); return this; diff --git a/src/js/modules/plant/overlay.js b/src/js/modules/plant/overlay.js index f239414..b6fa338 100644 --- a/src/js/modules/plant/overlay.js +++ b/src/js/modules/plant/overlay.js @@ -69,17 +69,14 @@ export default View.extend({ const $img = $container.children('img'); const height = $img.height(); const width = $img.width(); - const pos = $container.position(); - let top = pos.top; - const left = pos.left * scale; + const pos = object.moveable.getPosition(); + let top = pos.y; + const left = pos.x * scale; top = newH / 2 + (top - oldH / 2) * scale; $img.height(height * scale); $img.width(width * scale); - $container.css({ - top: top, - left: left, - }); + object.moveable.moveTo({ x: left, y: top}); }); this._width = newW; this._height = newH; diff --git a/test/component-movable-test.js b/test/component-movable-test.js index 64c1533..2ea41c9 100644 --- a/test/component-movable-test.js +++ b/test/component-movable-test.js @@ -22,6 +22,16 @@ describe('Moveable component', () => { viewInstance.remove(); } + function mouseMoveTo(x, y) { + viewInstance.el.dispatchEvent(createMouseEvent({ type: 'mousedown' })); + document.dispatchEvent(createMouseEvent({ + type: 'mousemove', + clientX: x, + clientY: y, + })); + document.dispatchEvent(createMouseEvent({ type: 'mouseup' })); + } + before(cb => environment.then((w) => { document = w.document; cb(); @@ -44,13 +54,30 @@ describe('Moveable component', () => { moveableComponent({ view: viewInstance }); viewInstance.on('moveend', spy); equal(spy.called, false); - viewInstance.el.dispatchEvent(createMouseEvent({ type: 'mousedown' })); - document.dispatchEvent(createMouseEvent({ - type: 'mousemove', - clientX: 100, - clientY: 100, - })); - document.dispatchEvent(createMouseEvent({ type: 'mouseup' })); + mouseMoveTo(100, 100); equal(spy.calledWithExactly({ x: 150, y: 150 }), true); }); + + describe('API', () => { + it('Should return actual position of the element', () => { + const api = moveableComponent({ view: viewInstance }); + + equal(api.getPosition().x, 0); + equal(api.getPosition().y, 0); + mouseMoveTo(100, 100); + equal(api.getPosition().x, 150); + equal(api.getPosition().y, 150); + }); + + it('Should set position to given coordinates', () => { + const api = moveableComponent({ view: viewInstance }); + + equal(api.getPosition().x, 0); + equal(api.getPosition().y, 0); + api.moveTo({ x: 150, y: 150 }); + equal(api.getPosition().x, 150); + equal(api.getPosition().y, 150); + equal(viewInstance.el.style.transform, 'translate3d(150px, 150px, 0)'); + }); + }); }); From cd4caea3c404fdb9ff5e5fcb1c1dae1173f4af67 Mon Sep 17 00:00:00 2001 From: cmwd Date: Mon, 13 Jun 2016 22:12:07 +0200 Subject: [PATCH 3/8] Initialize static mode in viewer mode --- src/js/modules/plant/model.js | 5 ++++- src/js/modules/plant/object.js | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/js/modules/plant/model.js b/src/js/modules/plant/model.js index faa1623..37d3c69 100644 --- a/src/js/modules/plant/model.js +++ b/src/js/modules/plant/model.js @@ -13,7 +13,10 @@ export default Model.extend({ }, getProjection() { - return this.get('projections')[this.get('projection')]; + return this.manifesto() + .getProjectionsFor(this.get('objectId'))[ + this.get('currentProjection') || this.get('projection') || 0 + ]; }, setProjection(at_) { diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index 702d1fe..e3ce26c 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -15,8 +15,10 @@ export default View.extend({ $img: null, initialize: function(options) { + const isViewerMode = this.app.getState() === Const.State.VIEWER; + this.overlay = options.overlay; - this.moveable = moveableComponent({ view: this }); + this.moveable = moveableComponent({ view: this, staticMode: isViewerMode }); this.listenTo(this.model, 'change:scale', this.resize); this.render(); this.$img @@ -38,7 +40,7 @@ export default View.extend({ .on('change:currentProjection', this.updateProjection, this) .on('change:layerIndex', this.setLayer, this); - if (this.app.getState() !== Const.State.VIEWER) { + if (!isViewerMode) { this.on(MOVE_END, this.model.set, this.model); } }, From 1b637411754c8a811aae02ba6484e877ef82ea1c Mon Sep 17 00:00:00 2001 From: cmwd Date: Tue, 14 Jun 2016 00:00:37 +0200 Subject: [PATCH 4/8] Fix position save --- src/js/modules/plant/object.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index e3ce26c..6fd6d55 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -41,7 +41,13 @@ export default View.extend({ .on('change:layerIndex', this.setLayer, this); if (!isViewerMode) { - this.on(MOVE_END, this.model.set, this.model); + this.on(MOVE_END, ({ x, y }) => { + this.model.setPosX({ x, width: this.overlay.width() }); + this.model.setPosY({ y, + width: this.overlay.width(), + height: this.overlay.height() }); + console.log(this.model.attributes); + }); } }, From ff8ed17c6c2d029a1f3fdff9247467c7123e6ec1 Mon Sep 17 00:00:00 2001 From: cmwd Date: Tue, 14 Jun 2016 00:01:01 +0200 Subject: [PATCH 5/8] Remove console.log --- src/js/modules/plant/object.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index 6fd6d55..dc73fc3 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -46,7 +46,6 @@ export default View.extend({ this.model.setPosY({ y, width: this.overlay.width(), height: this.overlay.height() }); - console.log(this.model.attributes); }); } }, From 365fcf07928e480f0fb88d1b69e87ac80bc55d8b Mon Sep 17 00:00:00 2001 From: cmwd Date: Wed, 15 Jun 2016 20:27:38 +0200 Subject: [PATCH 6/8] Fixes after code review --- src/js/modules/plant/model.js | 26 +++++++++++--------------- src/js/modules/plant/object.js | 12 ++++++------ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/js/modules/plant/model.js b/src/js/modules/plant/model.js index 37d3c69..a458584 100644 --- a/src/js/modules/plant/model.js +++ b/src/js/modules/plant/model.js @@ -26,23 +26,19 @@ export default Model.extend({ this.set('projection', at); }, - setPosX({ x, width }) { - this.set('x', x / width); + setPosition({ x, y, width, height }) { + const props = { + x: x / width, + y: (y - (height / 2)) / width, + }; - return this; + this.set(props); }, - getPosX({ width }) { - return width * this.get('x'); - }, - - setPosY({ y, height, width }) { - this.set('y', (y - (height / 2)) / width ); - - return this; - }, - - getPosY({ width, height }) { - return height / 2 + this.get('y') * width; + getPosition({ width, height }) { + return { + x: width * this.get('x'), + y: height / 2 + this.get('y') * width, + }; }, }); diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index dc73fc3..4a3ae46 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -42,19 +42,19 @@ export default View.extend({ if (!isViewerMode) { this.on(MOVE_END, ({ x, y }) => { - this.model.setPosX({ x, width: this.overlay.width() }); - this.model.setPosY({ y, + this.model.setPosition({ x, y, width: this.overlay.width(), - height: this.overlay.height() }); + height: this.overlay.height(), + }); }); } }, render: function() { - const x = this.model.getPosX({ width: this.overlay.width() }); - const y = this.model.getPosY({ + const { x, y } = this.model.getPosition({ width: this.overlay.width(), - height: this.overlay.height() }); + height: this.overlay.height(), + }); this.$el .html(this.template({ From 538ee4cfcce6c2d239365521b9d5b3a066a70a8c Mon Sep 17 00:00:00 2001 From: cmwd Date: Wed, 15 Jun 2016 20:45:59 +0200 Subject: [PATCH 7/8] Store container size inside model --- src/js/modules/plant/model.js | 21 +++++++++++++++++++-- src/js/modules/plant/object.js | 16 ++++------------ src/js/modules/plant/overlay.js | 3 +++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/js/modules/plant/model.js b/src/js/modules/plant/model.js index a458584..21f36dd 100644 --- a/src/js/modules/plant/model.js +++ b/src/js/modules/plant/model.js @@ -1,4 +1,5 @@ import { Model } from '../../core'; +import { Model as BModel } from 'backbone'; export default Model.extend({ defaults: { @@ -11,6 +12,15 @@ export default Model.extend({ height: 0, userActivity: false, }, + container: undefined, + + constructor({ containerWidth, containerHeight, ...props }, options) { + this.container = new BModel({ + width: containerWidth, + height: containerHeight }); + + return Model.call(this, props, options); + }, getProjection() { return this.manifesto() @@ -26,7 +36,12 @@ export default Model.extend({ this.set('projection', at); }, - setPosition({ x, y, width, height }) { + setContainerSize({ width, height }) { + this.container.set({ width, height }); + }, + + setPosition({ x, y }) { + const { width, height } = this.container.attributes; const props = { x: x / width, y: (y - (height / 2)) / width, @@ -35,7 +50,9 @@ export default Model.extend({ this.set(props); }, - getPosition({ width, height }) { + getPosition() { + const { width, height } = this.container.attributes; + return { x: width * this.get('x'), y: height / 2 + this.get('y') * width, diff --git a/src/js/modules/plant/object.js b/src/js/modules/plant/object.js index 4a3ae46..4fde28f 100644 --- a/src/js/modules/plant/object.js +++ b/src/js/modules/plant/object.js @@ -11,8 +11,8 @@ export default View.extend({ 'mouseover': 'setUserActivity', 'mouseleave': 'unsetUserActivity', }, - moveable: null, - $img: null, + moveable: undefined, + $img: undefined, initialize: function(options) { const isViewerMode = this.app.getState() === Const.State.VIEWER; @@ -41,20 +41,12 @@ export default View.extend({ .on('change:layerIndex', this.setLayer, this); if (!isViewerMode) { - this.on(MOVE_END, ({ x, y }) => { - this.model.setPosition({ x, y, - width: this.overlay.width(), - height: this.overlay.height(), - }); - }); + this.on(MOVE_END, this.model.setPosition, this.model); } }, render: function() { - const { x, y } = this.model.getPosition({ - width: this.overlay.width(), - height: this.overlay.height(), - }); + const { x, y } = this.model.getPosition(); this.$el .html(this.template({ diff --git a/src/js/modules/plant/overlay.js b/src/js/modules/plant/overlay.js index b6fa338..22d00be 100644 --- a/src/js/modules/plant/overlay.js +++ b/src/js/modules/plant/overlay.js @@ -76,6 +76,7 @@ export default View.extend({ top = newH / 2 + (top - oldH / 2) * scale; $img.height(height * scale); $img.width(width * scale); + object.model.setContainerSize({ width: newW, height: newH }); object.moveable.moveTo({ x: left, y: top}); }); this._width = newW; @@ -87,6 +88,8 @@ export default View.extend({ const newModel = lodash.extend(model, { x: ui.position.left / this.width(), y: (ui.position.top - (this.height() / 2)) / this.width(), + containerWidth: this.width(), + containerHeight: this.height(), }); this.collection.add(newModel, { From 6bbbdcbdc04aa3ca7b7c92ead662f4b0699f2588 Mon Sep 17 00:00:00 2001 From: cmwd Date: Sat, 18 Jun 2016 22:28:20 +0200 Subject: [PATCH 8/8] Fix plant position in viewer --- src/js/modules/plant/overlay.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/modules/plant/overlay.js b/src/js/modules/plant/overlay.js index 22d00be..6c20dcd 100644 --- a/src/js/modules/plant/overlay.js +++ b/src/js/modules/plant/overlay.js @@ -38,6 +38,7 @@ export default View.extend({ }, addObject: function(model) { + model.setContainerSize({ width: this._width, height: this._height }); const newObject = new PlantViewObject({ model: model, app: this.app,