diff --git a/examples/mouse-position.js b/examples/mouse-position.js index 7a43a9abf4..f399735b70 100644 --- a/examples/mouse-position.js +++ b/examples/mouse-position.js @@ -35,9 +35,16 @@ var map = new ol.Map({ }); var projectionSelect = new ol.dom.Input(document.getElementById('projection')); -projectionSelect.on('change:value', function() { - mousePositionControl.setProjection(ol.proj.get(projectionSelect.getValue())); -}); +projectionSelect.bindTo('value', mousePositionControl, 'projection') + .transform( + function(code) { + // projectionSelect.value -> mousePositionControl.projection + return ol.proj.get(/** @type {string} */ (code)); + }, + function(projection) { + // mousePositionControl.projection -> projectionSelect.value + return projection.getCode(); + }); var precisionInput = document.getElementById('precision'); precisionInput.addEventListener('change', function() { diff --git a/src/ol/object.js b/src/ol/object.js index 70864f815a..1dba992cd7 100644 --- a/src/ol/object.js +++ b/src/ol/object.js @@ -11,6 +11,7 @@ goog.provide('ol.ObjectEventType'); goog.require('goog.array'); goog.require('goog.events'); goog.require('goog.events.EventTarget'); +goog.require('goog.functions'); goog.require('goog.object'); @@ -22,6 +23,49 @@ ol.ObjectEventType = { }; + +/** + * @constructor + * @param {ol.Object} target + * @param {string} key + * @todo stability experimental + */ +ol.ObjectAccessor = function(target, key) { + + /** + * @type {ol.Object} + */ + this.target = target; + + /** + * @type {string} + */ + this.key = key; + + /** + * @type {function(?): ?} + */ + this.from = goog.functions.identity; + + /** + * @type {function(?): ?} + */ + this.to = goog.functions.identity; +}; + + +/** + * @param {function(?): ?} from A function that transforms the source value + * before it is set to the target. + * @param {function(?): ?} to A function that transforms the target value + * before it is set to the source. + */ +ol.ObjectAccessor.prototype.transform = function(from, to) { + this.from = from; + this.to = to; +}; + + /** * @enum {string} */ @@ -87,7 +131,7 @@ ol.Object.capitalize = function(str) { /** * @param {ol.Object} obj Object. - * @return {Object.} Accessors. + * @return {Object.} Accessors. */ ol.Object.getAccessors = function(obj) { return obj[ol.ObjectProperty.ACCESSORS] || @@ -139,14 +183,35 @@ ol.Object.getSetterName = function(key) { /** - * Binds a View to a Model. + * The bindTo method allows you to set up a two-way binding between a + * `source` and `target` object. The method returns an + * ol.ObjectAccessor with a transform method that lets you transform + * values on the way from the source to the target and on the way back. + * + * For example, if you had two map views (sourceView and targetView) + * and you wanted the target view to have double the resolution of the + * source view, you could transform the resolution on the way to and + * from the target with the following: + * + * sourceView.bindTo('resolution', targetView) + * .transform( + * function(sourceResolution) { + * // from sourceView.resolution to targetView.resolution + * return 2 * sourceResolution; + * }, + * function(targetResolution) { + * // from targetView.resolution to sourceView.resolution + * return targetResolution / 2; + * } + * ); + * * @param {string} key Key. * @param {ol.Object} target Target. * @param {string=} opt_targetKey Target key. + * @return {ol.ObjectAccessor} * @todo stability experimental */ -ol.Object.prototype.bindTo = - function(key, target, opt_targetKey) { +ol.Object.prototype.bindTo = function(key, target, opt_targetKey) { var targetKey = opt_targetKey || key; this.unbind(key); var eventType = ol.Object.getChangeEventType(targetKey); @@ -154,9 +219,11 @@ ol.Object.prototype.bindTo = listeners[key] = goog.events.listen(target, eventType, function() { this.notifyInternal_(key); }, undefined, this); + var accessor = new ol.ObjectAccessor(target, targetKey); var accessors = ol.Object.getAccessors(this); - accessors[key] = {target: target, key: targetKey}; + accessors[key] = accessor; this.notifyInternal_(key); + return accessor; }; @@ -179,6 +246,7 @@ ol.Object.prototype.get = function(key) { } else { value = target.get(targetKey); } + value = accessor.to(value); } else if (this.values_.hasOwnProperty(key)) { value = this.values_[key]; } @@ -289,6 +357,7 @@ ol.Object.prototype.set = function(key, value) { var target = accessor.target; var targetKey = accessor.key; var setterName = ol.Object.getSetterName(targetKey); + value = accessor.from(value); if (target[setterName]) { target[setterName](value); } else {