Chromium Code Reviews| Index: elements/designer-selection/designer-selection.html |
| diff --git a/elements/designer-selection/designer-selection.html b/elements/designer-selection/designer-selection.html |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..06e788e2ae3e8ed6b4c4c6b024d4b419c746896c |
| --- /dev/null |
| +++ b/elements/designer-selection/designer-selection.html |
| @@ -0,0 +1,257 @@ |
| +<!doctype html> |
| +<html> |
| + <head> |
| + <link rel="import" href="../../../polymer/polymer.html"> |
| + <link rel="import" href="../../../neoprene/components/x-elements/x-template/x-template.html"> |
| + </head> |
| + <body> |
| + |
| + <dom-module id="designer-selection"> |
| + <style> |
| + designer-selection { |
| + display: block; |
| + position: absolute; |
| + box-sizing: border-box; |
| + } |
| + designer-selection > #bounds { |
| + position: absolute; |
| + top: 0; |
| + left: 0; |
| + right: 0; |
| + bottom: 0; |
| + background: rgba(128, 128, 255, .5); |
| + border: solid 1px #88f; |
|
imac
2015/02/05 03:18:33
do you want border-box here?
justinfagnani
2015/02/05 20:15:54
Done.
|
| + } |
| + designer-selection > .handle { |
| + position: absolute; |
| + box-sizing: border-box; |
| + width: 8px; |
| + height: 8px; |
| + border: solid 1px #88f; |
| + background: #fff; |
| + } |
| + designer-selection > .handle:hover { |
| + background: #88f; |
| + } |
| + designer-selection > #top { |
| + top: -4px; |
| + left: calc(50% - 4px); |
| + cursor: ns-resize; |
| + } |
| + designer-selection > #left { |
| + top: calc(50% - 4px); |
| + left: -4px; |
| + cursor: ew-resize; |
| + } |
| + designer-selection > #bottom { |
| + bottom: -4px; |
| + left: calc(50% - 4px); |
| + cursor: ns-resize; |
| + } |
| + designer-selection > #right { |
| + top: calc(50% - 4px); |
| + right: -4px; |
| + cursor: ew-resize; |
| + } |
| + designer-selection > #top_left { |
| + top: -4px; |
| + left: -4px; |
| + cursor: nwse-resize; |
| + } |
| + designer-selection > #top_right { |
| + top: -4px; |
| + right: -4px; |
| + cursor: nesw-resize; |
| + } |
| + designer-selection > #bottom_left { |
| + bottom: -4px; |
| + left: -4px; |
| + cursor: nesw-resize; |
| + } |
| + designer-selection > #bottom_right { |
| + bottom: -4px; |
| + right: -4px; |
| + cursor: nwse-resize; |
| + } |
| + </style> |
| + <template> |
| + <div id="bounds"></div> |
| + <template is="x-repeat" items="{{directions}}"> |
| + <div class="handle" id$="{{item.name}}"></div> |
| + </template> |
| + </template> |
| + </dom-module> |
| + |
| + <script type="text/javascript"> |
| + function ResizeDirection(name, x, y) { |
| + this.name = name; |
| + this.x = x; |
| + this.y = y; |
| + } |
| + |
| + ResizeDirection.prototype.toString = function() { |
| + return 'ResizeDirection(' + this.name + ', ' + this.x + ', ' + this.y + ')'; |
| + }; |
|
imac
2015/02/05 03:18:33
Yay!
justinfagnani
2015/02/05 20:15:54
Done.
|
| + |
| + ResizeDirection.prototype.locate = function(rect) { |
| + return { |
| + x: rect.left + rect.width * this.x, |
| + y: rect.top + rect.height * this.y |
| + }; |
| + }; |
| + |
| + ResizeDirection.prototype.resizesLeft = function() { |
| + return this.x == 0.0; |
| + }, |
| + |
| + ResizeDirection.prototype.resizesRight = function() { |
| + return this.x == 1.0; |
| + }, |
| + |
| + ResizeDirection.prototype.resizesTop = function() { |
| + return this.y == 0.0; |
| + }, |
| + |
| + ResizeDirection.prototype.resizesBottom = function() { |
| + return this.y == 1.0; |
| + }, |
| + |
| + (function () { |
| + var top = ResizeDirection.top = new ResizeDirection('top', 0.5, 0.0); |
| + var left = ResizeDirection.left = new ResizeDirection('left', 0.0, 0.5); |
| + var bottom = ResizeDirection.bottom = new ResizeDirection('bottom', 0.5, 1.0); |
| + var right = ResizeDirection.right = new ResizeDirection('right', 1.0, 0.5); |
| + var top_left = ResizeDirection.top_left = new ResizeDirection('top_left', 0.0, 0.0); |
| + var top_right = ResizeDirection.top_right = new ResizeDirection('top_right', 1.0, 0.0); |
| + var bottom_left = ResizeDirection.bottom_left = new ResizeDirection('bottom_left', 0.0, 1.0); |
| + var bottom_right = ResizeDirection.bottom_right = new ResizeDirection('bottom_right', 1.0, 1.0); |
|
imac
2015/02/05 03:18:33
these should probably be ALL_CAPS (constants), or
justinfagnani
2015/02/05 20:15:54
I'll do camel case, I don't find ALL_CAPS to conve
|
| + |
| + ResizeDirection.all_directions = [top, left, bottom, right, top_left, top_right, bottom_left, bottom_right]; |
| + ResizeDirection.width_height = [bottom, right, bottom_right]; |
| + })(); |
|
imac
2015/02/05 03:18:33
consider moving ResizeDirection out to a separate
justinfagnani
2015/02/05 20:15:54
Done.
|
| + |
| + Polymer({ |
| + is: 'designer-selection', |
| + |
| + created: function() { |
| + this._onMove = null; |
| + this._dragging = false; |
| + this._offsetX = null; |
| + this._offsetY = null; |
| + this._onMouseMove_bound = this._onMouseMove.bind(this); |
| + this._onMouseUp_bound = this._onMouseUp.bind(this); |
| + this._resizeDirection = null; |
| + }, |
| + |
| + ready: function() { |
| + this.directions = ResizeDirection.all_directions; |
| + }, |
| + |
| + listeners: { |
| + 'mousedown': '_onMouseDown' |
| + }, |
| + |
| + _onMouseDown: function(e) { |
| + if (e.target.id == 'bounds') { |
| + this._boundsDown(e); |
| + } else { |
| + this._handleDown(e); |
| + } |
| + }, |
| + |
| + _onMouseUp: function(e) { |
| + this._stopDrag(); |
| + }, |
| + |
| + _onMouseMove: function(e) { |
| + if (this._onMove != null) { |
|
imac
2015/02/05 03:18:33
this feels like it should be an assert
justinfagnani
2015/02/05 20:15:54
Done.
|
| + var deltaX = e.clientX - this._offsetX; |
| + var deltaY = e.clientY - this._offsetY; |
| + this._onMove(deltaX, deltaY); |
| + } |
| + }, |
| + |
| + // called for mousedown on the main bounding box div |
| + _boundsDown: function(e) { |
| + this.$.bounds.style.cursor = 'move'; |
|
imac
2015/02/05 03:18:33
wouldn't you want the cursor to always be this to
justinfagnani
2015/02/05 20:15:54
I'm not totally sure, you should also be able to c
|
| + this._startDrag(this._boundsMove, e.clientX - this.offsetLeft, e.clientY - this.offsetTop); |
| + }, |
| + |
| + // [x], and [y] are relative to the offset passed to _startDrag |
| + _boundsMove: function(x, y) { |
| + var event = new CustomEvent('designer-selection-resize', |
| + {detail: { |
| + left: x, |
| + top: y, |
| + width: this.offsetWidth, |
| + height: this.offsetHeight}}); |
| + this.dispatchEvent(event); |
| + }, |
| + |
| + // called for mousedown on one of the resize handle divs |
| + _handleDown: function(e) { |
|
imac
2015/02/05 03:18:33
_resizeDown/_resizeMove would be clearer, I think
justinfagnani
2015/02/05 20:15:54
_resizeHandleDown is the most clear!
imac
2015/02/06 20:26:31
Most clearerer!
justinfagnani
2015/02/06 23:46:39
Acknowledged.
|
| + var handle = e.target; |
| + var direction = this._resizeDirection = ResizeDirection[handle.id]; |
| + |
| + var boundsBounds = this.$.bounds.getBoundingClientRect(); |
|
imac
2015/02/05 03:18:33
http://vimeo.com/87712359
justinfagnani
2015/02/05 20:15:54
Acknowledged.
|
| + var handleBounds = handle.getBoundingClientRect(); |
| + |
| + var offsetLeft = direction.resizesLeft() |
| + ? 0 |
| + : boundsBounds.left + (e.clientX - handleBounds.left); |
|
imac
2015/02/05 03:18:33
I'm confused, why does the position of the handle
justinfagnani
2015/02/05 20:15:54
This prevents a jump on first move by the amount t
|
| + |
| + var offsetTop = direction.resizesTop() |
| + ? 0 |
| + : boundsBounds.top + (e.clientY - handleBounds.top); |
| + |
| + this._startDrag(this._handleMove, offsetLeft, offsetTop); |
| + }, |
| + |
| + _handleMove: function(x, y) { |
| + var direction = this._resizeDirection; |
| + |
| + var newWidth = |
| + direction.resizesLeft() ? this.offsetWidth + this.offsetLeft - x : |
|
imac
2015/02/05 03:18:33
Rather than having to calculate offsetLeft/Top eac
justinfagnani
2015/02/05 20:15:54
Yeah, this.offsetWidth + this.offsetLeft is what I
imac
2015/02/06 20:26:31
Hmm, I mean that you shouldn't need to refer to th
justinfagnani
2015/02/06 23:46:39
Yes, but I want to restructure this so I don't hav
|
| + direction.resizesRight() ? x : |
| + this.offsetWidth; |
| + |
| + var newHeight = |
| + direction.resizesTop() ? this.offsetHeight + this.offsetTop - y : |
| + direction.resizesBottom() ? y : |
| + this.offsetHeight; |
| + |
| + var newLeft = direction.resizesLeft() ? x : this.offsetLeft; |
| + var newTop = direction.resizesTop() ? y : this.offsetTop; |
| + |
| + var event = new CustomEvent('designer-selection-resize', |
| + {detail: { |
| + left: newLeft, |
| + top: newTop, |
| + width: newWidth, |
| + height: newHeight}}); |
| + this.dispatchEvent(event); |
| + |
| + }, |
| + |
| + _startDrag: function(onMove, offsetX, offsetY) { |
| + this._dragging = true; |
| + this._onMove = onMove; |
| + this._offsetX = offsetX; |
| + this._offsetY = offsetY; |
| + window.addEventListener('mouseup', this._onMouseUp_bound); |
| + window.addEventListener('mousemove', this._onMouseMove_bound); |
| + }, |
| + |
| + _stopDrag: function() { |
| + this._dragging = false; |
| + this._onMove = null; |
| + this._offsetX = null; |
| + this._offsetY = null; |
| + window.removeEventListener('mouseup', this._onMouseUp_bound); |
| + window.removeEventListener('mousemove', this._onMouseMove_bound); |
| + this.$.bounds.style.cursor = 'auto'; |
| + } |
| + }); |
| + </script> |
| + </body> |
| +</html> |