Merge pull request #4278 from ahocevar/css-box

Use DOM instead of map canvas for ol.render.Box
This commit is contained in:
Andreas Hocevar
2015-10-15 17:59:59 +02:00
10 changed files with 218 additions and 151 deletions

View File

@@ -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

View File

@@ -1,3 +1,8 @@
.ol-box {
box-sizing: border-box;
border-radius: 2px;
border: 2px solid blue;
}
.ol-mouse-position {
top: 8px;

View File

@@ -0,0 +1,4 @@
.ol-dragbox {
background-color: rgba(255,255,255,0.4);
border-color: rgba(100,150,0,1);
}

View File

@@ -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);

View File

@@ -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.<ol.Feature>|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

View File

@@ -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}

View File

@@ -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'
});
};

View File

@@ -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_();
};

View File

@@ -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');
});
});

View File

@@ -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');