diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md
index 0438fdcd3f..9cd3cf4f21 100644
--- a/changelog/upgrade-notes.md
+++ b/changelog/upgrade-notes.md
@@ -2,6 +2,35 @@
### v3.11.0
+#### `ol.interaction.DragBox` and `ol.interaction.DragZoom` changes
+
+Styling is no longer done with `ol.Style`, but with pure CSS. The `style` constructor option is no longer required, and no longer available. Instead, there is a `className` option for the CSS selector. The default for `ol.interaction.DragBox` is `ol-dragbox`, and `ol.interaction.DragZoom` uses `ol-dragzoom`. If you previously had
+```js
+new ol.interaction.DragZoom({
+ style: new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: 'red',
+ width: 3
+ }),
+ fill: new ol.style.Fill({
+ color: [255, 255, 255, 0.4]
+ })
+ })
+});
+```
+you'll now just need
+```js
+new ol.interaction.DragZoom();
+```
+but with additional css:
+```css
+.ol-dragzoom {
+ border-color: red;
+ border-width: 3px;
+ background-color: rgba(255,255,255,0.4);
+}
+```
+
### v3.10.0
#### `ol.layer.Layer` changes
diff --git a/css/ol.css b/css/ol.css
index 65577bd10f..43c07a9bea 100644
--- a/css/ol.css
+++ b/css/ol.css
@@ -1,3 +1,8 @@
+.ol-box {
+ box-sizing: border-box;
+ border-radius: 2px;
+ border: 2px solid blue;
+}
.ol-mouse-position {
top: 8px;
diff --git a/examples/box-selection.css b/examples/box-selection.css
new file mode 100644
index 0000000000..90c08960a4
--- /dev/null
+++ b/examples/box-selection.css
@@ -0,0 +1,4 @@
+.ol-dragbox {
+ background-color: rgba(255,255,255,0.4);
+ border-color: rgba(100,150,0,1);
+}
diff --git a/examples/box-selection.js b/examples/box-selection.js
index ded817496a..69ed2a936a 100644
--- a/examples/box-selection.js
+++ b/examples/box-selection.js
@@ -8,9 +8,6 @@ goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.source.OSM');
goog.require('ol.source.Vector');
-goog.require('ol.style.Fill');
-goog.require('ol.style.Stroke');
-goog.require('ol.style.Style');
var vectorSource = new ol.source.Vector({
@@ -44,15 +41,7 @@ var selectedFeatures = select.getFeatures();
// a DragBox interaction used to select features by drawing boxes
var dragBox = new ol.interaction.DragBox({
- condition: ol.events.condition.platformModifierKeyOnly,
- style: new ol.style.Style({
- fill: new ol.style.Fill({
- color: [255, 255, 255, 0.4]
- }),
- stroke: new ol.style.Stroke({
- color: [100, 150, 0, 1]
- })
- })
+ condition: ol.events.condition.platformModifierKeyOnly
});
map.addInteraction(dragBox);
diff --git a/externs/olx.js b/externs/olx.js
index bcfbb01c18..b7abb24f37 100644
--- a/externs/olx.js
+++ b/externs/olx.js
@@ -2281,13 +2281,21 @@ olx.interaction.DragAndDropOptions.prototype.projection;
/**
- * @typedef {{condition: (ol.events.ConditionType|undefined),
- * style: ol.style.Style}}
+ * @typedef {{className: (string|undefined),
+ * condition: (ol.events.ConditionType|undefined)}}
* @api
*/
olx.interaction.DragBoxOptions;
+/**
+ * CSS class name for styling the box. The default is `ol-dragbox`.
+ * @type {string|undefined}
+ * @api
+ */
+olx.interaction.DragBoxOptions.prototype.className;
+
+
/**
* A function that takes an {@link ol.MapBrowserEvent} and returns a boolean
* to indicate whether that event should be handled.
@@ -2298,14 +2306,6 @@ olx.interaction.DragBoxOptions;
olx.interaction.DragBoxOptions.prototype.condition;
-/**
- * Style for the box.
- * @type {ol.style.Style}
- * @api
- */
-olx.interaction.DragBoxOptions.prototype.style;
-
-
/**
* @typedef {{kinetic: (ol.Kinetic|undefined)}}
* @api
@@ -2374,14 +2374,22 @@ olx.interaction.DragRotateOptions.prototype.duration;
/**
- * @typedef {{condition: (ol.events.ConditionType|undefined),
- * duration: (number|undefined),
- * style: (ol.style.Style|undefined)}}
+ * @typedef {{className: (string|undefined),
+ * condition: (ol.events.ConditionType|undefined),
+ * duration: (number|undefined)}}
* @api
*/
olx.interaction.DragZoomOptions;
+/**
+ * CSS class name for styling the box. The default is `ol-dragzoom`.
+ * @type {string|undefined}
+ * @api
+ */
+olx.interaction.DragZoomOptions.prototype.className;
+
+
/**
* A function that takes an {@link ol.MapBrowserEvent} and returns a boolean
* to indicate whether that event should be handled.
@@ -2400,14 +2408,6 @@ olx.interaction.DragZoomOptions.prototype.condition;
olx.interaction.DragZoomOptions.prototype.duration;
-/**
- * Style for the box.
- * @type {ol.style.Style|undefined}
- * @api
- */
-olx.interaction.DragZoomOptions.prototype.style;
-
-
/**
* @typedef {{clickTolerance: (number|undefined),
* features: (ol.Collection.
|undefined),
@@ -5995,7 +5995,7 @@ olx.style.TextOptions.prototype.rotation;
/**
- * Text content.
+ * Text content.
* @type {string|undefined}
* @api
*/
@@ -6003,7 +6003,7 @@ olx.style.TextOptions.prototype.text;
/**
- * Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
+ * Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
* Default is 'start'.
* @type {string|undefined}
* @api
@@ -6012,7 +6012,7 @@ olx.style.TextOptions.prototype.textAlign;
/**
- * Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
+ * Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
* 'hanging', 'ideographic'. Default is 'alphabetic'.
* @type {string|undefined}
* @api
diff --git a/src/ol/interaction/dragboxinteraction.js b/src/ol/interaction/dragboxinteraction.js
index 7aa5eb19be..ca044f1067 100644
--- a/src/ol/interaction/dragboxinteraction.js
+++ b/src/ol/interaction/dragboxinteraction.js
@@ -93,17 +93,11 @@ ol.interaction.DragBox = function(opt_options) {
var options = opt_options ? opt_options : {};
- /**
- * @private
- * @type {ol.style.Style}
- */
- var style = options.style ? options.style : null;
-
/**
* @type {ol.render.Box}
* @private
*/
- this.box_ = new ol.render.Box(style);
+ this.box_ = new ol.render.Box(options.className || 'ol-dragbox');
/**
* @type {ol.Pixel}
diff --git a/src/ol/interaction/dragzoominteraction.js b/src/ol/interaction/dragzoominteraction.js
index 96bdc04ce5..939dfeb561 100644
--- a/src/ol/interaction/dragzoominteraction.js
+++ b/src/ol/interaction/dragzoominteraction.js
@@ -6,8 +6,6 @@ goog.require('ol.easing');
goog.require('ol.events.condition');
goog.require('ol.extent');
goog.require('ol.interaction.DragBox');
-goog.require('ol.style.Stroke');
-goog.require('ol.style.Style');
@@ -17,6 +15,9 @@ goog.require('ol.style.Style');
* normally combined with an {@link ol.events.condition} that limits
* it to when a key, shift by default, is held down.
*
+ * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or
+ * your custom one configured with `className`.
+ *
* @constructor
* @extends {ol.interaction.DragBox}
* @param {olx.interaction.DragZoomOptions=} opt_options Options.
@@ -34,20 +35,9 @@ ol.interaction.DragZoom = function(opt_options) {
*/
this.duration_ = options.duration !== undefined ? options.duration : 200;
- /**
- * @private
- * @type {ol.style.Style}
- */
- var style = options.style ?
- options.style : new ol.style.Style({
- stroke: new ol.style.Stroke({
- color: [0, 0, 255, 1]
- })
- });
-
goog.base(this, {
condition: condition,
- style: style
+ className: options.className || 'ol-dragzoom'
});
};
diff --git a/src/ol/render/box.js b/src/ol/render/box.js
index 7a416a392a..a0541d806f 100644
--- a/src/ol/render/box.js
+++ b/src/ol/render/box.js
@@ -4,18 +4,30 @@ goog.provide('ol.render.Box');
goog.require('goog.Disposable');
goog.require('goog.asserts');
-goog.require('goog.events');
goog.require('ol.geom.Polygon');
-goog.require('ol.render.EventType');
/**
* @constructor
* @extends {goog.Disposable}
- * @param {ol.style.Style} style Style.
+ * @param {string} className CSS class name.
*/
-ol.render.Box = function(style) {
+ol.render.Box = function(className) {
+
+ /**
+ * @type {ol.geom.Polygon}
+ * @private
+ */
+ this.geometry_ = null;
+
+ /**
+ * @type {HTMLDivElement}
+ * @private
+ */
+ this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div'));
+ this.element_.style.position = 'absolute';
+ this.element_.className = 'ol-box ' + className;
/**
* @private
@@ -23,12 +35,6 @@ ol.render.Box = function(style) {
*/
this.map_ = null;
- /**
- * @private
- * @type {goog.events.Key}
- */
- this.postComposeListenerKey_ = null;
-
/**
* @private
* @type {ol.Pixel}
@@ -41,27 +47,68 @@ ol.render.Box = function(style) {
*/
this.endPixel_ = null;
- /**
- * @private
- * @type {ol.geom.Polygon}
- */
- this.geometry_ = null;
-
- /**
- * @private
- * @type {ol.style.Style}
- */
- this.style_ = style;
-
};
goog.inherits(ol.render.Box, goog.Disposable);
/**
- * @private
- * @return {ol.geom.Polygon} Geometry.
+ * @inheritDoc
*/
-ol.render.Box.prototype.createGeometry_ = function() {
+ol.render.Box.prototype.disposeInternal = function() {
+ this.setMap(null);
+ goog.base(this, 'disposeInternal');
+};
+
+
+/**
+ * @private
+ */
+ol.render.Box.prototype.render_ = function() {
+ var startPixel = this.startPixel_;
+ var endPixel = this.endPixel_;
+ goog.asserts.assert(startPixel, 'this.startPixel_ must be truthy');
+ goog.asserts.assert(endPixel, 'this.endPixel_ must be truthy');
+ var px = 'px';
+ var style = this.element_.style;
+ style.left = Math.min(startPixel[0], endPixel[0]) + px;
+ style.top = Math.min(startPixel[1], endPixel[1]) + px;
+ style.width = Math.abs(endPixel[0] - startPixel[0]) + px;
+ style.height = Math.abs(endPixel[1] - startPixel[1]) + px;
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ */
+ol.render.Box.prototype.setMap = function(map) {
+ if (this.map_) {
+ this.map_.getViewport().removeChild(this.element_);
+ var style = this.element_.style;
+ style.left = style.top = style.width = style.height = 'inherit';
+ }
+ this.map_ = map;
+ if (this.map_) {
+ this.map_.getViewport().appendChild(this.element_);
+ }
+};
+
+
+/**
+ * @param {ol.Pixel} startPixel Start pixel.
+ * @param {ol.Pixel} endPixel End pixel.
+ */
+ol.render.Box.prototype.setPixels = function(startPixel, endPixel) {
+ this.startPixel_ = startPixel;
+ this.endPixel_ = endPixel;
+ this.createOrUpdateGeometry();
+ this.render_();
+};
+
+
+/**
+ * Creates or updates the cached geometry.
+ */
+ol.render.Box.prototype.createOrUpdateGeometry = function() {
goog.asserts.assert(this.startPixel_,
'this.startPixel_ must be truthy');
goog.asserts.assert(this.endPixel_,
@@ -78,33 +125,11 @@ ol.render.Box.prototype.createGeometry_ = function() {
var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_);
// close the polygon
coordinates[4] = coordinates[0].slice();
- return new ol.geom.Polygon([coordinates]);
-};
-
-
-/**
- * @inheritDoc
- */
-ol.render.Box.prototype.disposeInternal = function() {
- this.setMap(null);
-};
-
-
-/**
- * @param {ol.render.Event} event Event.
- * @private
- */
-ol.render.Box.prototype.handleMapPostCompose_ = function(event) {
- var geometry = this.geometry_;
- goog.asserts.assert(geometry, 'geometry should be defined');
- var style = this.style_;
- goog.asserts.assert(style, 'style must be truthy');
- // use drawAsync(Infinity) to draw above everything
- event.vectorContext.drawAsync(Infinity, function(render) {
- render.setFillStrokeStyle(style.getFill(), style.getStroke());
- render.setTextStyle(style.getText());
- render.drawPolygonGeometry(geometry, null);
- });
+ if (!this.geometry_) {
+ this.geometry_ = new ol.geom.Polygon([coordinates]);
+ } else {
+ this.geometry_.setCoordinates([coordinates]);
+ }
};
@@ -114,45 +139,3 @@ ol.render.Box.prototype.handleMapPostCompose_ = function(event) {
ol.render.Box.prototype.getGeometry = function() {
return this.geometry_;
};
-
-
-/**
- * @private
- */
-ol.render.Box.prototype.requestMapRenderFrame_ = function() {
- if (this.map_ && this.startPixel_ && this.endPixel_) {
- this.map_.render();
- }
-};
-
-
-/**
- * @param {ol.Map} map Map.
- */
-ol.render.Box.prototype.setMap = function(map) {
- if (this.postComposeListenerKey_) {
- goog.events.unlistenByKey(this.postComposeListenerKey_);
- this.postComposeListenerKey_ = null;
- this.map_.render();
- this.map_ = null;
- }
- this.map_ = map;
- if (this.map_) {
- this.postComposeListenerKey_ = goog.events.listen(
- map, ol.render.EventType.POSTCOMPOSE, this.handleMapPostCompose_, false,
- this);
- this.requestMapRenderFrame_();
- }
-};
-
-
-/**
- * @param {ol.Pixel} startPixel Start pixel.
- * @param {ol.Pixel} endPixel End pixel.
- */
-ol.render.Box.prototype.setPixels = function(startPixel, endPixel) {
- this.startPixel_ = startPixel;
- this.endPixel_ = endPixel;
- this.geometry_ = this.createGeometry_();
- this.requestMapRenderFrame_();
-};
diff --git a/test/spec/ol/interaction/dragzoominteraction.test.js b/test/spec/ol/interaction/dragzoominteraction.test.js
index 61b0758fe4..987efaff3b 100644
--- a/test/spec/ol/interaction/dragzoominteraction.test.js
+++ b/test/spec/ol/interaction/dragzoominteraction.test.js
@@ -43,6 +43,14 @@ describe('ol.interaction.DragZoom', function() {
var instance = new ol.interaction.DragZoom();
expect(instance).to.be.an(ol.interaction.DragZoom);
});
+ it('sets "ol-dragzoom" as box className', function() {
+ var instance = new ol.interaction.DragZoom();
+ expect(instance.box_.element_.className).to.be('ol-box ol-dragzoom');
+ });
+ it('sets a custom box className', function() {
+ var instance = new ol.interaction.DragZoom({className: 'test-dragzoom'});
+ expect(instance.box_.element_.className).to.be('ol-box test-dragzoom');
+ });
});
diff --git a/test/spec/ol/render/box.test.js b/test/spec/ol/render/box.test.js
new file mode 100644
index 0000000000..958eee52de
--- /dev/null
+++ b/test/spec/ol/render/box.test.js
@@ -0,0 +1,65 @@
+goog.provide('ol.test.render.Box');
+
+describe('ol.render.Box', function() {
+
+ var box, map, target;
+
+ beforeEach(function() {
+ box = new ol.render.Box('test-box');
+
+ target = document.createElement('div');
+ document.body.appendChild(target);
+
+ map = new ol.Map({
+ target: target,
+ view: new ol.View({
+ center: [0, 0],
+ zoom: 0
+ })
+ });
+ map.renderSync();
+ box.setMap(map);
+ });
+
+ afterEach(function() {
+ goog.dispose(map);
+ document.body.removeChild(target);
+ });
+
+ describe('Constructor', function() {
+ it('creates an absolutely positioned DIV with a className', function() {
+ expect(box.element_).to.be.a(HTMLDivElement);
+ expect(box.element_.style.position).to.be('absolute');
+ expect(box.element_.className).to.be('ol-box test-box');
+ expect(box.element_.style.position).to.be('absolute');
+ });
+ });
+
+ describe('#setPixels()', function() {
+ it('applies correct styles for a box', function() {
+ box.setPixels([1, 2], [4, 8]);
+ expect(box.element_.style.left).to.be('1px');
+ expect(box.element_.style.top).to.be('2px');
+ expect(box.element_.style.width).to.be('3px');
+ expect(box.element_.style.height).to.be('6px');
+ });
+ it('applies correct styles for a flipped box', function() {
+ box.setPixels([4, 8], [1, 2]);
+ expect(box.element_.style.left).to.be('1px');
+ expect(box.element_.style.top).to.be('2px');
+ expect(box.element_.style.width).to.be('3px');
+ expect(box.element_.style.height).to.be('6px');
+ });
+ it('creates a polygon geometry', function() {
+ expect(box.getGeometry()).to.be(null);
+ box.setPixels([1, 2], [3, 4]);
+ expect(box.getGeometry()).to.be.a(ol.geom.Polygon);
+ });
+ });
+
+});
+
+goog.require('ol.Map');
+goog.require('ol.View');
+goog.require('ol.geom.Polygon');
+goog.require('ol.render.Box');