-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduction to moveable api (resolves #214) #215
base: master
Are you sure you want to change the base?
Changes from 5 commits
41fecea
5f49580
cd4caea
1b63741
ff8ed17
365fcf0
538ee4c
6bbbdcb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,26 @@ | ||
export const MOVE_END = 'moveend'; | ||
const PREVENT_SELECT_CLASS = 'noselect'; | ||
|
||
export function moveableComponent({ view }) { | ||
export function moveableComponent({ view, staticMode = false }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not exactly a fan of passing |
||
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 }); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,17 +12,37 @@ export default Model.extend({ | |
userActivity: false, | ||
}, | ||
|
||
getProjection: function() { | ||
getProjection() { | ||
return this.manifesto() | ||
.getProjectionsFor(this.get('objectId'))[ | ||
this.get('currentProjection') || this.get('projection') || 0 | ||
]; | ||
}, | ||
|
||
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 }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if the better aproach here will not be to create just two functions: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this idea. It's makes more sense. |
||
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; | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,10 +11,14 @@ export default View.extend({ | |
'mouseover': 'setUserActivity', | ||
'mouseleave': 'unsetUserActivity', | ||
}, | ||
moveable: null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, We can initialize always using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. I need to stop doing that :). I think null doesn't make much sense. |
||
$img: null, | ||
|
||
initialize: function(options) { | ||
const isViewerMode = this.app.getState() === Const.State.VIEWER; | ||
|
||
this.overlay = options.overlay; | ||
this.moveable = moveableComponent({ view: this, staticMode: isViewerMode }); | ||
this.listenTo(this.model, 'change:scale', this.resize); | ||
this.render(); | ||
this.$img | ||
|
@@ -36,26 +40,29 @@ export default View.extend({ | |
.on('change:currentProjection', this.updateProjection, this) | ||
.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); | ||
if (!isViewerMode) { | ||
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() }); | ||
}); | ||
} | ||
}, | ||
|
||
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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I see where You're using this
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's a must! I've been thinking about something like this: function moveable({ view }) {}
function draggable({ view, handler }) {
onDrag(event) {
if (handler) {
handler.moveTo({ x, y });
event.preventDefault();
}
}
}
View.extend({
initialize() {
this.moveable = moveable({ view: this });
if (draggable) {
draggable({ view: this, handler: this.moveable });
}
}
}) What do you think? |
||
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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,16 @@ describe('Moveable component', () => { | |
viewInstance.remove(); | ||
} | ||
|
||
function mouseMoveTo(x, y) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to change this name to something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since drag and drop has the same events name wouldn't it be confusing ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So maybe somthing like |
||
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)'); | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, that it is not in scope of this PR but i'm thinking that maybe better name for the whole functionality will be
draggable
? What do You think?