[Fixed Position] Add ability to work in pixel space

Fix code style issues per Victor's review

Add toggle to work in pixel space or grid space, per the issue description.
Each element stores a boolean property that determines whether or not it
snaps to grid space or pixel space. Coordinates are converted between spaces
on toggle, preserving the size of the element in pixels.

To complete: change UI element for toggle to a checkbox.
This commit is contained in:
Aaron Doubek-Kraft 2017-06-28 12:37:14 -07:00
parent 825f50262c
commit b9ab97eb7f
13 changed files with 178 additions and 36 deletions

View File

@ -177,7 +177,7 @@ define([
"name": "Y1",
"cssClass": "l-input-sm",
"control" : "numberfield",
"min": 0
"min": "0"
},
{
"property": "editX2",
@ -212,6 +212,21 @@ define([
"control": "numberfield",
"description": "Resize object width",
"min": "1"
},
{
"method": "setUnits",
"name": "Units",
"control": "menu-button",
"options": [
{
"name": "px",
"key": "px"
},
{
"name": "grid",
"key": "grid"
}
]
}
]
},

View File

@ -19,12 +19,12 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<svg ng-attr-width="{{parameters.gridSize[0] * ngModel.width()}}"
ng-attr-height="{{parameters.gridSize[1] * ngModel.height()}}">
<line ng-attr-x1="{{parameters.gridSize[0] * ngModel.x1() + 1}}"
ng-attr-y1="{{parameters.gridSize[1] * ngModel.y1() + 1}}"
ng-attr-x2="{{parameters.gridSize[0] * ngModel.x2() + 1}}"
ng-attr-y2="{{parameters.gridSize[1] * ngModel.y2() + 1}}"
<svg ng-attr-width="{{ngModel.getGridSize()[0] * ngModel.width()}}"
ng-attr-height="{{ngModel.getGridSize()[1] * ngModel.height()}}">
<line ng-attr-x1="{{ngModel.getGridSize()[0] * ngModel.x1() + 1}}"
ng-attr-y1="{{ngModel.getGridSize()[1] * ngModel.y1() + 1}}"
ng-attr-x2="{{ngModel.getGridSize()[0] * ngModel.x2() + 1}}"
ng-attr-y2="{{ngModel.getGridSize()[1] * ngModel.y2() + 1}}"
ng-attr-stroke="{{ngModel.stroke()}}"
stroke-width="2">
</line>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -75,7 +75,7 @@ define(
// Convert from element x/y/width/height to an
// appropriate ng-style argument, to position elements.
function convertPosition(elementProxy) {
var gridSize = self.gridSize;
var gridSize = elementProxy.getGridSize();
// Multiply position/dimensions by grid size
return {
left: (gridSize[0] * elementProxy.x()) + 'px',
@ -114,6 +114,7 @@ define(
self.gridSize = layoutGrid;
self.elementProxies.forEach(function (elementProxy) {
elementProxy.setGridSize(self.gridSize);
elementProxy.style = convertPosition(elementProxy);
});
}
@ -121,7 +122,7 @@ define(
// Decorate an element for display
function makeProxyElement(element, index, elements) {
var ElementProxy = ElementProxies[element.type],
e = ElementProxy && new ElementProxy(element, index, elements);
e = ElementProxy && new ElementProxy(element, index, elements, self.gridSize);
if (e) {
// Provide a displayable position (convert from grid to px)
@ -254,7 +255,8 @@ define(
color: "",
titled: true,
width: DEFAULT_DIMENSIONS[0],
height: DEFAULT_DIMENSIONS[1]
height: DEFAULT_DIMENSIONS[1],
useGrid: true
});
//Re-initialize objects, and subscribe to new object
@ -518,4 +520,3 @@ define(
return FixedController;
}
);

View File

@ -47,9 +47,10 @@ define(
* @memberof platform/features/layout.FixedDragHandle#
*/
FixedDragHandle.prototype.style = function () {
var gridSize = this.elementHandle.getGridSize();
// Adjust from grid to pixel coordinates
var x = this.elementHandle.x() * this.gridSize[0],
y = this.elementHandle.y() * this.gridSize[1];
var x = this.elementHandle.x() * gridSize[0],
y = this.elementHandle.y() * gridSize[1];
// Convert to a CSS style centered on that point
return {
@ -78,13 +79,14 @@ define(
* started
*/
FixedDragHandle.prototype.continueDrag = function (delta) {
var gridSize = this.elementHandle.getGridSize();
if (this.dragging) {
// Update x/y positions (snapping to grid)
this.elementHandle.x(
this.dragging.x + Math.round(delta[0] / this.gridSize[0])
this.dragging.x + Math.round(delta[0] / gridSize[0])
);
this.elementHandle.y(
this.dragging.y + Math.round(delta[1] / this.gridSize[1])
this.dragging.y + Math.round(delta[1] / gridSize[1])
);
// Invoke update callback
if (this.update) {

View File

@ -61,6 +61,7 @@ define(
element.width = element.width || 1;
element.height = element.height || 1;
element.type = type;
element.useGrid = true;
// Finally, add it to the view's configuration
addElementCallback(element);

View File

@ -37,10 +37,11 @@ define(
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @param {Array} elements the full array of elements
*/
function BoxProxy(element, index, elements) {
var proxy = new ElementProxy(element, index, elements);
function BoxProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize);
/**
* Get/set this element's fill color. (Omitting the

View File

@ -32,6 +32,10 @@ define(
bottom: Number.NEGATIVE_INFINITY
};
// Mininmum pixel height and width for objects
var MIN_WIDTH = 10;
var MIN_HEIGHT = 10;
// Ensure a value is non-negative (for x/y setters)
function clamp(value) {
return Math.max(value, 0);
@ -51,17 +55,29 @@ define(
* @param element the fixed position element, as stored in its
* configuration
* @param index the element's index within its array
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @param {Array} elements the full array of elements
*/
function ElementProxy(element, index, elements) {
this.resizeHandles = [new ResizeHandle(element, 1, 1)];
function ElementProxy(element, index, elements, gridSize) {
/**
* The element as stored in the view configuration.
* @memberof platform/features/layout.ElementProxy#
*/
this.element = element;
/**
* The current grid size of the layout.
* @memberof platform/features/layout.ElementProxy#
*/
this.gridSize = gridSize;
this.resizeHandles = [new ResizeHandle(
this.element,
this.getMinWidth(),
this.getMinHeight(),
this.getGridSize()
)];
/**
* Get and/or set the x position of this element.
* Units are in fixed position grid space.
@ -108,6 +124,7 @@ define(
this.index = index;
this.elements = elements;
this.useGrid = element.useGrid;
}
/**
@ -156,6 +173,95 @@ define(
return this.resizeHandles;
};
/**
* Set whether this elements's position is determined in terms of grid
* units or pixels.
* @param {string} key Which unit to use, px or grid
*/
ElementProxy.prototype.setUnits = function (key) {
if (key === 'px' && this.element.useGrid === true) {
this.element.useGrid = false;
this.convertCoordsTo('px');
} else if (key === 'grid' && this.element.useGrid === false) {
this.element.useGrid = true;
this.convertCoordsTo('grid');
}
};
/**
* Convert this element's coordinates and size from pixels to grid units,
* or vice-versa.
* @param {string} unit When called with 'px', converts grid units to
* pixels; when called with 'grid', snaps element
* to grid units
*/
ElementProxy.prototype.convertCoordsTo = function (unit) {
var gridSize = this.gridSize;
var element = this.element;
var minWidth = this.getMinWidth();
var minHeight = this.getMinHeight();
if (unit === 'px') {
element.x = element.x * gridSize[0];
element.y = element.y * gridSize[1];
element.width = element.width * gridSize[0];
element.height = element.height * gridSize[1];
if (element.x2 && element.y2) {
element.x2 = element.x2 * gridSize[0];
element.y2 = element.y2 * gridSize[1];
}
} else if (unit === 'grid') {
element.x = Math.round(element.x / gridSize[0]);
element.y = Math.round(element.y / gridSize[1]);
element.width = Math.max(Math.round(element.width / gridSize[0]), minWidth);
element.height = Math.max(Math.round(element.height / gridSize[1]), minHeight);
if (element.x2 && element.y2) {
element.x2 = Math.round(element.x2 / gridSize[0]);
element.y2 = Math.round(element.y2 / gridSize[1]);
}
}
};
/**
* Returns which grid size the element is currently using.
* @return {number[]} The current grid size in [x,y] form if the element
* is currently using the grid, [1,1] if it is using
* pixels.
*/
ElementProxy.prototype.getGridSize = function () {
var gridSize;
if (this.element.useGrid) {
gridSize = this.gridSize;
} else {
gridSize = [1,1];
}
return gridSize;
};
/**
* Set the current grid size stored by this element proxy
* @param {number[]} gridSize The current layout grid size in [x,y] form
*/
ElementProxy.prototype.setGridSize = function (gridSize) {
this.gridSize = gridSize;
};
/**
* Get the current minimum element width in grid units
* @return {number} The current minimum element width
*/
ElementProxy.prototype.getMinWidth = function () {
return Math.ceil(MIN_WIDTH / this.getGridSize()[0]);
};
/**
* Get the current minimum element height in grid units
* @return {number} The current minimum element height
*/
ElementProxy.prototype.getMinHeight = function () {
return Math.ceil(MIN_HEIGHT / this.getGridSize()[1]);
};
return ElementProxy;
}
);

View File

@ -36,10 +36,11 @@ define(
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function ImageProxy(element, index, elements) {
var proxy = new ElementProxy(element, index, elements);
function ImageProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize);
/**
* Get and/or set the displayed text of this element.

View File

@ -35,14 +35,16 @@ define(
* @param {string} yProperty field which stores x position
* @param {string} xOther field which stores x of other end
* @param {string} yOther field which stores y of other end
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @implements {platform/features/layout.ElementHandle}
*/
function LineHandle(element, xProperty, yProperty, xOther, yOther) {
function LineHandle(element, xProperty, yProperty, xOther, yOther, gridSize) {
this.element = element;
this.xProperty = xProperty;
this.yProperty = yProperty;
this.xOther = xOther;
this.yOther = yOther;
this.gridSize = gridSize;
}
LineHandle.prototype.x = function (value) {
@ -83,6 +85,10 @@ define(
return element[yProperty];
};
LineHandle.prototype.getGridSize = function () {
return this.gridSize;
};
return LineHandle;
}

View File

@ -21,8 +21,8 @@
*****************************************************************************/
define(
['./ElementProxy', './LineHandle','./AccessorMutator'],
function (ElementProxy, LineHandle,AccessorMutator) {
['./ElementProxy', './LineHandle', './AccessorMutator'],
function (ElementProxy, LineHandle, AccessorMutator) {
/**
* Selection/diplay proxy for line elements of a fixed position
@ -33,13 +33,14 @@ define(
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function LineProxy(element, index, elements) {
var proxy = new ElementProxy(element, index, elements),
function LineProxy(element, index, elements, gridSize) {
var proxy = new ElementProxy(element, index, elements, gridSize),
handles = [
new LineHandle(element, 'x', 'y', 'x2', 'y2'),
new LineHandle(element, 'x2', 'y2', 'x', 'y')
new LineHandle(element, 'x', 'y', 'x2', 'y2', proxy.getGridSize()),
new LineHandle(element, 'x2', 'y2', 'x', 'y', proxy.getGridSize())
];
/**

View File

@ -35,12 +35,14 @@ define(
* @memberof platform/features/layout
* @constructor
*/
function ResizeHandle(element, minWidth, minHeight) {
function ResizeHandle(element, minWidth, minHeight, gridSize) {
this.element = element;
// Ensure reasonable defaults
this.minWidth = minWidth || 0;
this.minHeight = minHeight || 0;
this.gridSize = gridSize;
}
ResizeHandle.prototype.x = function (value) {
@ -65,6 +67,10 @@ define(
return element.y + element.height;
};
ResizeHandle.prototype.getGridSize = function () {
return this.gridSize;
};
return ResizeHandle;
}

View File

@ -21,8 +21,8 @@
*****************************************************************************/
define(
['./TextProxy','./AccessorMutator'],
function (TextProxy,AccessorMutator) {
['./TextProxy'],
function (TextProxy) {
// Method names to expose from this proxy
var HIDE = 'hideTitle', SHOW = 'showTitle';
@ -39,10 +39,11 @@ define(
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] form
* @augments {platform/features/layout.ElementProxy}
*/
function TelemetryProxy(element, index, elements) {
var proxy = new TextProxy(element, index, elements);
function TelemetryProxy(element, index, elements, gridSize) {
var proxy = new TextProxy(element, index, elements, gridSize);
// Toggle the visibility of the title
function toggle() {

View File

@ -36,10 +36,11 @@ define(
* configuration
* @param index the element's index within its array
* @param {Array} elements the full array of elements
* @param {number[]} gridSize the current layout grid size in [x,y] from
* @augments {platform/features/layout.ElementProxy}
*/
function TextProxy(element, index, elements) {
var proxy = new BoxProxy(element, index, elements);
function TextProxy(element, index, elements, gridSize) {
var proxy = new BoxProxy(element, index, elements, gridSize);
/**
* Get and/or set the text color of this element.