Skip to content

Commit

Permalink
Merge pull request #795 from OpenGeoscience/widget-tests
Browse files Browse the repository at this point in the history
Add tests for geo.gui.widget and geo.gui.domWidget.
  • Loading branch information
manthey authored Mar 21, 2018
2 parents 213a0c3 + 2f41fae commit 63f796b
Show file tree
Hide file tree
Showing 12 changed files with 445 additions and 183 deletions.
1 change: 0 additions & 1 deletion src/d3/d3Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ var d3Renderer = function (arg) {

/**
* Set the translation, scale, and zoom for the current view.
* @note rotation not yet supported
* @private
*/
this._setTransform = function () {
Expand Down
19 changes: 16 additions & 3 deletions src/ui/domWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ var widget = require('./widget');
var inherit = require('../inherit');
var registerWidget = require('../registry').registerWidget;

/**
* Create a new instance of class domWidget.
*
* @class
* @alias geo.gui.domWidget
* @extends geo.gui.widget
* @param {object} arg
* @param {geo.widget} [parent] A parent widget for this widget.
* @param {string} [el='div'] The type of DOM element to create.
* @returns {geo.domWidget}
*/
var domWidget = function (arg) {
'use strict';
if (!(this instanceof domWidget)) {
Expand All @@ -17,25 +28,27 @@ var domWidget = function (arg) {
* Initializes DOM Widget.
* Sets the canvas for the widget, does parent/child relationship management,
* appends it to it's parent and handles any positioning logic.
*
* @returns {this}
*/
this._init = function () {
if (arg.hasOwnProperty('parent')) {
arg.parent.addChild(m_this);
}

m_this._createCanvas();
m_this._appendChild();
m_this._appendCanvasToParent();

m_this.canvas().addEventListener('mousedown', function (e) {
e.stopPropagation();
});

m_this.reposition();
return m_this;
};

/**
* Creates the widget canvas.
* This is just a simple DOM element (based on args.el, or defaults to a div)
* Creates the widget canvas. This is a DOM element (`arg.el` or a div).
*/
this._createCanvas = function () {
m_this.canvas(document.createElement(arg.el || m_default_canvas));
Expand Down
8 changes: 3 additions & 5 deletions src/ui/legendWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ var legendWidget = function (arg) {
m_group = null,
m_border = null,
m_spacing = 20, // distance in pixels between lines
m_padding = 12, // padding in pixels inside the border
s_createCanvas = this._createCanvas,
s_appendChild = this._appendChild;
m_padding = 12; // padding in pixels inside the border

/**
* Get or set the category array associated with
Expand Down Expand Up @@ -212,8 +210,8 @@ var legendWidget = function (arg) {
// adding categories redraws the entire thing by calling _init, see
// the m_top.remove() line below
if (!m_top) {
s_createCanvas();
s_appendChild();
m_this._createCanvas();
m_this._appendCanvasToParent();
}

// total size = interior size + 2 * padding + 2 * width of the border
Expand Down
6 changes: 2 additions & 4 deletions src/ui/sliderWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ var sliderWidget = function (arg) {

var m_this = this,
s_exit = this._exit,
s_createCanvas = this._createCanvas,
s_appendChild = this._appendChild,
m_xscale,
m_yscale,
m_plus,
Expand Down Expand Up @@ -91,8 +89,8 @@ var sliderWidget = function (arg) {
* @private
*/
this._init = function () {
s_createCanvas();
s_appendChild();
m_this._createCanvas();
m_this._appendCanvasToParent();

m_this.reposition();

Expand Down
49 changes: 35 additions & 14 deletions src/ui/svgWidget.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,45 @@
var domWidget = require('./domWidget');
var widget = require('./widget');
var inherit = require('../inherit');
var registerWidget = require('../registry').registerWidget;

/**
* Create a new instance of class geo.gui.svgWidget
* Create a new instance of class geo.gui.svgWidget.
*
* Due to the nature of d3 creating DOM elements as it inserts them, calls to appendChild
* don't appear in this widget.
* Due to the nature of d3 creating DOM elements as it inserts them, calls to
* appendChild don't appear in this widget.
*
* The canvas of an svgWidget always refers to the actual svg element.
* The parentCanvas can refer to another widgets svg element, dom element, or the
* UI layers dom element.
* The parentCanvas can refer to another widget's svg element, dom element, or
* the UI layer's dom element.
* See {@link geo.gui.widget#parentCanvas}.
*
* @class geo.gui.svgWidget
* @extends geo.gui.domWidget
* @class
* @alias geo.gui.svgWidget
* @extends geo.gui.widget
* @param {object} arg
* @param {geo.widget} [parent] A parent widget for this widget.
* @returns {geo.gui.svgWidget}
*
*/
var svgWidget = function (arg) {
'use strict';
if (!(this instanceof svgWidget)) {
return new svgWidget(arg);
}

domWidget.call(this, arg);
widget.call(this, arg);

var d3Renderer = require('../d3/d3Renderer');

var m_this = this,
s_exit = this._exit,
m_renderer = null;

this._init = function (arg) {
/**
* Initializes SVG Widget.
*
* @returns {this}
*/
this._init = function () {
var d3Parent;
if (arg.hasOwnProperty('parent')) {
arg.parent.addChild(m_this);
Expand All @@ -47,12 +55,25 @@ var svgWidget = function (arg) {
});

m_this.reposition();
return m_this;
};

/**
* Clean up the widget.
*/
this._exit = function () {
if (m_renderer) {
m_renderer._exit();
}
s_exit();
};

/**
* Creates the canvas for the svg widget.
* This directly uses the {@link geo.d3.d3Renderer} as a helper to do all of the heavy
* lifting.
* This directly uses the {@link geo.d3.d3Renderer} as a helper to do all of
* the heavy lifting.
*
* @param {d3Selector} d3Parent The canvas's parent element.
*/
this._createCanvas = function (d3Parent) {
var rendererOpts = {
Expand All @@ -75,7 +96,7 @@ var svgWidget = function (arg) {
return this;
};

inherit(svgWidget, domWidget);
inherit(svgWidget, widget);

registerWidget('dom', 'svg', svgWidget);
module.exports = svgWidget;
109 changes: 51 additions & 58 deletions src/ui/widget.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
var inherit = require('../inherit');
var sceneObject = require('../sceneObject');
var $ = require('jquery');

/**
* @typedef {object} geo.gui.widget.position
* @property {string|number} [top] The position to the top of the container.
* A string css position or a number. If a number is used, it will be treated as px value.
* @property {string|number} [right] The position to the right of the container.
* Value is used similarly to the top property.
* @property {string|number} [bottom] The position to the bottom of the container.
* Value is used similarly to the top property.
* A string css position or a number in pixels.
* @property {string|number} [right] The position to the right of the
* container. A string css position or a number in pixels.
* @property {string|number} [bottom] The position to the bottom of the
* container. A string css position or a number in pixels.
* @property {string|number} [left] The position to the left of the container.
* Value is used similarly to the top property.
* @property {string|number} [top] The position to the top of the container.
* @property {*} [...] Additional css properties that affect position are
allowed. See the css specification for details.
* allowed. See the css specification for details.
*/

/**
Expand All @@ -32,10 +33,10 @@ var widget = function (arg) {
if (!(this instanceof widget)) {
return new widget(arg);
}
arg = arg || {};
sceneObject.call(this, arg);

var geo_event = require('../event');
var createFeature = require('../registry').createFeature;

var m_this = this,
s_exit = this._exit,
Expand All @@ -45,6 +46,8 @@ var widget = function (arg) {

if (arg.parent !== undefined && !(arg.parent instanceof widget)) {
throw new Error('Parent must be of type geo.gui.widget');
} else if (arg.parent) {
m_this.parent(arg.parent);
}

/**
Expand All @@ -59,54 +62,31 @@ var widget = function (arg) {

/**
* Clean up the widget.
*
*/
this._exit = function () {
m_this.children().forEach(function (child) {
m_this._deleteFeature(child);
m_this.removeChild(child);
child._exit();
});

m_this.layer().geoOff(geo_event.pan, m_this.repositionEvent);
m_this.parentCanvas().removeChild(m_this.canvas());
if (m_this.parentCanvas().removeChild && m_this.canvas()) {
try {
m_this.parentCanvas().removeChild(m_this.canvas());
} catch (err) {
// fail gracefully if the canvas is not a child of the parentCanvas
}
}
s_exit();
};

/**
* Create a new feature.
*
* @param {string} featureName Name of the feature to create.
* @param {object} arg Options for the new feature.
* @returns {geo.feature} The new feature.
*/
this._createFeature = function (featureName, arg) {

var newFeature = createFeature(
featureName, m_this, m_this.renderer(), arg);

m_this.addChild(newFeature);
m_this.modified();
return newFeature;
};

/**
* Delete feature.
*
* @param {geo.feature} feature The feature to delete.
* @returns {this}
*/
this._deleteFeature = function (feature) {
m_this.removeChild(feature);
feature._exit();
return m_this;
};

/**
* Return the layer associated with this widget.
*
* @returns {geo.layer}
*/
this.layer = function () {
return m_layer;
return m_layer || (m_this.parent() && m_this.parent().layer());
};

/**
Expand All @@ -133,11 +113,11 @@ var widget = function (arg) {
};

/**
* Appends a child to the widget.
* Appends the canvas to the parent canvas.
* The widget determines how to append itself to a parent, the parent can
* either be another widget, or the UI Layer.
*/
this._appendChild = function () {
this._appendCanvasToParent = function () {
m_this.parentCanvas().appendChild(m_this.canvas());
};

Expand All @@ -148,7 +128,7 @@ var widget = function (arg) {
* @returns {HTMLElement} The canvas of the widget's parent.
*/
this.parentCanvas = function () {
if (m_this.parent === undefined) {
if (!m_this.parent()) {
return m_this.layer().canvas();
}
return m_this.parent().canvas();
Expand All @@ -169,11 +149,17 @@ var widget = function (arg) {
this.position = function (pos, actualValue) {
if (pos !== undefined) {
this.layer().geoOff(geo_event.pan, m_this.repositionEvent);
var clearPosition = {};
for (var attr in m_position) {
if (m_position.hasOwnProperty(attr)) {
clearPosition[attr] = null;
}
}
m_position = pos;
if (m_position.hasOwnProperty('x') && m_position.hasOwnProperty('y')) {
this.layer().geoOn(geo_event.pan, m_this.repositionEvent);
}
this.reposition();
this.reposition($.extend(clearPosition, m_this.position()));
return this;
}
if (m_position.hasOwnProperty('x') && m_position.hasOwnProperty('y') && !actualValue) {
Expand All @@ -199,17 +185,23 @@ var widget = function (arg) {
*/
this.reposition = function (position) {
position = position || m_this.position();
m_this.canvas().style.position = 'absolute';

for (var cssAttr in position) {
if (position.hasOwnProperty(cssAttr)) {
// if the property is a number, add px to it, otherwise set it to the
// specified value. Setting a property to null clears it. Setting to
// undefined doesn't alter it.
if (/^\s*(-|\+)?(\d+(\.\d*)?|\d*\.\d+)([eE](-|\+)?\d+)?\s*$/.test(position[cssAttr])) {
m_this.canvas().style[cssAttr] = ('' + position[cssAttr]).trim() + 'px';
} else {
m_this.canvas().style[cssAttr] = position[cssAttr];
if (m_this.canvas() && m_this.canvas().style) {
m_this.canvas().style.position = 'absolute';

for (var cssAttr in position) {
if (position.hasOwnProperty(cssAttr)) {
// if the property is a number, add px to it, otherwise set it to the
// specified value. Setting a property to null clears it. Setting to
// undefined doesn't alter it.
if (/^\s*(-|\+)?(\d+(\.\d*)?|\d*\.\d+)([eE](-|\+)?\d+)?\s*$/.test(position[cssAttr])) {
// tris ensures that the number is a float with no more than 3
// decimal places (Chrome does this automatically, but doing so
// explicitly makes testing more consistent). It will be an
// integer when possible.
m_this.canvas().style[cssAttr] = parseFloat(parseFloat(position[cssAttr]).toFixed(3)) + 'px';
} else {
m_this.canvas().style[cssAttr] = position[cssAttr];
}
}
}
}
Expand All @@ -227,9 +219,10 @@ var widget = function (arg) {
};

/**
* Report if the widget is completely within the viewport.
* Report if the top left of widget (or its current x, y position) is within
* the viewport.
*
* @returns {boolean} True if the widget is completely within the viewport.
* @returns {boolean} True if the widget is within the viewport.
*/
this.isInViewport = function () {
var position = m_this.position();
Expand Down
Loading

0 comments on commit 63f796b

Please sign in to comment.