Merge pull request #1551 from twpayne/remove-old
Remove code from old/ directory
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
@exportSymbol ol.Feature
|
||||
@exportProperty ol.Feature.prototype.getAttributes
|
||||
@exportProperty ol.Feature.prototype.getId
|
||||
@exportProperty ol.Feature.prototype.getGeometry
|
||||
@exportProperty ol.Feature.prototype.set
|
||||
@exportProperty ol.Feature.prototype.setGeometry
|
||||
@@ -1,268 +0,0 @@
|
||||
goog.provide('ol.Feature');
|
||||
goog.provide('ol.FeatureEvent');
|
||||
goog.provide('ol.FeatureEventType');
|
||||
goog.provide('ol.FeatureRenderIntent');
|
||||
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.geom.Geometry');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new feature. A feature is the base entity for vectors and has
|
||||
* attributes, including normally a geometry attribute.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var feature = new ol.Feature({'foo': 'bar'});
|
||||
* feature.setGeometry(new ol.geom.Point([100, 500]));
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {Object.<string, *>=} opt_values Attributes.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature = function(opt_values) {
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.geometryExtent_ = null;
|
||||
|
||||
goog.base(this, opt_values);
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.featureId_;
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_;
|
||||
|
||||
/**
|
||||
* The render intent for this feature.
|
||||
* @type {ol.FeatureRenderIntent|string}
|
||||
* @private
|
||||
*/
|
||||
this.renderIntent_ = ol.FeatureRenderIntent.DEFAULT;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.style.Symbolizer>}
|
||||
* @private
|
||||
*/
|
||||
this.symbolizers_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.Feature, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* Gets a copy of the attributes of this feature.
|
||||
* @param {boolean=} opt_nonGeometry Don't include any geometry attributes
|
||||
* (by default geometry attributes are returned).
|
||||
* @return {Object.<string, *>} Attributes object.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature.prototype.getAttributes = function(opt_nonGeometry) {
|
||||
var keys = this.getKeys(),
|
||||
includeGeometry = !opt_nonGeometry,
|
||||
len = keys.length,
|
||||
attributes = {},
|
||||
i, value, key;
|
||||
for (i = 0; i < len; ++ i) {
|
||||
key = keys[i];
|
||||
value = this.get(key);
|
||||
if (includeGeometry || !(value instanceof ol.geom.Geometry)) {
|
||||
attributes[key] = value;
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the feature's commonly used identifier. This identifier is usually
|
||||
* the unique id in the source store.
|
||||
*
|
||||
* @return {string|undefined} The feature's identifier.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature.prototype.getId = function() {
|
||||
return this.featureId_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the geometry associated with this feature.
|
||||
* @return {ol.geom.Geometry} The geometry (or null if none).
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature.prototype.getGeometry = function() {
|
||||
return goog.isDef(this.geometryName_) ?
|
||||
/** @type {ol.geom.Geometry} */ (this.get(this.geometryName_)) :
|
||||
null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get any symbolizers set directly on the feature.
|
||||
* @return {Array.<ol.style.Symbolizer>} Symbolizers (or null if none).
|
||||
*/
|
||||
ol.Feature.prototype.getSymbolizers = function() {
|
||||
return this.symbolizers_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for geometry change events.
|
||||
* @param {goog.events.Event} evt Change event.
|
||||
* @private
|
||||
*/
|
||||
ol.Feature.prototype.handleGeometryChange_ = function(evt) {
|
||||
var oldExtent = this.geometryExtent_;
|
||||
this.geometryExtent_ = this.getGeometry().getBounds();
|
||||
this.dispatchEvent(new ol.FeatureEvent(
|
||||
ol.FeatureEventType.CHANGE, this, oldExtent));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param {string} key Key.
|
||||
* @param {*} value Value.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature.prototype.set = function(key, value) {
|
||||
var geometry = this.getGeometry();
|
||||
var oldExtent = this.geometryExtent_;
|
||||
if (goog.isDefAndNotNull(geometry)) {
|
||||
if (key === this.geometryName_) {
|
||||
this.geometryExtent_ = null;
|
||||
goog.events.unlisten(geometry, goog.events.EventType.CHANGE,
|
||||
this.handleGeometryChange_, false, this);
|
||||
}
|
||||
}
|
||||
if (value instanceof ol.geom.Geometry) {
|
||||
if (!goog.isDef(this.geometryName_)) {
|
||||
this.geometryName_ = key;
|
||||
}
|
||||
if (key === this.geometryName_) {
|
||||
this.geometryExtent_ = value.getBounds();
|
||||
goog.events.listen(value, goog.events.EventType.CHANGE,
|
||||
this.handleGeometryChange_, false, this);
|
||||
}
|
||||
}
|
||||
goog.base(this, 'set', key, value);
|
||||
this.dispatchEvent(new ol.FeatureEvent(
|
||||
ol.FeatureEventType.CHANGE, this, oldExtent));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the feature's commonly used identifier. This identifier is usually the
|
||||
* unique id in the source store.
|
||||
*
|
||||
* @param {string|undefined} featureId The feature's identifier.
|
||||
*/
|
||||
ol.Feature.prototype.setId = function(featureId) {
|
||||
this.featureId_ = featureId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the geometry to be associated with this feature after its creation.
|
||||
* @param {ol.geom.Geometry} geometry The geometry.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.Feature.prototype.setGeometry = function(geometry) {
|
||||
if (!goog.isDef(this.geometryName_)) {
|
||||
this.geometryName_ = ol.Feature.DEFAULT_GEOMETRY;
|
||||
}
|
||||
this.set(this.geometryName_, geometry);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the renderIntent for this feature.
|
||||
* @return {string} Render intent.
|
||||
*/
|
||||
ol.Feature.prototype.getRenderIntent = function() {
|
||||
return this.renderIntent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Changes the renderIntent for this feature.
|
||||
* @param {string} renderIntent Render intent.
|
||||
*/
|
||||
ol.Feature.prototype.setRenderIntent = function(renderIntent) {
|
||||
this.renderIntent_ = renderIntent;
|
||||
var geometry = this.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.dispatchEvent(new ol.FeatureEvent(
|
||||
ol.FeatureEventType.INTENTCHANGE, this, geometry.getBounds()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the symbolizers to be used for this feature.
|
||||
* @param {Array.<ol.style.Symbolizer>} symbolizers Symbolizers for this
|
||||
* feature. If set, these take precedence over layer style.
|
||||
*/
|
||||
ol.Feature.prototype.setSymbolizers = function(symbolizers) {
|
||||
this.symbolizers_ = symbolizers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
ol.Feature.DEFAULT_GEOMETRY = 'geometry';
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.FeatureRenderIntent = {
|
||||
DEFAULT: 'default',
|
||||
FUTURE: 'future',
|
||||
HIDDEN: 'hidden',
|
||||
SELECTED: 'selected',
|
||||
TEMPORARY: 'temporary'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.FeatureEventType = {
|
||||
CHANGE: 'featurechange',
|
||||
INTENTCHANGE: 'featureintentchange'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for feature events.
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
* @param {string} type Event type.
|
||||
* @param {ol.Feature} target The target feature.
|
||||
* @param {ol.Extent} oldExtent The previous geometry extent.
|
||||
*/
|
||||
ol.FeatureEvent = function(type, target, oldExtent) {
|
||||
goog.base(this, type, target);
|
||||
|
||||
this.oldExtent = oldExtent;
|
||||
};
|
||||
goog.inherits(ol.FeatureEvent, goog.events.Event);
|
||||
@@ -1,29 +0,0 @@
|
||||
@exportSymbol ol.geom.GeometryType
|
||||
@exportProperty ol.geom.GeometryType.POINT
|
||||
@exportProperty ol.geom.GeometryType.LINEAR_RING
|
||||
@exportProperty ol.geom.GeometryType.LINE_STRING
|
||||
@exportProperty ol.geom.GeometryType.POLYGON
|
||||
@exportProperty ol.geom.GeometryType.MULTI_POINT
|
||||
@exportProperty ol.geom.GeometryType.MULTI_LINE_STRING
|
||||
@exportProperty ol.geom.GeometryType.MULTI_POLYGON
|
||||
@exportProperty ol.geom.GeometryType.GEOMETRY_COLLECTION
|
||||
|
||||
@exportSymbol ol.geom.Geometry
|
||||
|
||||
@exportSymbol ol.geom.Point
|
||||
@exportProperty ol.geom.Point.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.LineString
|
||||
@exportProperty ol.geom.LineString.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.Polygon
|
||||
@exportProperty ol.geom.Polygon.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiPoint
|
||||
@exportProperty ol.geom.MultiPoint.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiLineString
|
||||
@exportProperty ol.geom.MultiLineString.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiPolygon
|
||||
@exportProperty ol.geom.MultiPolygon.prototype.getCoordinates
|
||||
@@ -1,3 +0,0 @@
|
||||
/**
|
||||
* @namespace ol.geom
|
||||
*/
|
||||
@@ -1,96 +0,0 @@
|
||||
goog.provide('ol.geom.AbstractCollection');
|
||||
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.Geometry');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A collection of geometries. This constructor is not to be used directly.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
*/
|
||||
ol.geom.AbstractCollection = function() {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Geometry>}
|
||||
* @protected
|
||||
*/
|
||||
this.components = null;
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @protected
|
||||
*/
|
||||
this.bounds = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.AbstractCollection, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds)) {
|
||||
var bounds = ol.extent.createEmpty();
|
||||
var components = this.components;
|
||||
for (var i = 0, ii = components.length; i < ii; ++i) {
|
||||
ol.extent.extend(bounds, components[i].getBounds());
|
||||
}
|
||||
this.bounds = bounds;
|
||||
}
|
||||
return this.bounds;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.geom.Geometry>} Components.
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getComponents = function() {
|
||||
return this.components;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getCoordinates = function() {
|
||||
var count = this.components.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = this.components[i].getCoordinates();
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getType = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Listener for component change events.
|
||||
* @param {goog.events.Event} evt Change event.
|
||||
* @protected
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.handleComponentChange = function(evt) {
|
||||
this.bounds = null;
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.transform = function(transform) {
|
||||
var components = this.components;
|
||||
for (var i = 0, ii = components.length; i < ii; ++i) {
|
||||
components[i].transform(transform);
|
||||
}
|
||||
this.bounds = null;
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
goog.provide('ol.geom.Geometry');
|
||||
goog.provide('ol.geom.GeometryType');
|
||||
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Observable');
|
||||
goog.require('ol.TransformFunction');
|
||||
|
||||
|
||||
/**
|
||||
* Geometry types.
|
||||
*
|
||||
* @enum {string}
|
||||
* @todo stability stable
|
||||
*/
|
||||
ol.geom.GeometryType = {
|
||||
POINT: 'Point',
|
||||
LINE_STRING: 'LineString',
|
||||
LINEAR_RING: 'LinearRing',
|
||||
POLYGON: 'Polygon',
|
||||
MULTI_POINT: 'MultiPoint',
|
||||
MULTI_LINE_STRING: 'MultiLineString',
|
||||
MULTI_POLYGON: 'MultiPolygon',
|
||||
GEOMETRY_COLLECTION: 'GeometryCollection'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.Observable}
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.Geometry = function() {
|
||||
goog.base(this);
|
||||
};
|
||||
goog.inherits(ol.geom.Geometry, ol.Observable);
|
||||
|
||||
|
||||
/**
|
||||
* Create a clone of this geometry.
|
||||
* @return {ol.geom.Geometry} The cloned geometry.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.clone = function() {
|
||||
return new this.constructor(goog.object.unsafeClone(this.getCoordinates()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the rectangular 2D envelope for this geoemtry.
|
||||
* @return {ol.Extent} The bounding rectangular envelope.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getBounds = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array} The GeoJSON style coordinates array for the geometry.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getCoordinates = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Get the geometry type.
|
||||
* @return {ol.geom.GeometryType} The geometry type.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getType = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Transform a geometry in place.
|
||||
* @param {ol.TransformFunction} transform Transform function.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.transform = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch a generic event with type "change."
|
||||
*/
|
||||
ol.geom.Geometry.prototype.dispatchChangeEvent = function() {
|
||||
this.dispatchEvent(goog.events.EventType.CHANGE);
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
goog.provide('ol.geom.GeometryCollection');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mixed collection of geometries. Used one of the fixed type multi-part
|
||||
* constructors for collections of the same type.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<ol.geom.Geometry>} geometries Array of geometries.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.GeometryCollection = function(geometries) {
|
||||
goog.base(this);
|
||||
|
||||
for (var i = geometries.length - 1; i >= 0; --i) {
|
||||
goog.events.listen(geometries[i], goog.events.EventType.CHANGE,
|
||||
this.handleComponentChange, false, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Geometry>}
|
||||
* @protected
|
||||
*/
|
||||
this.components = geometries;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.GeometryCollection, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.GeometryCollection.prototype.clone = function() {
|
||||
var numComponents = this.components.length;
|
||||
var components = new Array(numComponents);
|
||||
for (var i = 0; i < numComponents; ++i) {
|
||||
components[i] = this.components[i].clone();
|
||||
}
|
||||
return new ol.geom.GeometryCollection(components);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.GeometryCollection.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.GEOMETRYCOLLECTION;
|
||||
};
|
||||
@@ -1,100 +0,0 @@
|
||||
goog.provide('ol.geom.LinearRing');
|
||||
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.LineString}
|
||||
* @param {ol.CoordinateArray} coordinates Vertex array (e.g.
|
||||
* `[[x0, y0], [x1, y1]]`).
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.LinearRing = function(coordinates) {
|
||||
goog.base(this, coordinates);
|
||||
|
||||
/**
|
||||
* We're intentionally not enforcing that rings be closed right now. This
|
||||
* will allow proper rendering of data from tiled vector sources that leave
|
||||
* open rings.
|
||||
*/
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.LinearRing, ol.geom.LineString);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a vertex array representing a linear ring is in clockwise
|
||||
* order.
|
||||
*
|
||||
* This method comes from Green's Theorem and was mentioned in an answer to a
|
||||
* a Stack Overflow question (http://tinyurl.com/clockwise-method).
|
||||
*
|
||||
* Note that calculating the cross product for each pair of edges could be
|
||||
* avoided by first finding the lowest, rightmost vertex. See OGR's
|
||||
* implementation for an example of this.
|
||||
* https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
|
||||
*
|
||||
* @param {ol.CoordinateArray} coordinates Linear ring coordinates.
|
||||
* @return {boolean} The coordinates are in clockwise order.
|
||||
*/
|
||||
ol.geom.LinearRing.isClockwise = function(coordinates) {
|
||||
var length = coordinates.length;
|
||||
var edge = 0;
|
||||
|
||||
var last = coordinates[length - 1];
|
||||
var x1 = last[0];
|
||||
var y1 = last[1];
|
||||
|
||||
var x2, y2, coord;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
coord = coordinates[i];
|
||||
x2 = coord[0];
|
||||
y2 = coord[1];
|
||||
edge += (x2 - x1) * (y2 + y1);
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
return edge > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LinearRing.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.LINEARRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this ring. Note that this is a
|
||||
* fast and simple check - points on an edge or vertex of the ring are either
|
||||
* classified inside or outside.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the ring.
|
||||
*/
|
||||
ol.geom.LinearRing.prototype.containsCoordinate = function(coordinate) {
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
var x = coordinate[0], y = coordinate[1];
|
||||
var vertices = this.getCoordinates();
|
||||
var inside = false;
|
||||
var xi, yi, xj, yj, intersect;
|
||||
var numVertices = vertices.length;
|
||||
for (var i = 0, j = numVertices - 1; i < numVertices; j = i++) {
|
||||
xi = vertices[i][0];
|
||||
yi = vertices[i][1];
|
||||
xj = vertices[j][0];
|
||||
yj = vertices[j][1];
|
||||
intersect = ((yi > y) != (yj > y)) &&
|
||||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
};
|
||||
@@ -1,134 +0,0 @@
|
||||
goog.provide('ol.geom.LineString');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.coordinate');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {ol.CoordinateArray} coordinates Array of coordinates (e.g.
|
||||
* `[[x0, y0], [x1, y1]]`).
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.LineString = function(coordinates) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0]));
|
||||
|
||||
/**
|
||||
* Array of coordinates.
|
||||
* @type {ol.CoordinateArray}
|
||||
* @private
|
||||
*/
|
||||
this.coordinates_ = coordinates;
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.bounds_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.LineString, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* Get a vertex coordinate value for the given dimension.
|
||||
* @param {number} index Vertex index.
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @return {number} The vertex coordinate value.
|
||||
*/
|
||||
ol.geom.LineString.prototype.get = function(index, dim) {
|
||||
var coordinates = this.getCoordinates();
|
||||
goog.asserts.assert(coordinates.length > index);
|
||||
return coordinates[index][dim];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.CoordinateArray} Coordinates array.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getCoordinates = function() {
|
||||
return this.coordinates_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the count of vertices in this linestring.
|
||||
* @return {number} The vertex count.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getCount = function() {
|
||||
return this.getCoordinates().length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds_)) {
|
||||
var coordinates = this.getCoordinates();
|
||||
var extent = ol.extent.createEmpty();
|
||||
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
ol.extent.extendCoordinate(extent, coordinates[i]);
|
||||
}
|
||||
this.bounds_ = extent;
|
||||
}
|
||||
return this.bounds_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.LINE_STRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the distance from a coordinate to this linestring.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {number} Distance from the coordinate to this linestring.
|
||||
*/
|
||||
ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) {
|
||||
var coordinates = this.getCoordinates();
|
||||
var dist2 = Infinity;
|
||||
for (var i = 0, j = 1, len = coordinates.length; j < len; i = j++) {
|
||||
dist2 = Math.min(dist2, ol.coordinate.squaredDistanceToSegment(coordinate,
|
||||
[coordinates[i], coordinates[j]]));
|
||||
}
|
||||
return Math.sqrt(dist2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update the linestring coordinates.
|
||||
* @param {ol.CoordinateArray} coordinates Coordinates array.
|
||||
*/
|
||||
ol.geom.LineString.prototype.setCoordinates = function(coordinates) {
|
||||
this.bounds_ = null;
|
||||
this.coordinates_ = coordinates;
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.transform = function(transform) {
|
||||
var coordinates = this.getCoordinates();
|
||||
var coord;
|
||||
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
coord = coordinates[i];
|
||||
transform(coord, coord, coord.length);
|
||||
}
|
||||
this.setCoordinates(coordinates); // for invalidating bounds
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
goog.provide('ol.geom.MultiLineString');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<ol.CoordinateArray>} coordinates Coordinates array.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.MultiLineString = function(coordinates) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0]));
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.LineString>}
|
||||
* @protected
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
var component = new ol.geom.LineString(coordinates[i]);
|
||||
this.components[i] = component;
|
||||
goog.events.listen(component, goog.events.EventType.CHANGE,
|
||||
this.handleComponentChange, false, this);
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiLineString, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiLineString.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTILINESTRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the distance from a coordinate to this multilinestring. This is
|
||||
* the closest distance of the coordinate to one of this multilinestring's
|
||||
* components.<
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {number} Distance from the coordinate to this multilinestring.
|
||||
*/
|
||||
ol.geom.MultiLineString.prototype.distanceFromCoordinate =
|
||||
function(coordinate) {
|
||||
var distance = Infinity;
|
||||
for (var i = 0, ii = this.components.length; i < ii; ++i) {
|
||||
distance = Math.min(distance,
|
||||
this.components[i].distanceFromCoordinate(coordinate));
|
||||
}
|
||||
return distance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-linestring geometry from an array of linestring geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.LineString>} geometries Array of geometries.
|
||||
* @return {ol.geom.MultiLineString} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiLineString.fromParts = function(geometries) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiLineString(coordinates);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
goog.provide('ol.geom.MultiPoint');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.Point');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {ol.CoordinateArray} coordinates Coordinates array.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.MultiPoint = function(coordinates) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0]));
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Point>}
|
||||
* @protected
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
var component = new ol.geom.Point(coordinates[i]);
|
||||
this.components[i] = component;
|
||||
goog.events.listen(component, goog.events.EventType.CHANGE,
|
||||
this.handleComponentChange, false, this);
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiPoint, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiPoint.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTIPOINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-point geometry from an array of point geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.Point>} geometries Array of geometries.
|
||||
* @return {ol.geom.MultiPoint} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiPoint.fromParts = function(geometries) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiPoint(coordinates);
|
||||
};
|
||||
@@ -1,81 +0,0 @@
|
||||
goog.provide('ol.geom.MultiPolygon');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.Polygon');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<Array.<ol.CoordinateArray>>} coordinates Coordinates
|
||||
* array.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.MultiPolygon = function(coordinates) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0][0]));
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Polygon>}
|
||||
* @protected
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
var component = new ol.geom.Polygon(coordinates[i]);
|
||||
this.components[i] = component;
|
||||
goog.events.listen(component, goog.events.EventType.CHANGE,
|
||||
this.handleComponentChange, false, this);
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiPolygon, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiPolygon.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTIPOLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this multipolygon.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the multipolygon.
|
||||
*/
|
||||
ol.geom.MultiPolygon.prototype.containsCoordinate = function(coordinate) {
|
||||
var containsCoordinate = false;
|
||||
for (var i = 0, ii = this.components.length; i < ii; ++i) {
|
||||
if (this.components[i].containsCoordinate(coordinate)) {
|
||||
containsCoordinate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsCoordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-polygon geometry from an array of polygon geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.Polygon>} geometries Array of geometries.
|
||||
* @return {ol.geom.MultiPolygon} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiPolygon.fromParts = function(geometries) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiPolygon(coordinates);
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
goog.provide('ol.geom.Point');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {ol.Coordinate} coordinates Coordinate values (e.g. `[x, y]`).
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.Point = function(coordinates) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Point coordinate values.
|
||||
* @type {ol.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.coordinates_ = coordinates;
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.bounds_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.Point, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @return {number} The coordinate value.
|
||||
*/
|
||||
ol.geom.Point.prototype.get = function(dim) {
|
||||
return this.getCoordinates()[dim];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds_)) {
|
||||
var x = this.get(0),
|
||||
y = this.get(1);
|
||||
this.bounds_ = [x, y, x, y];
|
||||
}
|
||||
return this.bounds_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.Coordinate} Coordinates array.
|
||||
*/
|
||||
ol.geom.Point.prototype.getCoordinates = function() {
|
||||
return this.coordinates_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.POINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update the point coordinates.
|
||||
* @param {ol.Coordinate} coordinates Coordinates array.
|
||||
*/
|
||||
ol.geom.Point.prototype.setCoordinates = function(coordinates) {
|
||||
this.bounds_ = null;
|
||||
this.coordinates_ = coordinates;
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.transform = function(transform) {
|
||||
var coordinates = this.getCoordinates();
|
||||
transform(coordinates, coordinates, coordinates.length);
|
||||
this.setCoordinates(coordinates); // for invalidating bounds
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
goog.provide('ol.geom.Polygon');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LinearRing');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon from an array of vertex arrays. Coordinates for the
|
||||
* exterior ring will be forced to clockwise order. Coordinates for any
|
||||
* interior rings will be forced to counter-clockwise order. In cases where
|
||||
* the opposite winding order occurs in the passed vertex arrays, they will
|
||||
* be modified in place.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {Array.<ol.CoordinateArray>} coordinates Array of rings. First
|
||||
* is outer, any remaining are inner.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.Polygon = function(coordinates) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0]));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.labelPoint_ = null;
|
||||
|
||||
var numRings = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.LinearRing>}
|
||||
* @private
|
||||
*/
|
||||
this.rings_ = new Array(numRings);
|
||||
var ringCoords, ring;
|
||||
for (var i = 0; i < numRings; ++i) {
|
||||
ringCoords = coordinates[i];
|
||||
if (i === 0) {
|
||||
// force exterior ring to be clockwise
|
||||
if (!ol.geom.LinearRing.isClockwise(ringCoords)) {
|
||||
ringCoords.reverse();
|
||||
}
|
||||
} else {
|
||||
// force interior rings to be counter-clockwise
|
||||
if (ol.geom.LinearRing.isClockwise(ringCoords)) {
|
||||
ringCoords.reverse();
|
||||
}
|
||||
}
|
||||
ring = new ol.geom.LinearRing(ringCoords);
|
||||
goog.events.listen(ring, goog.events.EventType.CHANGE,
|
||||
this.handleRingChange_, false, this);
|
||||
this.rings_[i] = ring;
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getBounds = function() {
|
||||
return this.rings_[0].getBounds();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.CoordinateArray>} Coordinates array.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getCoordinates = function() {
|
||||
var count = this.rings_.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = this.rings_[i].getCoordinates();
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.POLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get polygon rings.
|
||||
* @return {Array.<ol.geom.LinearRing>} Array of rings. The first ring is the
|
||||
* exterior and any additional rings are interior.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getRings = function() {
|
||||
return this.rings_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for ring change events.
|
||||
* @param {goog.events.Event} evt Change event.
|
||||
* @private
|
||||
*/
|
||||
ol.geom.Polygon.prototype.handleRingChange_ = function(evt) {
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this polygon. Note that this is a
|
||||
* fast and simple check - points on an edge or vertex of the polygon or one of
|
||||
* its inner rings are either classified inside or outside.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the polygon.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
|
||||
var rings = this.rings_;
|
||||
/** @type {boolean} */
|
||||
var containsCoordinate;
|
||||
for (var i = 0, ii = rings.length; i < ii; ++i) {
|
||||
containsCoordinate = rings[i].containsCoordinate(coordinate);
|
||||
// if inner ring (i > 0) contains coordinate, polygon does not contain it
|
||||
if (i > 0) {
|
||||
containsCoordinate = !containsCoordinate;
|
||||
}
|
||||
if (!containsCoordinate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsCoordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates a point that is guaranteed to lie in the interior of the polygon.
|
||||
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
|
||||
* @return {ol.Coordinate} A point which is in the interior of the polygon.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getInteriorPoint = function() {
|
||||
if (goog.isNull(this.labelPoint_)) {
|
||||
var center = ol.extent.getCenter(this.getBounds()),
|
||||
resultY = center[1],
|
||||
vertices = this.rings_[0].getCoordinates(),
|
||||
intersections = [],
|
||||
maxLength = 0,
|
||||
i, vertex1, vertex2, x, segmentLength, resultX;
|
||||
|
||||
// Calculate intersections with the horizontal bounding box center line
|
||||
for (i = vertices.length - 1; i >= 1; --i) {
|
||||
vertex1 = vertices[i];
|
||||
vertex2 = vertices[i - 1];
|
||||
if ((vertex1[1] >= resultY && vertex2[1] <= resultY) ||
|
||||
(vertex1[1] <= resultY && vertex2[1] >= resultY)) {
|
||||
x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) *
|
||||
(vertex2[0] - vertex1[0]) + vertex1[0];
|
||||
intersections.push(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the longest segment of the horizontal bounding box center line that
|
||||
// has its center point inside the polygon
|
||||
intersections.sort();
|
||||
for (i = intersections.length - 1; i >= 1; --i) {
|
||||
segmentLength = Math.abs(intersections[i] - intersections[i - 1]);
|
||||
if (segmentLength > maxLength) {
|
||||
x = (intersections[i] + intersections[i - 1]) / 2;
|
||||
if (this.containsCoordinate([x, resultY])) {
|
||||
maxLength = segmentLength;
|
||||
resultX = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.labelPoint_ = [resultX, resultY];
|
||||
}
|
||||
|
||||
return this.labelPoint_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.transform = function(transform) {
|
||||
var rings = this.rings_;
|
||||
for (var i = 0, ii = rings.length; i < ii; ++i) {
|
||||
rings[i].transform(transform);
|
||||
}
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.interaction.Draw
|
||||
@@ -1,418 +0,0 @@
|
||||
goog.provide('ol.interaction.Draw');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.LinearRing');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.source.Vector');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interaction that allows drawing geometries.
|
||||
* @param {olx.interaction.DrawOptions} options Options.
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Interaction}
|
||||
*/
|
||||
ol.interaction.Draw = function(options) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Target layer for drawn features.
|
||||
* @type {ol.layer.Vector}
|
||||
* @private
|
||||
*/
|
||||
this.layer_ = options.layer;
|
||||
|
||||
/**
|
||||
* Temporary sketch layer.
|
||||
* @type {ol.layer.Vector}
|
||||
* @private
|
||||
*/
|
||||
this.sketchLayer_ = null;
|
||||
|
||||
/**
|
||||
* Pixel distance for snapping.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.snapTolerance_ = goog.isDef(options.snapTolerance) ?
|
||||
options.snapTolerance : 12;
|
||||
|
||||
/**
|
||||
* Geometry type.
|
||||
* @type {ol.geom.GeometryType}
|
||||
* @private
|
||||
*/
|
||||
this.type_ = options.type;
|
||||
|
||||
/**
|
||||
* Drawing mode (derived from geometry type.
|
||||
* @type {ol.interaction.DrawMode}
|
||||
* @private
|
||||
*/
|
||||
this.mode_ = ol.interaction.Draw.getMode_(this.type_);
|
||||
|
||||
/**
|
||||
* Finish coordinate for the feature (first point for polygons, last point for
|
||||
* linestrings).
|
||||
* @type {ol.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.finishCoordinate_ = null;
|
||||
|
||||
/**
|
||||
* Sketch feature.
|
||||
* @type {ol.Feature}
|
||||
* @private
|
||||
*/
|
||||
this.sketchFeature_ = null;
|
||||
|
||||
/**
|
||||
* Sketch point.
|
||||
* @type {ol.Feature}
|
||||
* @private
|
||||
*/
|
||||
this.sketchPoint_ = null;
|
||||
|
||||
/**
|
||||
* Squared tolerance for handling click events. If the squared distance
|
||||
* between a down and click event is greater than this tolerance, click events
|
||||
* will not be handled.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.squaredClickTolerance_ = 4;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.Draw, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Draw.prototype.setMap = function(map) {
|
||||
var oldMap = this.getMap();
|
||||
if (!goog.isNull(oldMap)) {
|
||||
oldMap.removeLayer(this.sketchLayer_);
|
||||
}
|
||||
|
||||
if (!goog.isNull(map)) {
|
||||
if (goog.isNull(this.sketchLayer_)) {
|
||||
var layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector(),
|
||||
style: this.layer_.getStyle()
|
||||
});
|
||||
layer.setTemporary(true);
|
||||
this.sketchLayer_ = layer;
|
||||
}
|
||||
map.addLayer(this.sketchLayer_);
|
||||
} else {
|
||||
// removing from a map, clean up
|
||||
this.abortDrawing_();
|
||||
this.sketchLayer_ = null;
|
||||
}
|
||||
|
||||
goog.base(this, 'setMap', map);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Draw.prototype.handleMapBrowserEvent = function(event) {
|
||||
var map = event.map;
|
||||
if (!map.isDef()) {
|
||||
return true;
|
||||
}
|
||||
var pass = true;
|
||||
if (event.type === ol.MapBrowserEvent.EventType.CLICK) {
|
||||
pass = this.handleClick_(event);
|
||||
} else if (event.type === ol.MapBrowserEvent.EventType.MOUSEMOVE) {
|
||||
pass = this.handleMove_(event);
|
||||
} else if (event.type === ol.MapBrowserEvent.EventType.DBLCLICK) {
|
||||
pass = false;
|
||||
}
|
||||
return pass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle click events.
|
||||
* @param {ol.MapBrowserEvent} event A click event.
|
||||
* @return {boolean} Pass the event to other interactions.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.handleClick_ = function(event) {
|
||||
var downPx = event.map.getEventPixel(event.target.getDown());
|
||||
var clickPx = event.getPixel();
|
||||
var dx = downPx[0] - clickPx[0];
|
||||
var dy = downPx[1] - clickPx[1];
|
||||
var squaredDistance = dx * dx + dy * dy;
|
||||
var pass = true;
|
||||
if (squaredDistance <= this.squaredClickTolerance_) {
|
||||
if (goog.isNull(this.finishCoordinate_)) {
|
||||
this.startDrawing_(event);
|
||||
} else if (this.mode_ === ol.interaction.DrawMode.POINT ||
|
||||
this.atFinish_(event)) {
|
||||
this.finishDrawing_(event);
|
||||
} else {
|
||||
this.addToDrawing_(event);
|
||||
}
|
||||
pass = false;
|
||||
}
|
||||
return pass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle mousemove events.
|
||||
* @param {ol.MapBrowserEvent} event A mousemove event.
|
||||
* @return {boolean} Pass the event to other interactions.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.handleMove_ = function(event) {
|
||||
if (this.mode_ === ol.interaction.DrawMode.POINT &&
|
||||
goog.isNull(this.finishCoordinate_)) {
|
||||
this.startDrawing_(event);
|
||||
} else if (!goog.isNull(this.finishCoordinate_)) {
|
||||
this.modifyDrawing_(event);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if an event is within the snapping tolerance of the start coord.
|
||||
* @param {ol.MapBrowserEvent} event Event.
|
||||
* @return {boolean} The event is within the snapping tolerance of the start.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.atFinish_ = function(event) {
|
||||
var at = false;
|
||||
if (this.sketchFeature_) {
|
||||
var geometry = this.sketchFeature_.getGeometry();
|
||||
var potentiallyDone = false;
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
potentiallyDone = geometry.getCoordinates().length > 2;
|
||||
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||
potentiallyDone = geometry.getRings()[0].getCoordinates().length > 3;
|
||||
}
|
||||
if (potentiallyDone) {
|
||||
var map = event.map;
|
||||
var finishPixel = map.getPixelFromCoordinate(this.finishCoordinate_);
|
||||
var pixel = event.getPixel();
|
||||
var dx = pixel[0] - finishPixel[0];
|
||||
var dy = pixel[1] - finishPixel[1];
|
||||
at = Math.sqrt(dx * dx + dy * dy) <= this.snapTolerance_;
|
||||
}
|
||||
}
|
||||
return at;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Start the drawing.
|
||||
* @param {ol.MapBrowserEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.startDrawing_ = function(event) {
|
||||
var start = event.getCoordinate();
|
||||
this.finishCoordinate_ = start;
|
||||
var sketchFeature = new ol.Feature();
|
||||
sketchFeature.setRenderIntent(ol.FeatureRenderIntent.SELECTED);
|
||||
var features = [sketchFeature];
|
||||
var geometry;
|
||||
if (this.mode_ === ol.interaction.DrawMode.POINT) {
|
||||
geometry = new ol.geom.Point(start.slice());
|
||||
} else {
|
||||
var sketchPoint = new ol.Feature({
|
||||
geom: new ol.geom.Point(start.slice())
|
||||
});
|
||||
sketchPoint.setRenderIntent(ol.FeatureRenderIntent.TEMPORARY);
|
||||
this.sketchPoint_ = sketchPoint;
|
||||
features.push(sketchPoint);
|
||||
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
geometry = new ol.geom.LineString([start.slice(), start.slice()]);
|
||||
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
|
||||
geometry = new ol.geom.Polygon([[start.slice(), start.slice()]]);
|
||||
}
|
||||
}
|
||||
goog.asserts.assert(goog.isDef(geometry));
|
||||
sketchFeature.setGeometry(geometry);
|
||||
this.sketchFeature_ = sketchFeature;
|
||||
|
||||
this.sketchLayer_.getVectorSource().addFeatures(features);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Modify the drawing.
|
||||
* @param {ol.MapBrowserEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
|
||||
var coordinate = event.getCoordinate();
|
||||
var geometry = this.sketchFeature_.getGeometry();
|
||||
var coordinates, last;
|
||||
if (this.mode_ === ol.interaction.DrawMode.POINT) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
|
||||
last = geometry.getCoordinates();
|
||||
last[0] = coordinate[0];
|
||||
last[1] = coordinate[1];
|
||||
geometry.setCoordinates(last);
|
||||
} else {
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
|
||||
coordinates = geometry.getCoordinates();
|
||||
} else {
|
||||
goog.asserts.assert(this.mode_ === ol.interaction.DrawMode.POLYGON);
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||
geometry = geometry.getRings()[0];
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.LinearRing);
|
||||
coordinates = geometry.getCoordinates();
|
||||
}
|
||||
if (this.atFinish_(event)) {
|
||||
// snap to finish
|
||||
coordinate = this.finishCoordinate_.slice();
|
||||
}
|
||||
var point = this.sketchPoint_.getGeometry();
|
||||
goog.asserts.assertInstanceof(point, ol.geom.Point);
|
||||
point.setCoordinates(coordinate);
|
||||
last = coordinates[coordinates.length - 1];
|
||||
last[0] = coordinate[0];
|
||||
last[1] = coordinate[1];
|
||||
geometry.setCoordinates(coordinates);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a new coordinate to the drawing.
|
||||
* @param {ol.MapBrowserEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
|
||||
var coordinate = event.getCoordinate();
|
||||
var geometry = this.sketchFeature_.getGeometry();
|
||||
var coordinates, last;
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
|
||||
this.finishCoordinate_ = coordinate.slice();
|
||||
coordinates = geometry.getCoordinates();
|
||||
coordinates.push(coordinate.slice());
|
||||
geometry.setCoordinates(coordinates);
|
||||
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||
var ring = geometry.getRings()[0];
|
||||
coordinates = ring.getCoordinates();
|
||||
coordinates.push(coordinate.slice());
|
||||
ring.setCoordinates(coordinates);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stop drawing and add the sketch feature to the target layer.
|
||||
* @param {ol.MapBrowserEvent} event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.finishDrawing_ = function(event) {
|
||||
var sketchFeature = this.abortDrawing_();
|
||||
goog.asserts.assert(!goog.isNull(sketchFeature));
|
||||
sketchFeature.setRenderIntent(ol.FeatureRenderIntent.DEFAULT);
|
||||
var geometry = sketchFeature.getGeometry();
|
||||
var coordinates = geometry.getCoordinates();
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.LineString);
|
||||
// remove the redundant last point
|
||||
coordinates.pop();
|
||||
geometry.setCoordinates(coordinates);
|
||||
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||
// force clockwise order for exterior ring
|
||||
sketchFeature.setGeometry(new ol.geom.Polygon(coordinates));
|
||||
}
|
||||
// cast multi-part geometries
|
||||
if (this.type_ === ol.geom.GeometryType.MULTI_POINT) {
|
||||
sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates]));
|
||||
} else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) {
|
||||
sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates]));
|
||||
} else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) {
|
||||
sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));
|
||||
}
|
||||
this.layer_.getVectorSource().addFeatures([sketchFeature]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stop drawing without adding the sketch feature to the target layer.
|
||||
* @return {ol.Feature} The sketch feature (or null if none).
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.prototype.abortDrawing_ = function() {
|
||||
this.finishCoordinate_ = null;
|
||||
var sketchFeature = this.sketchFeature_;
|
||||
if (!goog.isNull(sketchFeature)) {
|
||||
var features = [sketchFeature];
|
||||
this.sketchFeature_ = null;
|
||||
if (this.mode_ !== ol.interaction.DrawMode.POINT) {
|
||||
features.push(this.sketchPoint_);
|
||||
this.sketchPoint_ = null;
|
||||
}
|
||||
this.sketchLayer_.getVectorSource().removeFeatures(features);
|
||||
}
|
||||
return sketchFeature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the drawing mode. The mode for mult-part geometries is the same as for
|
||||
* their single-part cousins.
|
||||
* @param {ol.geom.GeometryType} type Geometry type.
|
||||
* @return {ol.interaction.DrawMode} Drawing mode.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Draw.getMode_ = function(type) {
|
||||
var mode;
|
||||
if (type === ol.geom.GeometryType.POINT ||
|
||||
type === ol.geom.GeometryType.MULTI_POINT) {
|
||||
mode = ol.interaction.DrawMode.POINT;
|
||||
} else if (type === ol.geom.GeometryType.LINE_STRING ||
|
||||
type === ol.geom.GeometryType.MULTI_LINE_STRING) {
|
||||
mode = ol.interaction.DrawMode.LINESTRING;
|
||||
} else if (type === ol.geom.GeometryType.POLYGON ||
|
||||
type === ol.geom.GeometryType.MULTI_POLYGON) {
|
||||
mode = ol.interaction.DrawMode.POLYGON;
|
||||
}
|
||||
goog.asserts.assert(goog.isDef(mode));
|
||||
return mode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Draw mode. This collapses multi-part geometry types with their single-part
|
||||
* cousins.
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.interaction.DrawMode = {
|
||||
POINT: 'point',
|
||||
LINESTRING: 'linestring',
|
||||
POLYGON: 'polygon'
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportClass ol.layer.Vector ol.layer.VectorLayerOptions
|
||||
@@ -1,539 +0,0 @@
|
||||
goog.provide('ol.layer.Vector');
|
||||
goog.provide('ol.layer.VectorEventType');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureEventType');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.structs.RTree');
|
||||
goog.require('ol.style');
|
||||
goog.require('ol.style.Style');
|
||||
goog.require('ol.style.TextLiteral');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
ol.layer.FeatureCache = function() {
|
||||
|
||||
/**
|
||||
* @type {Object.<string, ol.Feature>}
|
||||
* @private
|
||||
*/
|
||||
this.idLookup_;
|
||||
|
||||
/**
|
||||
* @type {ol.structs.RTree}
|
||||
* @private
|
||||
*/
|
||||
this.rTree_;
|
||||
|
||||
this.clear();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.clear = function() {
|
||||
this.idLookup_ = {};
|
||||
this.rTree_ = new ol.structs.RTree();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a feature to the cache.
|
||||
* @param {ol.Feature} feature Feature to be cached.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.add = function(feature) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
this.idLookup_[id] = feature;
|
||||
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.rTree_.insert(geometry.getBounds(), feature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function() {
|
||||
return this.idLookup_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent) {
|
||||
return this.rTree_.searchReturningObject(extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get features by ids.
|
||||
* @param {Array.<string>} ids Array of (internal) identifiers.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesByIds_ = function(ids) {
|
||||
var len = ids.length,
|
||||
features = new Array(len),
|
||||
i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
features[i] = this.idLookup_[ids[i]];
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove a feature from the cache.
|
||||
* @param {ol.Feature} feature Feature.
|
||||
* @param {ol.Extent=} opt_extent Optional extent (used when the current feature
|
||||
* extent is different than the one in the index).
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.remove = function(feature, opt_extent) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
delete this.idLookup_[id];
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
var extent = goog.isDef(opt_extent) ? opt_extent : geometry.getBounds();
|
||||
this.rTree_.remove(extent, feature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.layer.Layer}
|
||||
* @param {ol.layer.VectorLayerOptions} options Vector layer options.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.layer.Vector = function(options) {
|
||||
|
||||
goog.base(this, /** @type {ol.layer.LayerOptions} */ (options));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.style.Style}
|
||||
*/
|
||||
this.style_ = goog.isDef(options.style) ? options.style : null;
|
||||
|
||||
/**
|
||||
* @type {ol.layer.FeatureCache}
|
||||
* @private
|
||||
*/
|
||||
this.featureCache_ = new ol.layer.FeatureCache();
|
||||
|
||||
/**
|
||||
* @type {function(Array.<ol.Feature>):string}
|
||||
* @private
|
||||
*/
|
||||
this.transformFeatureInfo_ = goog.isDef(options.transformFeatureInfo) ?
|
||||
options.transformFeatureInfo : ol.layer.Vector.uidTransformFeatureInfo;
|
||||
|
||||
/**
|
||||
* True if this is a temporary layer.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.temporary_ = false;
|
||||
|
||||
};
|
||||
goog.inherits(ol.layer.Vector, ol.layer.Layer);
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.addFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.featureCache_.add(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
goog.events.listen(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.listen(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.ADD,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for feature change events.
|
||||
* @param {ol.FeatureEvent} evt The feature change event.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.Vector.prototype.handleFeatureChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var extents = [];
|
||||
if (!goog.isNull(evt.oldExtent)) {
|
||||
extents.push(evt.oldExtent);
|
||||
}
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.featureCache_.remove(feature, evt.oldExtent);
|
||||
this.featureCache_.add(feature);
|
||||
extents.push(geometry.getBounds());
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE,
|
||||
[feature], extents));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for render intent change events of features.
|
||||
* @param {ol.FeatureEvent} evt The feature intent change event.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.Vector.prototype.handleIntentChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(
|
||||
ol.layer.VectorEventType.INTENTCHANGE, [feature],
|
||||
[geometry.getBounds()]));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all features from the layer.
|
||||
*/
|
||||
ol.layer.Vector.prototype.clear = function() {
|
||||
this.featureCache_.clear();
|
||||
this.dispatchEvent(
|
||||
new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE, [], []));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether this layer is temporary.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getTemporary = function() {
|
||||
return this.temporary_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.source.Vector} Source.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getVectorSource = function() {
|
||||
return /** @type {ol.source.Vector} */ (this.getSource());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.style.Style} This layer's style.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getStyle = function() {
|
||||
return this.style_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set a style for this layer.
|
||||
* @param {ol.style.Style} style Style.
|
||||
*/
|
||||
ol.layer.Vector.prototype.setStyle = function(style) {
|
||||
this.style_ = style;
|
||||
this.dispatchEvent(
|
||||
new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE, [], []));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of features that match a filter. This will not fetch data,
|
||||
* it only considers features that are loaded already.
|
||||
* @param {(function(ol.Feature):boolean)=} opt_filter Filter function.
|
||||
* @return {Array.<ol.Feature>} Features that match the filter, or all features
|
||||
* if no filter was provided.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
|
||||
var result;
|
||||
var features = this.featureCache_.getFeaturesObject();
|
||||
if (goog.isDef(opt_filter)) {
|
||||
result = [];
|
||||
for (var f in features) {
|
||||
if (opt_filter(features[f]) === true) {
|
||||
result.push(features[f]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = goog.object.getValues(features);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent. This
|
||||
* method is intended for being called by the renderer. When null is returned,
|
||||
* the renderer should not waste time rendering, and `opt_callback` is
|
||||
* usually a function that requests a renderFrame, which will be called as soon
|
||||
* as the data for `extent` is available.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.proj.Projection} projection Target projection.
|
||||
* @param {Function=} opt_callback Callback to call when data is parsed.
|
||||
* @return {Object.<string, ol.Feature>} Features or null if source is loading
|
||||
* data for `extent`.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
projection, opt_callback) {
|
||||
var source = this.getSource();
|
||||
return source.prepareFeatures(this, extent, projection, opt_callback) ==
|
||||
ol.source.VectorLoadState.LOADING ?
|
||||
null :
|
||||
this.featureCache_.getFeaturesObjectForExtent(extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object.<string, ol.Feature>} features Features.
|
||||
* @param {number} resolution Map resolution.
|
||||
* @return {Array.<Array>} symbolizers for features. Each array in this array
|
||||
* contains 3 items: an array of features, the symbolizer literal, and
|
||||
* an array with optional additional data for each feature.
|
||||
*/
|
||||
ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
|
||||
function(features, resolution) {
|
||||
var uniqueLiterals = {},
|
||||
featuresBySymbolizer = [],
|
||||
style = this.style_,
|
||||
i, j, l, feature, symbolizers, literals, numLiterals, literal,
|
||||
uniqueLiteral, key, item;
|
||||
for (i in features) {
|
||||
feature = features[i];
|
||||
// feature level symbolizers take precedence
|
||||
symbolizers = feature.getSymbolizers();
|
||||
if (!goog.isNull(symbolizers)) {
|
||||
literals = ol.style.Style.createLiterals(symbolizers, feature);
|
||||
} else {
|
||||
// layer style second
|
||||
if (goog.isNull(style)) {
|
||||
style = ol.style.getDefault();
|
||||
}
|
||||
literals = style.createLiterals(feature, resolution);
|
||||
}
|
||||
numLiterals = literals.length;
|
||||
for (j = 0; j < numLiterals; ++j) {
|
||||
literal = literals[j];
|
||||
for (l in uniqueLiterals) {
|
||||
uniqueLiteral = featuresBySymbolizer[uniqueLiterals[l]][1];
|
||||
if (literal.equals(uniqueLiteral)) {
|
||||
literal = uniqueLiteral;
|
||||
break;
|
||||
}
|
||||
}
|
||||
key = goog.getUid(literal);
|
||||
if (!goog.object.containsKey(uniqueLiterals, key)) {
|
||||
uniqueLiterals[key] = featuresBySymbolizer.length;
|
||||
featuresBySymbolizer.push([
|
||||
/** @type {Array.<ol.Feature>} */ ([]),
|
||||
/** @type {ol.style.Literal} */ (literal),
|
||||
/** @type {Array} */ ([])
|
||||
]);
|
||||
}
|
||||
item = featuresBySymbolizer[uniqueLiterals[key]];
|
||||
item[0].push(feature);
|
||||
if (literal instanceof ol.style.TextLiteral) {
|
||||
item[2].push(literals[j].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
featuresBySymbolizer.sort(this.sortByZIndex_);
|
||||
return featuresBySymbolizer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object|Element|Document|string} data Feature data.
|
||||
* @param {ol.parser.Parser} parser Feature parser.
|
||||
* @param {ol.proj.Projection} projection This sucks. The layer should be a
|
||||
* view in one projection.
|
||||
*/
|
||||
ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
|
||||
|
||||
var addFeatures = function(data) {
|
||||
var features = data.features;
|
||||
var sourceProjection = this.getSource().getProjection();
|
||||
if (goog.isNull(sourceProjection)) {
|
||||
sourceProjection = data.metadata.projection;
|
||||
}
|
||||
var transform = ol.proj.getTransform(sourceProjection, projection);
|
||||
var geometry = null;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
geometry = features[i].getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
geometry.transform(transform);
|
||||
}
|
||||
}
|
||||
this.addFeatures(features);
|
||||
};
|
||||
|
||||
var result;
|
||||
if (goog.isString(data)) {
|
||||
if (goog.isFunction(parser.readFeaturesFromStringAsync)) {
|
||||
parser.readFeaturesFromStringAsync(data, goog.bind(addFeatures, this));
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
goog.isFunction(parser.readFeaturesFromString),
|
||||
'Expected parser with a readFeaturesFromString method.');
|
||||
result = parser.readFeaturesFromString(data);
|
||||
addFeatures.call(this, result);
|
||||
}
|
||||
} else if (goog.isObject(data)) {
|
||||
if (goog.isFunction(parser.readFeaturesFromObjectAsync)) {
|
||||
parser.readFeaturesFromObjectAsync(data, goog.bind(addFeatures, this));
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
goog.isFunction(parser.readFeaturesFromObject),
|
||||
'Expected parser with a readFeaturesFromObject method.');
|
||||
result = parser.readFeaturesFromObject(data);
|
||||
addFeatures.call(this, result);
|
||||
}
|
||||
} else {
|
||||
// TODO: parse more data types
|
||||
throw new Error('Data type not supported: ' + data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {function(Array.<ol.Feature>):string} Feature info function.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getTransformFeatureInfo = function() {
|
||||
return this.transformFeatureInfo_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove features from the layer.
|
||||
* @param {Array.<ol.Feature>} features Features to remove.
|
||||
*/
|
||||
ol.layer.Vector.prototype.removeFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.featureCache_.remove(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} temporary Whether this layer is temporary.
|
||||
*/
|
||||
ol.layer.Vector.prototype.setTemporary = function(temporary) {
|
||||
this.temporary_ = temporary;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sort function for `groupFeaturesBySymbolizerLiteral`.
|
||||
* @private
|
||||
* @param {Array} a 1st item for the sort comparison.
|
||||
* @param {Array} b 2nd item for the sort comparison.
|
||||
* @return {number} Comparison result.
|
||||
*/
|
||||
ol.layer.Vector.prototype.sortByZIndex_ = function(a, b) {
|
||||
return a[1].zIndex - b[1].zIndex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Features.
|
||||
* @return {string} Feature info.
|
||||
*/
|
||||
ol.layer.Vector.uidTransformFeatureInfo = function(features) {
|
||||
var uids = goog.array.map(features,
|
||||
function(feature) { return goog.getUid(feature); });
|
||||
return uids.join(', ');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
* @return {boolean} Whether the feature is selected.
|
||||
*/
|
||||
ol.layer.Vector.selectedFeaturesFilter = function(feature) {
|
||||
return feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.SELECTED;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
* @param {string} type Event type.
|
||||
* @param {Array.<ol.Feature>} features Features associated with the event.
|
||||
* @param {Array.<ol.Extent>} extents Any extents associated with the event.
|
||||
*/
|
||||
ol.layer.VectorEvent = function(type, features, extents) {
|
||||
|
||||
goog.base(this, type);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Feature>}
|
||||
*/
|
||||
this.features = features;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Extent>}
|
||||
*/
|
||||
this.extents = extents;
|
||||
|
||||
};
|
||||
goog.inherits(ol.layer.VectorEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.layer.VectorEventType = {
|
||||
ADD: 'featureadd',
|
||||
CHANGE: 'featurechange',
|
||||
INTENTCHANGE: 'featureintentchange',
|
||||
REMOVE: 'featureremove'
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.parser.GeoJSON
|
||||
@@ -1,419 +0,0 @@
|
||||
goog.provide('ol.parser.GeoJSON');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.parser.Parser');
|
||||
goog.require('ol.parser.ReadFeaturesResult');
|
||||
goog.require('ol.parser.StringFeatureParser');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read and write [GeoJSON](http://geojson.org/)
|
||||
*
|
||||
* @constructor
|
||||
* @implements {ol.parser.StringFeatureParser}
|
||||
* @extends {ol.parser.Parser}
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.parser.GeoJSON = function() {};
|
||||
goog.inherits(ol.parser.GeoJSON, ol.parser.Parser);
|
||||
goog.addSingletonGetter(ol.parser.GeoJSON);
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GeoJSON string.
|
||||
* @param {string} str GeoJSON string.
|
||||
* @return {ol.Feature|Array.<ol.Feature>|
|
||||
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
|
||||
* of geometries.
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.read = function(str) {
|
||||
var json = /** @type {GeoJSONObject} */ (JSON.parse(str));
|
||||
return this.parse_(json);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GeoJSON string.
|
||||
* @param {string} str GeoJSON string.
|
||||
* @return {ol.Feature|Array.<ol.Feature>|
|
||||
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
|
||||
* of geometries.
|
||||
*/
|
||||
ol.parser.GeoJSON.read = function(str) {
|
||||
return ol.parser.GeoJSON.getInstance().read(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GeoJSON feature collection.
|
||||
* @param {string} str GeoJSON feature collection.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.readFeaturesFromString = function(str) {
|
||||
var json = /** @type {GeoJSONFeatureCollection} */ (JSON.parse(str));
|
||||
return this.parseAsFeatureCollection_(json);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GeoJSON feature collection from decoded JSON.
|
||||
* @param {GeoJSONFeatureCollection} object GeoJSON feature collection decoded
|
||||
* from JSON.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.readFeaturesFromObject = function(object) {
|
||||
return this.parseAsFeatureCollection_(object);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse any GeoJSON object.
|
||||
*
|
||||
* @param {GeoJSONObject} json GeoJSON object.
|
||||
* @return {ol.Feature|Array.<ol.Feature>|
|
||||
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
|
||||
* of geometries.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parse_ = function(json) {
|
||||
var result;
|
||||
if (json.type === 'FeatureCollection') {
|
||||
result = this.parseFeatureCollection_(
|
||||
/** @type {GeoJSONFeatureCollection} */ (json));
|
||||
} else if (json.type === 'Feature') {
|
||||
result = this.parseFeature_(
|
||||
/** @type {GeoJSONFeature} */ (json));
|
||||
} else if (json.type === 'GeometryCollection') {
|
||||
result = this.parseGeometryCollection_(
|
||||
/** @type {GeoJSONGeometryCollection} */ (json));
|
||||
} else {
|
||||
// we've been called with a geometry or an unknown object
|
||||
// create a feature to get shared vertices handling
|
||||
var feature = this.parseFeature_(
|
||||
/** @type {GeoJSONFeature} */ ({type: 'Feature', geometry: json}));
|
||||
result = feature.getGeometry();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONObject} json GeoJSON object.
|
||||
* @return {ol.parser.ReadFeaturesResult} Parsed object coerced into array of
|
||||
* features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseAsFeatureCollection_ = function(json) {
|
||||
var obj = this.parse_(json);
|
||||
var features = [];
|
||||
var feature;
|
||||
if (obj instanceof ol.Feature) {
|
||||
features = [obj];
|
||||
} else if (obj instanceof ol.geom.Geometry) {
|
||||
feature = new ol.Feature();
|
||||
feature.setGeometry(obj);
|
||||
features = [feature];
|
||||
} else if (goog.isArray(obj)) {
|
||||
var item, geomArray;
|
||||
for (var i = 0, ii = obj.length; i < ii; ++i) {
|
||||
item = obj[i];
|
||||
geomArray = geomArray || (item instanceof ol.geom.Geometry);
|
||||
if (!geomArray) {
|
||||
goog.asserts.assert(item instanceof ol.Feature, 'expected feature');
|
||||
features = obj;
|
||||
break;
|
||||
} else {
|
||||
feature = new ol.Feature();
|
||||
feature.setGeometry(item);
|
||||
features[i] = feature;
|
||||
}
|
||||
}
|
||||
}
|
||||
var projection = 'EPSG:4326';
|
||||
if (goog.isDefAndNotNull(json.crs)) {
|
||||
var crs = json.crs;
|
||||
if (crs.type === 'name') {
|
||||
projection = (/** GeoJSONCRSName */ (crs.properties)).name;
|
||||
}
|
||||
}
|
||||
return {features: features, metadata: {projection: projection}};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONFeature} json GeoJSON feature.
|
||||
* @return {ol.Feature} Parsed feature.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseFeature_ = function(json) {
|
||||
var geomJson = json.geometry,
|
||||
geometry = null;
|
||||
var feature = new ol.Feature(json.properties);
|
||||
if (goog.isDef(json.id)) {
|
||||
feature.setId(json.id);
|
||||
}
|
||||
if (geomJson) {
|
||||
var type = geomJson.type;
|
||||
switch (type) {
|
||||
case 'Point':
|
||||
geometry = this.parsePoint_(geomJson);
|
||||
break;
|
||||
case 'LineString':
|
||||
geometry = this.parseLineString_(geomJson);
|
||||
break;
|
||||
case 'Polygon':
|
||||
geometry = this.parsePolygon_(geomJson);
|
||||
break;
|
||||
case 'MultiPoint':
|
||||
geometry = this.parseMultiPoint_(geomJson);
|
||||
break;
|
||||
case 'MultiLineString':
|
||||
geometry = this.parseMultiLineString_(geomJson);
|
||||
break;
|
||||
case 'MultiPolygon':
|
||||
geometry = this.parseMultiPolygon_(geomJson);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Bad geometry type: ' + type);
|
||||
}
|
||||
feature.setGeometry(geometry);
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONFeatureCollection} json GeoJSON feature collection.
|
||||
* @return {Array.<ol.Feature>} Parsed array of features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseFeatureCollection_ = function(json) {
|
||||
var features = json.features,
|
||||
len = features.length,
|
||||
result = new Array(len),
|
||||
i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
result[i] = this.parseFeature_(/** @type {GeoJSONFeature} */ (features[i]));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometryCollection} json GeoJSON geometry collection.
|
||||
* @return {Array.<ol.geom.Geometry>} Parsed array of geometries.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json) {
|
||||
var geometries = json.geometries,
|
||||
len = geometries.length,
|
||||
result = new Array(len),
|
||||
i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i]));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON linestring.
|
||||
* @return {ol.geom.LineString} Parsed linestring.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseLineString_ = function(json) {
|
||||
return new ol.geom.LineString(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON multi-linestring.
|
||||
* @return {ol.geom.MultiLineString} Parsed multi-linestring.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseMultiLineString_ = function(json) {
|
||||
return new ol.geom.MultiLineString(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON multi-point.
|
||||
* @return {ol.geom.MultiPoint} Parsed multi-point.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseMultiPoint_ = function(json) {
|
||||
return new ol.geom.MultiPoint(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON multi-polygon.
|
||||
* @return {ol.geom.MultiPolygon} Parsed multi-polygon.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parseMultiPolygon_ = function(json) {
|
||||
return new ol.geom.MultiPolygon(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON point.
|
||||
* @return {ol.geom.Point} Parsed point.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parsePoint_ = function(json) {
|
||||
return new ol.geom.Point(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {GeoJSONGeometry} json GeoJSON polygon.
|
||||
* @return {ol.geom.Polygon} Parsed polygon.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.parsePolygon_ = function(json) {
|
||||
return new ol.geom.Polygon(json.coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom.Geometry} geometry Geometry to encode.
|
||||
* @return {GeoJSONGeometry} GeoJSON geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.encodeGeometry_ = function(geometry) {
|
||||
var type = geometry.getType();
|
||||
return /** @type {GeoJSONGeometry} */({
|
||||
type: goog.object.findKey(ol.parser.GeoJSON.GeometryType,
|
||||
function(value, key) {
|
||||
return value === type;
|
||||
}
|
||||
),
|
||||
coordinates: geometry.getCoordinates()
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom.GeometryCollection} collection Geometry collection to
|
||||
* encode.
|
||||
* @return {GeoJSONGeometryCollection} GeoJSON geometry collection.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.encodeGeometryCollection_ = function(collection) {
|
||||
var geometries = [];
|
||||
var components = collection.getComponents();
|
||||
for (var i = 0, ii = components.length; i < ii; ++i) {
|
||||
geometries.push(this.encodeGeometry_(components[i]));
|
||||
}
|
||||
return /** @type {GeoJSONGeometryCollection} */({
|
||||
type: 'GeometryCollection',
|
||||
geometries: geometries
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} collection Feature collection to encode.
|
||||
* @return {GeoJSONFeatureCollection} GeoJSON feature collection.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.encodeFeatureCollection_ = function(collection) {
|
||||
var features = [];
|
||||
for (var i = 0, ii = collection.length; i < ii; ++i) {
|
||||
features.push(this.encodeFeature_(collection[i]));
|
||||
}
|
||||
return /** @type {GeoJSONFeatureCollection} */({
|
||||
type: 'FeatureCollection',
|
||||
features: features
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature to encode.
|
||||
* @return {GeoJSONFeature} GeoJSON feature.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.encodeFeature_ = function(feature) {
|
||||
var geometry = feature.getGeometry(),
|
||||
properties = feature.getAttributes(true);
|
||||
return /** @type {GeoJSONFeature} */({
|
||||
type: 'Feature',
|
||||
properties: properties,
|
||||
geometry: this.encodeGeometry_(geometry)
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom.GeometryCollection|ol.geom.Geometry|Array.<ol.Feature>|
|
||||
* ol.Feature} obj The object to encode.
|
||||
* @return {string} The GeoJSON as string.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.encode_ = function(obj) {
|
||||
var result;
|
||||
if (obj instanceof ol.geom.GeometryCollection) {
|
||||
result = this.encodeGeometryCollection_(obj);
|
||||
} else if (obj instanceof ol.geom.Geometry) {
|
||||
result = this.encodeGeometry_(obj);
|
||||
} else if (obj instanceof ol.Feature) {
|
||||
result = this.encodeFeature_(obj);
|
||||
} else if (goog.isArray(obj)) {
|
||||
result = this.encodeFeatureCollection_(obj);
|
||||
}
|
||||
return JSON.stringify(result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Write out a geometry, geometry collection, feature or an array of features
|
||||
* as a GeoJSON string.
|
||||
* @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature|
|
||||
* Array.<ol.Feature>} obj The object to encode.
|
||||
* @return {string} GeoJSON for the geometry.
|
||||
*/
|
||||
ol.parser.GeoJSON.write = function(obj) {
|
||||
return ol.parser.GeoJSON.getInstance().write(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Write out a geometry, geometry collection, feature or an array of features
|
||||
* as a GeoJSON string.
|
||||
* @param {ol.geom.Geometry|ol.geom.GeometryCollection|ol.Feature|
|
||||
* Array.<ol.Feature>} obj The object to encode.
|
||||
* @return {string} GeoJSON for the geometry.
|
||||
*/
|
||||
ol.parser.GeoJSON.prototype.write = function(obj) {
|
||||
return this.encode_(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {ol.geom.GeometryType}
|
||||
*/
|
||||
ol.parser.GeoJSON.GeometryType = {
|
||||
'Point': ol.geom.GeometryType.POINT,
|
||||
'LineString': ol.geom.GeometryType.LINE_STRING,
|
||||
'Polygon': ol.geom.GeometryType.POLYGON,
|
||||
'MultiPoint': ol.geom.GeometryType.MULTI_POINT,
|
||||
'MultiLineString': ol.geom.GeometryType.MULTI_LINE_STRING,
|
||||
'MultiPolygon': ol.geom.GeometryType.MULTI_POLYGON,
|
||||
'GeometryCollection': ol.geom.GeometryType.GEOMETRY_COLLECTION
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.parser.GPX
|
||||
@@ -1,291 +0,0 @@
|
||||
goog.provide('ol.parser.GPX');
|
||||
|
||||
goog.require('goog.dom.xml');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.parser.DomFeatureParser');
|
||||
goog.require('ol.parser.ObjectFeatureParser');
|
||||
goog.require('ol.parser.StringFeatureParser');
|
||||
goog.require('ol.parser.XML');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read and write [GPX](http://www.topografix.com/gpx.asp) version 1.1
|
||||
*
|
||||
* @constructor
|
||||
* @implements {ol.parser.DomFeatureParser}
|
||||
* @implements {ol.parser.StringFeatureParser}
|
||||
* @implements {ol.parser.ObjectFeatureParser}
|
||||
* @param {olx.parser.GPXOptions=} opt_options Optional configuration object.
|
||||
* @extends {ol.parser.XML}
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.parser.GPX = function(opt_options) {
|
||||
var options = /** @type {olx.parser.GPXOptions} */
|
||||
(goog.isDef(opt_options) ? opt_options : {});
|
||||
this.extractAttributes = goog.isDef(options.extractAttributes) ?
|
||||
options.extractAttributes : true;
|
||||
this.extractWaypoints = goog.isDef(options.extractWaypoints) ?
|
||||
options.extractWaypoints : true;
|
||||
this.extractTracks = goog.isDef(options.extractTracks) ?
|
||||
options.extractTracks : true;
|
||||
this.extractRoutes = goog.isDef(options.extractRoutes) ?
|
||||
options.extractRoutes : true;
|
||||
this.creator = goog.isDef(options.creator) ?
|
||||
options.creator : 'OpenLayers';
|
||||
this.defaultDesc = goog.isDef(options.defaultDesc) ?
|
||||
options.defaultDesc : 'No description available';
|
||||
this.defaultNamespaceURI = 'http://www.topografix.com/GPX/1/1';
|
||||
this.schemaLocation = 'http://www.topografix.com/GPX/1/1 ' +
|
||||
'http://www.topografix.com/GPX/1/1/gpx.xsd';
|
||||
this.readers = {
|
||||
'http://www.topografix.com/GPX/1/1': {
|
||||
'gpx': function(node, obj) {
|
||||
if (!goog.isDef(obj.features)) {
|
||||
obj.features = [];
|
||||
}
|
||||
this.readChildNodes(node, obj);
|
||||
},
|
||||
'wpt': function(node, obj) {
|
||||
if (this.extractWaypoints) {
|
||||
var properties = {};
|
||||
var coordinates = [parseFloat(node.getAttribute('lon')),
|
||||
parseFloat(node.getAttribute('lat'))];
|
||||
this.readChildNodes(node, properties);
|
||||
var feature = new ol.Feature(properties);
|
||||
var geometry = new ol.geom.Point(coordinates);
|
||||
feature.setGeometry(geometry);
|
||||
obj.features.push(feature);
|
||||
}
|
||||
},
|
||||
'rte': function(node, obj) {
|
||||
if (this.extractRoutes || obj.force) {
|
||||
var type = ol.geom.GeometryType.LINE_STRING;
|
||||
var container = {
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: type,
|
||||
coordinates: []
|
||||
}
|
||||
};
|
||||
this.readChildNodes(node, container);
|
||||
var feature = new ol.Feature(container.properties);
|
||||
var geometry = new ol.geom.LineString(container.geometry.coordinates);
|
||||
feature.setGeometry(geometry);
|
||||
obj.features.push(feature);
|
||||
}
|
||||
},
|
||||
'rtept': function(node, container) {
|
||||
var coordinate = [parseFloat(node.getAttribute('lon')),
|
||||
parseFloat(node.getAttribute('lat'))];
|
||||
container.geometry.coordinates.push(coordinate);
|
||||
},
|
||||
'trk': function(node, obj) {
|
||||
if (this.extractTracks) {
|
||||
var readers = this.readers[this.defaultNamespaceURI];
|
||||
obj.force = true;
|
||||
readers['rte'].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
'trkseg': function(node, container) {
|
||||
this.readChildNodes(node, container);
|
||||
},
|
||||
'trkpt': function(node, container) {
|
||||
var readers = this.readers[this.defaultNamespaceURI];
|
||||
readers['rtept'].apply(this, arguments);
|
||||
},
|
||||
'*': function(node, obj) {
|
||||
if (this.extractAttributes === true) {
|
||||
var len = node.childNodes.length;
|
||||
if ((len === 1 || len === 2) && (node.firstChild.nodeType === 3 ||
|
||||
node.firstChild.nodeType === 4)) {
|
||||
var readers = this.readers[this.defaultNamespaceURI];
|
||||
readers['_attribute'].apply(this, arguments);
|
||||
}
|
||||
}
|
||||
},
|
||||
'_attribute': function(node, obj) {
|
||||
var local = node.localName || node.nodeName.split(':').pop();
|
||||
var value = this.getChildValue(node);
|
||||
if (obj.properties) {
|
||||
obj.properties[local] = value.replace(this.regExes.trimSpace, '');
|
||||
} else {
|
||||
obj[local] = value.replace(this.regExes.trimSpace, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// create an alias for GXP 1.0
|
||||
this.readers['http://www.topografix.com/GPX/1/0'] =
|
||||
this.readers[this.defaultNamespaceURI];
|
||||
this.writers = {
|
||||
'http://www.topografix.com/GPX/1/1': {
|
||||
'_feature': function(feature) {
|
||||
var geom = feature.getGeometry();
|
||||
if (geom instanceof ol.geom.Point) {
|
||||
return this.writeNode('wpt', feature);
|
||||
} else if ((geom instanceof ol.geom.LineString) ||
|
||||
(geom instanceof ol.geom.MultiLineString) ||
|
||||
(geom instanceof ol.geom.Polygon)) {
|
||||
return this.writeNode('trk', feature);
|
||||
}
|
||||
},
|
||||
'wpt': function(feature) {
|
||||
var node = this.createElementNS('wpt');
|
||||
var geom = feature.getGeometry();
|
||||
var coordinates = geom.getCoordinates();
|
||||
node.setAttribute('lon', coordinates[0]);
|
||||
node.setAttribute('lat', coordinates[1]);
|
||||
var attributes = feature.getAttributes();
|
||||
var name = attributes['name'] || goog.getUid(feature).toString();
|
||||
this.writeNode('name', name, undefined, node);
|
||||
var desc = attributes['description'] || this.defaultDesc;
|
||||
this.writeNode('desc', desc, undefined, node);
|
||||
return node;
|
||||
},
|
||||
'trk': function(feature) {
|
||||
var attributes = feature.getAttributes();
|
||||
var node = this.createElementNS('trk');
|
||||
var name = attributes['name'] || goog.getUid(feature).toString();
|
||||
this.writeNode('name', name, undefined, node);
|
||||
var desc = attributes['description'] || this.defaultDesc;
|
||||
this.writeNode('desc', desc, undefined, node);
|
||||
var geom = feature.getGeometry();
|
||||
var i, ii, rings;
|
||||
if (geom instanceof ol.geom.LineString) {
|
||||
this.writeNode('trkseg', feature.getGeometry(), undefined, node);
|
||||
} else if (geom instanceof ol.geom.MultiLineString) {
|
||||
var components = geom.getComponents();
|
||||
for (i = 0, ii = components.length; i < ii; ++i) {
|
||||
this.writeNode('trkseg', components[i], undefined, node);
|
||||
}
|
||||
} else if (geom instanceof ol.geom.Polygon) {
|
||||
rings = geom.getRings();
|
||||
for (i = 0, ii = rings.length; i < ii; ++i) {
|
||||
this.writeNode('trkseg', rings[i], undefined, node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
},
|
||||
'trkseg': function(geometry) {
|
||||
var node = this.createElementNS('trkseg');
|
||||
var coordinates = geometry.getCoordinates();
|
||||
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
this.writeNode('trkpt', coordinates[i], undefined, node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
'trkpt': function(coord) {
|
||||
var node = this.createElementNS('trkpt');
|
||||
node.setAttribute('lon', coord[0]);
|
||||
node.setAttribute('lat', coord[1]);
|
||||
return node;
|
||||
},
|
||||
'metadata': function(metadata) {
|
||||
var node = this.createElementNS('metadata');
|
||||
if (goog.isDef(metadata['name'])) {
|
||||
this.writeNode('name', metadata['name'], undefined, node);
|
||||
}
|
||||
if (goog.isDef(metadata['desc'])) {
|
||||
this.writeNode('desc', metadata['desc'], undefined, node);
|
||||
}
|
||||
if (goog.isDef(metadata['author'])) {
|
||||
this.writeNode('author', metadata['author'], undefined, node);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
'name': function(name) {
|
||||
var node = this.createElementNS('name');
|
||||
node.appendChild(this.createTextNode(name));
|
||||
return node;
|
||||
},
|
||||
'desc': function(desc) {
|
||||
var node = this.createElementNS('desc');
|
||||
node.appendChild(this.createTextNode(desc));
|
||||
return node;
|
||||
},
|
||||
'author': function(author) {
|
||||
var node = this.createElementNS('author');
|
||||
node.appendChild(this.createTextNode(author));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
};
|
||||
goog.base(this);
|
||||
};
|
||||
goog.inherits(ol.parser.GPX, ol.parser.XML);
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|Document|Element|Object} data Data to read.
|
||||
* @return {ol.parser.ReadFeaturesResult} An object representing the document.
|
||||
*/
|
||||
ol.parser.GPX.prototype.read = function(data) {
|
||||
if (goog.isString(data)) {
|
||||
data = goog.dom.xml.loadXml(data);
|
||||
}
|
||||
if (data && data.nodeType == 9) {
|
||||
data = data.documentElement;
|
||||
}
|
||||
var obj = /** @type {ol.parser.ReadFeaturesResult} */
|
||||
({metadata: {projection: 'EPSG:4326'}});
|
||||
this.readNode(data, obj);
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GPX document provided as a string.
|
||||
* @param {string} str GPX document.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.GPX.prototype.readFeaturesFromString = function(str) {
|
||||
return this.read(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a GPX document provided as a DOM structure.
|
||||
* @param {Element|Document} node Document or element node.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.GPX.prototype.readFeaturesFromNode = function(node) {
|
||||
return this.read(node);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object} obj Object representing features.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.GPX.prototype.readFeaturesFromObject = function(obj) {
|
||||
return this.read(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {olx.parser.GPXWriteOptions} obj Object structure to write out
|
||||
* as GPX.
|
||||
* @return {string} An string representing the GPX document.
|
||||
*/
|
||||
ol.parser.GPX.prototype.write = function(obj) {
|
||||
var features = goog.isArray(obj.features) ? obj.features : [obj.features];
|
||||
var root = this.createElementNS('gpx');
|
||||
root.setAttribute('version', '1.1');
|
||||
root.setAttribute('creator', this.creator);
|
||||
this.setAttributeNS(
|
||||
root, 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xsi:schemaLocation', this.schemaLocation);
|
||||
if (goog.isDef(obj.metadata)) {
|
||||
this.writeNode('metadata', obj.metadata, undefined, root);
|
||||
}
|
||||
for (var i = 0, ii = features.length; i < ii; i++) {
|
||||
this.writeNode('_feature', features[i], undefined, root);
|
||||
}
|
||||
return this.serialize(root);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.parser.KML
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
@exportSymbol ol.parser.TopoJSON
|
||||
@@ -1,382 +0,0 @@
|
||||
goog.provide('ol.parser.TopoJSON');
|
||||
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.parser.Parser');
|
||||
goog.require('ol.parser.StringFeatureParser');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Read [TopoJSON](https://github.com/mbostock/topojson)
|
||||
*
|
||||
* @constructor
|
||||
* @implements {ol.parser.StringFeatureParser}
|
||||
* @extends {ol.parser.Parser}
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.parser.TopoJSON = function() {};
|
||||
goog.inherits(ol.parser.TopoJSON, ol.parser.Parser);
|
||||
goog.addSingletonGetter(ol.parser.TopoJSON);
|
||||
|
||||
|
||||
/**
|
||||
* Concatenate arcs into a coordinate array.
|
||||
* @param {Array.<number>} indices Indices of arcs to concatenate. Negative
|
||||
* values indicate arcs need to be reversed.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Arcs (already transformed).
|
||||
* @return {ol.CoordinateArray} Coordinate array.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.concatenateArcs_ = function(indices, arcs) {
|
||||
var coordinates = [];
|
||||
var index, arc;
|
||||
for (var i = 0, ii = indices.length; i < ii; ++i) {
|
||||
index = indices[i];
|
||||
if (i > 0) {
|
||||
// splicing together arcs, discard last point
|
||||
coordinates.pop();
|
||||
}
|
||||
if (index >= 0) {
|
||||
// forward arc
|
||||
arc = arcs[index];
|
||||
} else {
|
||||
// reverse arc
|
||||
arc = arcs[~index].slice().reverse();
|
||||
}
|
||||
coordinates.push.apply(coordinates, arc);
|
||||
}
|
||||
// provide fresh copies of coordinate arrays
|
||||
for (var j = 0, jj = coordinates.length; j < jj; ++j) {
|
||||
coordinates[j] = coordinates[j].slice();
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a TopoJSON string.
|
||||
* @param {string} str TopoJSON string.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.read = function(str) {
|
||||
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
|
||||
return this.readFeaturesFromObject(topology).features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON topology string.
|
||||
*
|
||||
* @param {string} str TopoJSON topology string.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromString = function(str) {
|
||||
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
|
||||
if (topology.type !== 'Topology') {
|
||||
throw new Error('Not a "Topology" type object');
|
||||
}
|
||||
return {
|
||||
features: this.readFeaturesFromTopology_(topology),
|
||||
metadata: {projection: 'EPSG:4326'}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON topology object.
|
||||
*
|
||||
* @param {TopoJSONTopology} topology TopoJSON topology object.
|
||||
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromObject = function(topology) {
|
||||
if (topology.type !== 'Topology') {
|
||||
throw new Error('Not a "Topology" type object');
|
||||
}
|
||||
return {
|
||||
features: this.readFeaturesFromTopology_(topology),
|
||||
metadata: {projection: 'EPSG:4326'}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a feature from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONGeometry} object TopoJSON geometry object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @return {ol.Feature} Feature.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeatureFromGeometry_ = function(object, arcs,
|
||||
scale, translate) {
|
||||
var geometry;
|
||||
var type = object.type;
|
||||
if (type === 'Point') {
|
||||
geometry = this.readPoint_(/** @type {TopoJSONPoint} */ (object), scale,
|
||||
translate);
|
||||
} else if (type === 'LineString') {
|
||||
geometry = this.readLineString_(/** @type {TopoJSONLineString} */ (object),
|
||||
arcs);
|
||||
} else if (type === 'Polygon') {
|
||||
geometry = this.readPolygon_(/** @type {TopoJSONPolygon} */ (object), arcs);
|
||||
} else if (type === 'MultiPoint') {
|
||||
geometry = this.readMultiPoint_(/** @type {TopoJSONMultiPoint} */ (object),
|
||||
scale, translate);
|
||||
} else if (type === 'MultiLineString') {
|
||||
geometry = this.readMultiLineString_(
|
||||
/** @type {TopoJSONMultiLineString} */(object), arcs);
|
||||
} else if (type === 'MultiPolygon') {
|
||||
geometry = this.readMultiPolygon_(
|
||||
/** @type {TopoJSONMultiPolygon} */ (object), arcs);
|
||||
} else {
|
||||
throw new Error('Unsupported geometry type: ' + type);
|
||||
}
|
||||
var feature = new ol.Feature();
|
||||
feature.setGeometry(geometry);
|
||||
if (goog.isDef(object.id)) {
|
||||
feature.setId(String(object.id));
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON GeometryCollection object.
|
||||
*
|
||||
* @param {TopoJSONGeometryCollection} collection TopoJSON GeometryCollection
|
||||
* object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromGeometryCollection_ = function(
|
||||
collection, arcs, scale, translate) {
|
||||
var geometries = collection.geometries;
|
||||
var num = geometries.length;
|
||||
var features = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
features[i] = this.readFeatureFromGeometry_(geometries[i], arcs, scale,
|
||||
translate);
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {TopoJSONTopology} topology TopoJSON object.
|
||||
* @return {Array.<ol.Feature>} Parsed features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromTopology_ = function(topology) {
|
||||
var transform = topology.transform;
|
||||
var scale = transform.scale;
|
||||
var translate = transform.translate;
|
||||
var arcs = topology.arcs;
|
||||
this.transformArcs_(arcs, scale, translate);
|
||||
var objects = topology.objects;
|
||||
var features = [];
|
||||
for (var key in objects) {
|
||||
if (objects[key].type === 'GeometryCollection') {
|
||||
features.push.apply(features, this.readFeaturesFromGeometryCollection_(
|
||||
/** @type {TopoJSONGeometryCollection} */ (objects[key]),
|
||||
arcs, scale, translate));
|
||||
} else {
|
||||
features.push(this.readFeatureFromGeometry_(
|
||||
/** @type {TopoJSONGeometry} */ (objects[key]),
|
||||
arcs, scale, translate));
|
||||
}
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a linestring from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONLineString} object TopoJSON object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @return {ol.geom.LineString} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readLineString_ = function(object, arcs) {
|
||||
var coordinates = this.concatenateArcs_(object.arcs, arcs);
|
||||
return new ol.geom.LineString(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-linestring from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiLineString} object TopoJSON object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @return {ol.geom.MultiLineString} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiLineString_ = function(object, arcs) {
|
||||
var array = object.arcs; // I'm out of good names
|
||||
var num = array.length;
|
||||
var coordinates = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
coordinates[i] = this.concatenateArcs_(array[i], arcs);
|
||||
}
|
||||
return new ol.geom.MultiLineString(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-point from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiPoint} object TopoJSON object.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @return {ol.geom.MultiPoint} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiPoint_ = function(object, scale,
|
||||
translate) {
|
||||
var coordinates = object.coordinates;
|
||||
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
this.transformVertex_(coordinates[i], scale, translate);
|
||||
}
|
||||
return new ol.geom.MultiPoint(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-polygon from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiPolygon} object TopoJSON object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @return {ol.geom.MultiPolygon} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiPolygon_ = function(object, arcs) {
|
||||
var array = object.arcs;
|
||||
var numPolys = array.length;
|
||||
var coordinates = new Array(numPolys);
|
||||
var polyArray, numRings, ringCoords, j;
|
||||
for (var i = 0; i < numPolys; ++i) {
|
||||
// for each polygon
|
||||
polyArray = array[i];
|
||||
numRings = polyArray.length;
|
||||
ringCoords = new Array(numRings);
|
||||
for (j = 0; j < numRings; ++j) {
|
||||
// for each ring
|
||||
ringCoords[j] = this.concatenateArcs_(polyArray[j], arcs);
|
||||
}
|
||||
coordinates[i] = ringCoords;
|
||||
}
|
||||
return new ol.geom.MultiPolygon(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a point from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONPoint} object TopoJSON object.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @return {ol.geom.Point} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readPoint_ = function(object, scale, translate) {
|
||||
var coordinates = object.coordinates;
|
||||
this.transformVertex_(coordinates, scale, translate);
|
||||
return new ol.geom.Point(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONPolygon} object TopoJSON object.
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @return {ol.geom.Polygon} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readPolygon_ = function(object, arcs) {
|
||||
var array = object.arcs; // I'm out of good names
|
||||
var num = array.length;
|
||||
var coordinates = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
coordinates[i] = this.concatenateArcs_(array[i], arcs);
|
||||
}
|
||||
return new ol.geom.Polygon(coordinates);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to array of arcs. The provided array of arcs is
|
||||
* modified in place.
|
||||
*
|
||||
* @param {Array.<ol.CoordinateArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformArcs_ = function(arcs, scale, translate) {
|
||||
for (var i = 0, ii = arcs.length; i < ii; ++i) {
|
||||
this.transformArc_(arcs[i], scale, translate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to an arc. The provided arc is modified in place.
|
||||
*
|
||||
* @param {ol.CoordinateArray} arc Arc.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformArc_ = function(arc, scale, translate) {
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var vertex;
|
||||
for (var i = 0, ii = arc.length; i < ii; ++i) {
|
||||
vertex = arc[i];
|
||||
x += vertex[0];
|
||||
y += vertex[1];
|
||||
vertex[0] = x;
|
||||
vertex[1] = y;
|
||||
this.transformVertex_(vertex, scale, translate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to a vertex. The provided vertex is modified in
|
||||
* place.
|
||||
*
|
||||
* @param {ol.Coordinate} vertex Vertex.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformVertex_ = function(vertex, scale,
|
||||
translate) {
|
||||
vertex[0] = vertex[0] * scale[0] + translate[0];
|
||||
vertex[1] = vertex[1] * scale[1] + translate[1];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a TopoJSON string.
|
||||
* @param {string} str TopoJSON string.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.read = function(str) {
|
||||
return ol.parser.TopoJSON.getInstance().read(str);
|
||||
};
|
||||
@@ -1,581 +0,0 @@
|
||||
goog.provide('ol.renderer.canvas.VectorLayer');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Pixel');
|
||||
goog.require('ol.TileCache');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorEventType');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.renderer.canvas.Layer');
|
||||
goog.require('ol.renderer.canvas.Vector');
|
||||
goog.require('ol.tilegrid.TileGrid');
|
||||
|
||||
|
||||
/**
|
||||
* Resolution at zoom level 21 in a web mercator default tiling scheme. This
|
||||
* is a workaround for browser bugs that cause line segments to disappear when
|
||||
* they get too long. TODO: Use line clipping as a better work around. See
|
||||
* https://github.com/openlayers/ol3/issues/404.
|
||||
*
|
||||
* @define {number} The lowest supported resolution value.
|
||||
*/
|
||||
ol.renderer.canvas.MIN_RESOLUTION = 0.14929107086948487;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.renderer.canvas.Layer}
|
||||
* @param {ol.renderer.Map} mapRenderer Map renderer.
|
||||
* @param {ol.layer.Vector} layer Vector layer.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
|
||||
|
||||
goog.base(this, mapRenderer, layer);
|
||||
|
||||
/**
|
||||
* Final canvas made available to the map renderer.
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.canvas_ = /** @type {HTMLCanvasElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.CANVAS));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.context_ = /** @type {CanvasRenderingContext2D} */
|
||||
(this.canvas_.getContext('2d'));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!goog.vec.Mat4.Number}
|
||||
*/
|
||||
this.transform_ = goog.vec.Mat4.createNumber();
|
||||
|
||||
/**
|
||||
* Interim canvas for drawing newly visible features.
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.sketchCanvas_ = /** @type {HTMLCanvasElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.CANVAS));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!goog.vec.Mat4.Number}
|
||||
*/
|
||||
this.sketchTransform_ = goog.vec.Mat4.createNumber();
|
||||
|
||||
/**
|
||||
* Tile cache entries are arrays. The first item in each array is the tile
|
||||
* itself, the second are the symbol sizes, and the third is the maximum
|
||||
* symbol size.
|
||||
*
|
||||
* @private
|
||||
* @type {ol.TileCache}
|
||||
*/
|
||||
this.tileCache_ = new ol.TileCache(
|
||||
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE);
|
||||
goog.events.listen(layer, [
|
||||
ol.layer.VectorEventType.ADD,
|
||||
ol.layer.VectorEventType.CHANGE,
|
||||
ol.layer.VectorEventType.REMOVE,
|
||||
ol.layer.VectorEventType.INTENTCHANGE
|
||||
],
|
||||
this.handleLayerChange_, false, this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.tileArchetype_ = null;
|
||||
|
||||
/**
|
||||
* The maximum symbol size ever rendered for this layer (in pixels).
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxSymbolPixelDim_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedResolution_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Extent}
|
||||
*/
|
||||
this.renderedExtent_ = null;
|
||||
|
||||
/**
|
||||
* Flag to be set internally when we know something has changed that suggests
|
||||
* we need to re-render.
|
||||
* TODO: discuss setting this for all layers when something changes before
|
||||
* calling map.render().
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.dirty_ = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.pendingCachePrune_ = false;
|
||||
|
||||
/**
|
||||
* Grid used for internal generation of canvas tiles. This is created
|
||||
* lazily so we have access to the view projection.
|
||||
*
|
||||
* @private
|
||||
* @type {ol.tilegrid.TileGrid}
|
||||
*/
|
||||
this.tileGrid_ = null;
|
||||
|
||||
/**
|
||||
* Tile range before the current animation or interaction. This is updated
|
||||
* whenever the view is idle.
|
||||
*
|
||||
* @private
|
||||
* @type {ol.TileRange}
|
||||
*/
|
||||
this.tileRange_ = new ol.TileRange(NaN, NaN, NaN, NaN);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function()}
|
||||
*/
|
||||
this.requestMapRenderFrame_ = goog.bind(function() {
|
||||
this.dirty_ = true;
|
||||
mapRenderer.getMap().requestRenderFrame();
|
||||
}, this);
|
||||
|
||||
};
|
||||
goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
|
||||
|
||||
|
||||
/**
|
||||
* Get rid cached tiles. If the optional extent is provided, only tiles that
|
||||
* intersect that extent will be removed.
|
||||
* @param {Array.<ol.Extent>} extents extent Expire tiles within the provided
|
||||
* extents. If the array is empty, all tiles will be expired.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(extents) {
|
||||
// buffer by max symbolizer size at rendered resolution
|
||||
var resolution = this.renderedResolution_;
|
||||
goog.asserts.assertNumber(resolution);
|
||||
var tileCache = this.tileCache_;
|
||||
var length = extents.length;
|
||||
var extent;
|
||||
if (length > 0) {
|
||||
for (var i = 0; i < length; ++i) {
|
||||
extent = ol.extent.clone(extents[i]);
|
||||
ol.extent.buffer(extent, this.maxSymbolPixelDim_ * resolution / 2);
|
||||
tileCache.pruneTileRange(
|
||||
this.tileGrid_.getTileRangeForExtentAndZ(extent, 0));
|
||||
}
|
||||
} else {
|
||||
tileCache.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getImage = function() {
|
||||
return this.canvas_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.layer.Vector} Vector layer.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getVectorLayer = function() {
|
||||
return /** @type {ol.layer.Vector} */ (this.getLayer());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getTransform = function() {
|
||||
return this.transform_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
|
||||
* @param {function(string, ol.layer.Layer)} success Callback for
|
||||
* successful queries. The passed arguments are the resulting feature
|
||||
* information and the layer.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
|
||||
function(pixel, success) {
|
||||
var callback = function(features, layer) {
|
||||
success(layer.getTransformFeatureInfo()(features), layer);
|
||||
};
|
||||
this.getFeaturesForPixel(pixel, callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
|
||||
* @param {function(Array.<ol.Feature>, ol.layer.Layer)} success Callback for
|
||||
* successful queries. The passed arguments are the resulting features
|
||||
* and the layer.
|
||||
* @param {function()=} opt_error Callback for unsuccessful queries.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
function(pixel, success, opt_error) {
|
||||
// TODO What do we want to pass to the error callback?
|
||||
var map = this.getMap();
|
||||
var result = [];
|
||||
|
||||
var layer = this.getLayer();
|
||||
var location = map.getCoordinateFromPixel(pixel);
|
||||
var tileCoord = this.tileGrid_.getTileCoordForCoordAndZ(location, 0);
|
||||
var key = tileCoord.toString();
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
var cachedTile = this.tileCache_.get(key);
|
||||
var symbolSizes = cachedTile[1];
|
||||
var maxSymbolSize = cachedTile[2];
|
||||
var symbolOffsets = cachedTile[3];
|
||||
var halfMaxWidth = maxSymbolSize[0] / 2;
|
||||
var halfMaxHeight = maxSymbolSize[1] / 2;
|
||||
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
|
||||
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
|
||||
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
|
||||
var candidates = layer.getFeaturesObjectForExtent(locationBbox,
|
||||
map.getView().getView2D().getProjection());
|
||||
if (goog.isNull(candidates)) {
|
||||
// data is not loaded
|
||||
if (goog.isDef(opt_error)) {
|
||||
goog.global.setTimeout(function() { opt_error(); }, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var candidate, geom, type, symbolBounds, symbolSize, symbolOffset,
|
||||
halfWidth, halfHeight, uid, coordinates, j;
|
||||
for (var id in candidates) {
|
||||
candidate = candidates[id];
|
||||
if (candidate.getRenderIntent() ==
|
||||
ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
geom = candidate.getGeometry();
|
||||
type = geom.getType();
|
||||
if (type === ol.geom.GeometryType.POINT ||
|
||||
type === ol.geom.GeometryType.MULTIPOINT) {
|
||||
// For points, check if the pixel coordinate is inside the candidate's
|
||||
// symbol
|
||||
uid = goog.getUid(candidate);
|
||||
symbolSize = symbolSizes[uid];
|
||||
symbolOffset = symbolOffsets[uid];
|
||||
halfWidth = symbolSize[0] / 2;
|
||||
halfHeight = symbolSize[1] / 2;
|
||||
symbolBounds = ol.extent.boundingExtent([
|
||||
[location[0] - halfWidth - symbolOffset[0],
|
||||
location[1] - halfHeight + symbolOffset[1]],
|
||||
[location[0] + halfWidth - symbolOffset[0],
|
||||
location[1] + halfHeight + symbolOffset[1]]
|
||||
]);
|
||||
coordinates = geom.getCoordinates();
|
||||
if (!goog.isArray(coordinates[0])) {
|
||||
coordinates = [coordinates];
|
||||
}
|
||||
for (j = coordinates.length - 1; j >= 0; --j) {
|
||||
if (ol.extent.containsCoordinate(symbolBounds, coordinates[j])) {
|
||||
result.push(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (goog.isFunction(geom.containsCoordinate)) {
|
||||
// For polygons, check if the pixel location is inside the polygon
|
||||
if (geom.containsCoordinate(location)) {
|
||||
result.push(candidate);
|
||||
}
|
||||
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
|
||||
// For lines, check if the distance to the pixel location is
|
||||
// within the rendered line width
|
||||
if (2 * geom.distanceFromCoordinate(location) <=
|
||||
symbolSizes[goog.getUid(candidate)][0]) {
|
||||
result.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
goog.global.setTimeout(function() { success(result, layer); }, 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.VectorEvent} event Vector layer event.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.handleLayerChange_ = function(event) {
|
||||
if (goog.isDef(this.renderedResolution_)) {
|
||||
this.expireTiles_(event.extents);
|
||||
}
|
||||
this.requestMapRenderFrame_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
|
||||
function(frameState, layerState) {
|
||||
|
||||
// TODO: consider bailing out here if rendered center and resolution
|
||||
// have not changed. Requires that other change listeners set a dirty flag.
|
||||
|
||||
var view2DState = frameState.view2DState,
|
||||
resolution = view2DState.resolution,
|
||||
projection = view2DState.projection,
|
||||
extent = frameState.extent,
|
||||
layer = this.getVectorLayer(),
|
||||
tileGrid = this.tileGrid_,
|
||||
tileSize = [512, 512],
|
||||
idle = !frameState.viewHints[ol.ViewHint.ANIMATING] &&
|
||||
!frameState.viewHints[ol.ViewHint.INTERACTING];
|
||||
|
||||
// lazy tile grid creation
|
||||
if (idle) {
|
||||
// avoid rendering issues for very high zoom levels
|
||||
var minResolution = ol.renderer.canvas.MIN_RESOLUTION;
|
||||
var metersPerUnit = projection.getMetersPerUnit();
|
||||
if (metersPerUnit) {
|
||||
minResolution = minResolution / metersPerUnit;
|
||||
}
|
||||
var gridResolution = Math.max(resolution, minResolution);
|
||||
if (gridResolution !== this.renderedResolution_) {
|
||||
tileGrid = new ol.tilegrid.TileGrid({
|
||||
origin: [0, 0],
|
||||
projection: projection,
|
||||
resolutions: [gridResolution],
|
||||
tileSize: tileSize
|
||||
});
|
||||
this.tileCache_.clear();
|
||||
this.tileGrid_ = tileGrid;
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isNull(tileGrid)) {
|
||||
// We should only get here when the first call to prepareFrame happens
|
||||
// during an animation. Try again in the next prepareFrame call.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// set up transform for the layer canvas to be drawn to the map canvas
|
||||
var tileResolution = tileGrid.getResolution(0);
|
||||
if (idle) {
|
||||
tileGrid.getTileRangeForExtentAndResolution(
|
||||
extent, tileResolution, this.tileRange_);
|
||||
}
|
||||
var transform = this.transform_,
|
||||
tileRange = this.tileRange_,
|
||||
tileRangeExtent = tileGrid.getTileRangeExtent(0, tileRange),
|
||||
sketchOrigin = ol.extent.getTopLeft(tileRangeExtent);
|
||||
|
||||
goog.vec.Mat4.makeIdentity(transform);
|
||||
goog.vec.Mat4.translate(transform,
|
||||
frameState.size[0] / 2,
|
||||
frameState.size[1] / 2,
|
||||
0);
|
||||
goog.vec.Mat4.scale(transform,
|
||||
tileResolution / resolution, tileResolution / resolution, 1);
|
||||
goog.vec.Mat4.rotateZ(transform, view2DState.rotation);
|
||||
goog.vec.Mat4.translate(transform,
|
||||
(sketchOrigin[0] - view2DState.center[0]) / tileResolution,
|
||||
(view2DState.center[1] - sketchOrigin[1]) / tileResolution,
|
||||
0);
|
||||
|
||||
/**
|
||||
* Fastest path out of here. This method is called many many times while
|
||||
* there is nothing to do (e.g. while waiting for tiles from every other
|
||||
* layer to load.) Do not put anything above here that is more expensive than
|
||||
* necessary. And look for ways to get here faster.
|
||||
*/
|
||||
if (!this.dirty_ && this.renderedResolution_ === tileResolution &&
|
||||
ol.extent.equals(this.renderedExtent_, tileRangeExtent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (goog.isNull(this.tileArchetype_)) {
|
||||
this.tileArchetype_ = /** @type {HTMLCanvasElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.CANVAS));
|
||||
this.tileArchetype_.width = tileSize[0];
|
||||
this.tileArchetype_.height = tileSize[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the sketch canvas. This covers the currently visible tile range
|
||||
* and will have rendered all newly visible features.
|
||||
*/
|
||||
var sketchCanvas = this.sketchCanvas_;
|
||||
var sketchWidth = tileSize[0] * tileRange.getWidth();
|
||||
var sketchHeight = tileSize[1] * tileRange.getHeight();
|
||||
|
||||
// transform for map coords to sketch canvas pixel coords
|
||||
var sketchTransform = this.sketchTransform_;
|
||||
var halfWidth = sketchWidth / 2;
|
||||
var halfHeight = sketchHeight / 2;
|
||||
goog.vec.Mat4.makeIdentity(sketchTransform);
|
||||
goog.vec.Mat4.translate(sketchTransform,
|
||||
halfWidth,
|
||||
halfHeight,
|
||||
0);
|
||||
goog.vec.Mat4.scale(sketchTransform,
|
||||
1 / tileResolution,
|
||||
-1 / tileResolution,
|
||||
1);
|
||||
goog.vec.Mat4.translate(sketchTransform,
|
||||
-(sketchOrigin[0] + halfWidth * tileResolution),
|
||||
-(sketchOrigin[1] - halfHeight * tileResolution),
|
||||
0);
|
||||
|
||||
// clear/resize sketch canvas
|
||||
sketchCanvas.width = sketchWidth;
|
||||
sketchCanvas.height = sketchHeight;
|
||||
|
||||
var sketchContext = /** @type {CanvasRenderingContext2D} */
|
||||
(sketchCanvas.getContext('2d'));
|
||||
var sketchCanvasRenderer = new ol.renderer.canvas.Vector(
|
||||
sketchContext, sketchTransform, this.requestMapRenderFrame_);
|
||||
|
||||
// clear/resize final canvas
|
||||
var finalCanvas = this.canvas_;
|
||||
finalCanvas.width = sketchWidth;
|
||||
finalCanvas.height = sketchHeight;
|
||||
var finalContext = this.context_;
|
||||
|
||||
var featuresToRender = {};
|
||||
var tilesToRender = {};
|
||||
var tilesOnSketchCanvas = {};
|
||||
// TODO make gutter configurable?
|
||||
var tileGutter = 15 * tileResolution;
|
||||
var tile, tileCoord, key, x, y, i, type;
|
||||
var deferred = false;
|
||||
var dirty = false;
|
||||
var tileExtent, groups, group, j, numGroups, featuresObject, tileHasFeatures;
|
||||
fetchTileData:
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
tileCoord = new ol.TileCoord(0, x, y);
|
||||
key = tileCoord.toString();
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
tilesToRender[key] = tileCoord;
|
||||
} else if (idle) {
|
||||
tileExtent = tileGrid.getTileCoordExtent(tileCoord);
|
||||
tileExtent[0] -= tileGutter;
|
||||
tileExtent[2] += tileGutter;
|
||||
tileExtent[1] -= tileGutter;
|
||||
tileExtent[3] += tileGutter;
|
||||
tileHasFeatures = false;
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
|
||||
projection, this.requestMapRenderFrame_);
|
||||
if (goog.isNull(featuresObject)) {
|
||||
deferred = true;
|
||||
break fetchTileData;
|
||||
}
|
||||
tileHasFeatures = tileHasFeatures ||
|
||||
!goog.object.isEmpty(featuresObject);
|
||||
goog.object.extend(featuresToRender, featuresObject);
|
||||
if (tileHasFeatures) {
|
||||
tilesOnSketchCanvas[key] = tileCoord;
|
||||
}
|
||||
} else {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dirty_ = dirty;
|
||||
|
||||
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender,
|
||||
tileResolution);
|
||||
numGroups = groups.length;
|
||||
for (j = 0; j < numGroups; ++j) {
|
||||
group = groups[j];
|
||||
deferred = sketchCanvasRenderer.renderFeatures(group[0], group[1],
|
||||
group[2]);
|
||||
if (deferred) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!deferred) {
|
||||
goog.object.extend(tilesToRender, tilesOnSketchCanvas);
|
||||
}
|
||||
|
||||
var symbolSizes = sketchCanvasRenderer.getSymbolSizes(),
|
||||
maxSymbolSize = sketchCanvasRenderer.getMaxSymbolSize(),
|
||||
symbolOffsets = sketchCanvasRenderer.getSymbolOffsets();
|
||||
|
||||
// keep track of maximum pixel size for symbols rendered on this layer
|
||||
this.maxSymbolPixelDim_ = Math.max(maxSymbolSize[0] / tileResolution,
|
||||
maxSymbolSize[1] / tileResolution);
|
||||
|
||||
for (key in tilesToRender) {
|
||||
tileCoord = tilesToRender[key];
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
tile = /** @type {HTMLCanvasElement} */ (this.tileCache_.get(key)[0]);
|
||||
} else {
|
||||
tile = /** @type {HTMLCanvasElement} */
|
||||
(this.tileArchetype_.cloneNode(false));
|
||||
tile.getContext('2d').drawImage(sketchCanvas,
|
||||
(tileRange.minX - tileCoord.x) * tileSize[0],
|
||||
(tileCoord.y - tileRange.maxY) * tileSize[1]);
|
||||
// TODO: Create an ol.VectorTile subclass of ol.Tile
|
||||
this.tileCache_.set(key,
|
||||
[tile, symbolSizes, maxSymbolSize, symbolOffsets]);
|
||||
}
|
||||
finalContext.drawImage(tile,
|
||||
tileSize[0] * (tileCoord.x - tileRange.minX),
|
||||
tileSize[1] * (tileRange.maxY - tileCoord.y));
|
||||
}
|
||||
|
||||
this.renderedResolution_ = tileResolution;
|
||||
this.renderedExtent_ = tileRangeExtent;
|
||||
if (!this.pendingCachePrune_) {
|
||||
this.pendingCachePrune_ = true;
|
||||
frameState.postRenderFunctions.push(goog.bind(this.pruneTileCache_, this));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get rid of tiles that exceed the cache capacity.
|
||||
* TODO: add a method to the cache to handle this
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.pruneTileCache_ = function() {
|
||||
while (this.tileCache_.canExpireCache()) {
|
||||
this.tileCache_.pop();
|
||||
}
|
||||
this.pendingCachePrune_ = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE = 128;
|
||||
@@ -1,646 +0,0 @@
|
||||
goog.provide('ol.renderer.canvas.Vector');
|
||||
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.style.IconLiteral');
|
||||
goog.require('ol.style.LineLiteral');
|
||||
goog.require('ol.style.Literal');
|
||||
goog.require('ol.style.PointLiteral');
|
||||
goog.require('ol.style.PolygonLiteral');
|
||||
goog.require('ol.style.ShapeLiteral');
|
||||
goog.require('ol.style.ShapeType');
|
||||
goog.require('ol.style.TextLiteral');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {goog.vec.Mat4.Number} transform Transform.
|
||||
* @param {function()=} opt_iconLoadedCallback Callback for deferred rendering
|
||||
* when images need to be loaded before rendering.
|
||||
*/
|
||||
ol.renderer.canvas.Vector =
|
||||
function(context, transform, opt_iconLoadedCallback) {
|
||||
|
||||
/**
|
||||
* @type {goog.vec.Mat4.Number}
|
||||
* @private
|
||||
*/
|
||||
this.transform_ = transform;
|
||||
|
||||
var vec = [1, 0, 0];
|
||||
goog.vec.Mat4.multVec3NoTranslate(transform, vec, vec);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.inverseScale_ = 1 / Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
|
||||
|
||||
/**
|
||||
* @type {CanvasRenderingContext2D}
|
||||
* @private
|
||||
*/
|
||||
this.context_ = context;
|
||||
|
||||
/**
|
||||
* @type {function()|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.iconLoadedCallback_ = opt_iconLoadedCallback;
|
||||
|
||||
/**
|
||||
* @type {Object.<number, Array.<number>>}
|
||||
* @private
|
||||
*/
|
||||
this.symbolSizes_ = {};
|
||||
|
||||
/**
|
||||
* @type {Object.<number, Array.<number>>}
|
||||
* @private
|
||||
*/
|
||||
this.symbolOffsets_ = {};
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.maxSymbolSize_ = [0, 0];
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object.<number, Array.<number>>} Symbolizer sizes.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.getSymbolSizes = function() {
|
||||
return this.symbolSizes_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object.<number, Array.<number>>} Symbolizer offsets.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.getSymbolOffsets = function() {
|
||||
return this.symbolOffsets_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Maximum symbolizer size.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.getMaxSymbolSize = function() {
|
||||
return this.maxSymbolSize_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of features.
|
||||
* @param {ol.style.Literal} symbolizer Symbolizer.
|
||||
* @param {Array} data Additional data.
|
||||
* @return {boolean} true if deferred, false if rendered.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.renderFeatures =
|
||||
function(features, symbolizer, data) {
|
||||
var deferred = false;
|
||||
if (symbolizer instanceof ol.style.PointLiteral) {
|
||||
deferred = this.renderPointFeatures_(features, symbolizer);
|
||||
} else if (symbolizer instanceof ol.style.LineLiteral) {
|
||||
this.renderLineStringFeatures_(features, symbolizer);
|
||||
} else if (symbolizer instanceof ol.style.PolygonLiteral) {
|
||||
this.renderPolygonFeatures_(features, symbolizer);
|
||||
} else if (symbolizer instanceof ol.style.TextLiteral) {
|
||||
this.renderText_(features, symbolizer, data);
|
||||
}
|
||||
return deferred;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of line features.
|
||||
* @param {ol.style.LineLiteral} symbolizer Line symbolizer.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.renderLineStringFeatures_ =
|
||||
function(features, symbolizer) {
|
||||
|
||||
var context = this.context_,
|
||||
i, ii, feature, id, currentSize, geometry, components, j, jj,
|
||||
coordinates, coordinate, k, kk, strokeSize;
|
||||
|
||||
var vec = [NaN, NaN, 0];
|
||||
var pixel = [NaN, NaN];
|
||||
var lastPixel = [NaN, NaN];
|
||||
|
||||
context.globalAlpha = symbolizer.opacity;
|
||||
context.strokeStyle = symbolizer.color;
|
||||
context.lineWidth = symbolizer.width;
|
||||
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
|
||||
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
|
||||
strokeSize = context.lineWidth * this.inverseScale_;
|
||||
context.beginPath();
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
id = goog.getUid(feature);
|
||||
currentSize = goog.isDef(this.symbolSizes_[id]) ?
|
||||
this.symbolSizes_[id] : [0];
|
||||
currentSize[0] = Math.max(currentSize[0], strokeSize);
|
||||
this.symbolSizes_[id] = currentSize;
|
||||
this.maxSymbolSize_ = [Math.max(currentSize[0], this.maxSymbolSize_[0]),
|
||||
Math.max(currentSize[0], this.maxSymbolSize_[1])];
|
||||
geometry = feature.getGeometry();
|
||||
if (geometry instanceof ol.geom.LineString) {
|
||||
components = [geometry];
|
||||
} else {
|
||||
goog.asserts.assert(geometry instanceof ol.geom.MultiLineString,
|
||||
'Expected MultiLineString');
|
||||
components = geometry.getComponents();
|
||||
}
|
||||
for (j = 0, jj = components.length; j < jj; ++j) {
|
||||
coordinates = components[j].getCoordinates();
|
||||
for (k = 0, kk = coordinates.length; k < kk; ++k) {
|
||||
coordinate = coordinates[k];
|
||||
vec[0] = coordinate[0];
|
||||
vec[1] = coordinate[1];
|
||||
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
||||
if (k === 0) {
|
||||
lastPixel[0] = NaN;
|
||||
lastPixel[1] = NaN;
|
||||
context.moveTo(vec[0], vec[1]);
|
||||
} else {
|
||||
pixel[0] = Math.round(vec[0]);
|
||||
pixel[1] = Math.round(vec[1]);
|
||||
if (pixel[0] !== lastPixel[0] || pixel[1] !== lastPixel[1]) {
|
||||
context.lineTo(vec[0], vec[1]);
|
||||
lastPixel[0] = pixel[0];
|
||||
lastPixel[1] = pixel[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.stroke();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of point features.
|
||||
* @param {ol.style.PointLiteral} symbolizer Point symbolizer.
|
||||
* @return {boolean} true if deferred, false if rendered.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.renderPointFeatures_ =
|
||||
function(features, symbolizer) {
|
||||
|
||||
var context = this.context_,
|
||||
content, alpha, i, ii, feature, id, size, geometry, components, j, jj,
|
||||
point, vec;
|
||||
|
||||
var xOffset = 0;
|
||||
var yOffset = 0;
|
||||
if (symbolizer instanceof ol.style.ShapeLiteral) {
|
||||
content = ol.renderer.canvas.Vector.renderShape(symbolizer);
|
||||
alpha = 1;
|
||||
} else if (symbolizer instanceof ol.style.IconLiteral) {
|
||||
content = ol.renderer.canvas.Vector.renderIcon(
|
||||
symbolizer, this.iconLoadedCallback_);
|
||||
alpha = symbolizer.opacity;
|
||||
xOffset = symbolizer.xOffset;
|
||||
yOffset = symbolizer.yOffset;
|
||||
} else {
|
||||
throw new Error('Unsupported symbolizer: ' + symbolizer);
|
||||
}
|
||||
|
||||
if (goog.isNull(content)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var midWidth = Math.floor(content.width / 2);
|
||||
var midHeight = Math.floor(content.height / 2);
|
||||
var contentWidth = content.width * this.inverseScale_;
|
||||
var contentHeight = content.height * this.inverseScale_;
|
||||
var contentXOffset = xOffset * this.inverseScale_;
|
||||
var contentYOffset = yOffset * this.inverseScale_;
|
||||
context.save();
|
||||
context.setTransform(1, 0, 0, 1, -midWidth, -midHeight);
|
||||
context.globalAlpha = alpha;
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
id = goog.getUid(feature);
|
||||
size = this.symbolSizes_[id];
|
||||
this.symbolSizes_[id] = goog.isDef(size) ?
|
||||
[Math.max(size[0], contentWidth), Math.max(size[1], contentHeight)] :
|
||||
[contentWidth, contentHeight];
|
||||
this.symbolOffsets_[id] =
|
||||
[xOffset * this.inverseScale_, yOffset * this.inverseScale_];
|
||||
this.maxSymbolSize_ =
|
||||
[Math.max(this.maxSymbolSize_[0],
|
||||
this.symbolSizes_[id][0] + 2 * Math.abs(contentXOffset)),
|
||||
Math.max(this.maxSymbolSize_[1],
|
||||
this.symbolSizes_[id][1] + 2 * Math.abs(contentYOffset))];
|
||||
geometry = feature.getGeometry();
|
||||
if (geometry instanceof ol.geom.Point) {
|
||||
components = [geometry];
|
||||
} else {
|
||||
goog.asserts.assert(geometry instanceof ol.geom.MultiPoint,
|
||||
'Expected MultiPoint');
|
||||
components = geometry.getComponents();
|
||||
}
|
||||
for (j = 0, jj = components.length; j < jj; ++j) {
|
||||
point = components[j];
|
||||
goog.asserts.assertInstanceof(point, ol.geom.Point);
|
||||
vec = [point.get(0), point.get(1), 0];
|
||||
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
||||
context.drawImage(content, Math.round(vec[0] + xOffset),
|
||||
Math.round(vec[1] + yOffset),
|
||||
content.width, content.height);
|
||||
}
|
||||
}
|
||||
context.restore();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of features.
|
||||
* @param {ol.style.TextLiteral} text Text symbolizer.
|
||||
* @param {Array} texts Label text for each feature.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.renderText_ =
|
||||
function(features, text, texts) {
|
||||
var context = this.context_,
|
||||
feature, vecs, vec;
|
||||
|
||||
if (context.fillStyle !== text.color) {
|
||||
context.fillStyle = text.color;
|
||||
}
|
||||
|
||||
// font shorthand values must be given in the correct order
|
||||
// see http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
|
||||
context.font = text.fontWeight + ' ' +
|
||||
text.fontSize + 'px ' +
|
||||
text.fontFamily;
|
||||
|
||||
context.globalAlpha = text.opacity;
|
||||
|
||||
// TODO: make alignments configurable
|
||||
context.textAlign = 'center';
|
||||
context.textBaseline = 'middle';
|
||||
|
||||
var stroke = false;
|
||||
if (goog.isDef(text.strokeColor)) {
|
||||
stroke = true;
|
||||
goog.asserts.assertString(text.strokeColor);
|
||||
context.strokeStyle = text.strokeColor;
|
||||
goog.asserts.assertNumber(text.strokeWidth);
|
||||
context.lineWidth = text.strokeWidth;
|
||||
}
|
||||
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
vecs = ol.renderer.canvas.Vector.getLabelVectors(
|
||||
feature.getGeometry());
|
||||
for (var j = 0, jj = vecs.length; j < jj; ++j) {
|
||||
vec = vecs[j];
|
||||
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
||||
if (stroke) {
|
||||
if (text.strokeOpacity !== text.opacity) {
|
||||
goog.asserts.assertNumber(text.strokeOpacity);
|
||||
context.globalAlpha = text.strokeOpacity;
|
||||
}
|
||||
context.strokeText(texts[i], vec[0], vec[1]);
|
||||
if (text.strokeOpacity !== text.opacity) {
|
||||
context.globalAlpha = text.opacity;
|
||||
}
|
||||
}
|
||||
context.fillText(texts[i], vec[0], vec[1]);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of polygon features.
|
||||
* @param {ol.style.PolygonLiteral} symbolizer Polygon symbolizer.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.prototype.renderPolygonFeatures_ =
|
||||
function(features, symbolizer) {
|
||||
var context = this.context_,
|
||||
strokeColor = symbolizer.strokeColor,
|
||||
strokeWidth = symbolizer.strokeWidth,
|
||||
strokeOpacity = symbolizer.strokeOpacity,
|
||||
fillColor = symbolizer.fillColor,
|
||||
fillOpacity = symbolizer.fillOpacity,
|
||||
globalAlpha,
|
||||
i, ii, geometry, components, j, jj, poly,
|
||||
rings, numRings, coordinates, coordinate, k, kk, feature;
|
||||
|
||||
var vec = [NaN, NaN, 0];
|
||||
var pixel = [NaN, NaN];
|
||||
var lastPixel = [NaN, NaN];
|
||||
|
||||
if (strokeColor) {
|
||||
context.strokeStyle = strokeColor;
|
||||
if (strokeWidth) {
|
||||
context.lineWidth = strokeWidth;
|
||||
}
|
||||
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
|
||||
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
|
||||
}
|
||||
if (fillColor) {
|
||||
context.fillStyle = fillColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Four scenarios covered here:
|
||||
* 1) stroke only, no holes - only need to have a single path
|
||||
* 2) fill only, no holes - only need to have a single path
|
||||
* 3) fill and stroke, no holes
|
||||
* 4) holes - render polygon to sketch canvas first
|
||||
*/
|
||||
context.beginPath();
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
geometry = feature.getGeometry();
|
||||
if (geometry instanceof ol.geom.Polygon) {
|
||||
components = [geometry];
|
||||
} else {
|
||||
goog.asserts.assert(geometry instanceof ol.geom.MultiPolygon,
|
||||
'Expected MultiPolygon');
|
||||
components = geometry.getComponents();
|
||||
}
|
||||
for (j = 0, jj = components.length; j < jj; ++j) {
|
||||
poly = components[j];
|
||||
goog.asserts.assertInstanceof(poly, ol.geom.Polygon);
|
||||
rings = poly.getRings();
|
||||
numRings = rings.length;
|
||||
if (numRings > 0) {
|
||||
// TODO: scenario 4
|
||||
coordinates = rings[0].getCoordinates();
|
||||
for (k = 0, kk = coordinates.length; k < kk; ++k) {
|
||||
coordinate = coordinates[k];
|
||||
vec[0] = coordinate[0];
|
||||
vec[1] = coordinate[1];
|
||||
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
||||
if (k === 0) {
|
||||
lastPixel[0] = NaN;
|
||||
lastPixel[1] = NaN;
|
||||
context.moveTo(vec[0], vec[1]);
|
||||
} else {
|
||||
pixel[0] = Math.round(vec[0]);
|
||||
pixel[1] = Math.round(vec[1]);
|
||||
if (pixel[0] !== lastPixel[0] || pixel[1] !== lastPixel[1]) {
|
||||
context.lineTo(vec[0], vec[1]);
|
||||
lastPixel[0] = pixel[0];
|
||||
lastPixel[1] = pixel[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fillColor && strokeColor) {
|
||||
// scenario 3 - fill and stroke each time
|
||||
if (fillOpacity !== globalAlpha) {
|
||||
goog.asserts.assertNumber(fillOpacity);
|
||||
context.globalAlpha = fillOpacity;
|
||||
globalAlpha = fillOpacity;
|
||||
}
|
||||
context.fill();
|
||||
if (strokeOpacity !== globalAlpha) {
|
||||
goog.asserts.assertNumber(strokeOpacity);
|
||||
context.globalAlpha = strokeOpacity;
|
||||
globalAlpha = strokeOpacity;
|
||||
}
|
||||
context.stroke();
|
||||
if (i < ii - 1 || j < jj - 1) {
|
||||
context.beginPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(fillColor && strokeColor)) {
|
||||
if (fillColor) {
|
||||
// scenario 2 - fill all at once
|
||||
if (fillOpacity !== globalAlpha) {
|
||||
goog.asserts.assertNumber(fillOpacity);
|
||||
context.globalAlpha = fillOpacity;
|
||||
globalAlpha = fillOpacity;
|
||||
}
|
||||
context.fill();
|
||||
} else {
|
||||
// scenario 1 - stroke all at once
|
||||
if (strokeOpacity !== globalAlpha) {
|
||||
goog.asserts.assertNumber(strokeOpacity);
|
||||
context.globalAlpha = strokeOpacity;
|
||||
globalAlpha = strokeOpacity;
|
||||
}
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.style.ShapeLiteral} circle Shape symbolizer.
|
||||
* @return {!HTMLCanvasElement} Canvas element.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.renderCircle_ = function(circle) {
|
||||
var strokeWidth = circle.strokeWidth || 0,
|
||||
size = circle.size + (2 * strokeWidth) + 1,
|
||||
mid = size / 2,
|
||||
canvas = /** @type {HTMLCanvasElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.CANVAS)),
|
||||
context = /** @type {CanvasRenderingContext2D} */
|
||||
(canvas.getContext('2d')),
|
||||
fillColor = circle.fillColor,
|
||||
strokeColor = circle.strokeColor,
|
||||
twoPi = Math.PI * 2;
|
||||
|
||||
canvas.height = size;
|
||||
canvas.width = size;
|
||||
|
||||
if (fillColor) {
|
||||
context.fillStyle = fillColor;
|
||||
}
|
||||
if (strokeColor) {
|
||||
context.lineWidth = strokeWidth;
|
||||
context.strokeStyle = strokeColor;
|
||||
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
|
||||
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
|
||||
}
|
||||
|
||||
context.beginPath();
|
||||
context.arc(mid, mid, circle.size / 2, 0, twoPi, true);
|
||||
|
||||
if (fillColor) {
|
||||
goog.asserts.assertNumber(circle.fillOpacity);
|
||||
context.globalAlpha = circle.fillOpacity;
|
||||
context.fill();
|
||||
}
|
||||
if (strokeColor) {
|
||||
goog.asserts.assertNumber(circle.strokeOpacity);
|
||||
context.globalAlpha = circle.strokeOpacity;
|
||||
context.stroke();
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom.Geometry} geometry Geometry.
|
||||
* @return {Array.<goog.vec.Vec3.AnyType>} Renderable geometry vectors.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.getLabelVectors = function(geometry) {
|
||||
if (geometry instanceof ol.geom.AbstractCollection) {
|
||||
var components = geometry.getComponents();
|
||||
var numComponents = components.length;
|
||||
var result = [];
|
||||
for (var i = 0; i < numComponents; ++i) {
|
||||
result.push.apply(result,
|
||||
ol.renderer.canvas.Vector.getLabelVectors(components[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
var type = geometry.getType();
|
||||
if (type == ol.geom.GeometryType.POINT) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Point);
|
||||
return [[geometry.get(0), geometry.get(1), 0]];
|
||||
}
|
||||
if (type == ol.geom.GeometryType.POLYGON) {
|
||||
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon);
|
||||
var coordinates = geometry.getInteriorPoint();
|
||||
return [[coordinates[0], coordinates[1], 0]];
|
||||
}
|
||||
throw new Error('Label rendering not implemented for geometry type: ' +
|
||||
type);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.style.ShapeLiteral} shape Shape symbolizer.
|
||||
* @return {!HTMLCanvasElement} Canvas element.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.renderShape = function(shape) {
|
||||
var canvas;
|
||||
if (shape.type === ol.style.ShapeType.CIRCLE) {
|
||||
canvas = ol.renderer.canvas.Vector.renderCircle_(shape);
|
||||
} else {
|
||||
throw new Error('Unsupported shape type: ' + shape);
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.style.IconLiteral} icon Icon literal.
|
||||
* @param {function()=} opt_callback Callback which will be called when
|
||||
* the icon is loaded and rendering will work without deferring.
|
||||
* @return {HTMLImageElement} image element of null if deferred.
|
||||
*/
|
||||
ol.renderer.canvas.Vector.renderIcon = function(icon, opt_callback) {
|
||||
var url = icon.url;
|
||||
var image = ol.renderer.canvas.Vector.icons_[url];
|
||||
var deferred = false;
|
||||
if (!goog.isDef(image)) {
|
||||
deferred = true;
|
||||
image = /** @type {HTMLImageElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.IMG));
|
||||
goog.events.listenOnce(image, goog.events.EventType.ERROR,
|
||||
goog.bind(ol.renderer.canvas.Vector.handleIconError_, null,
|
||||
opt_callback),
|
||||
false, ol.renderer.canvas.Vector.renderIcon);
|
||||
goog.events.listenOnce(image, goog.events.EventType.LOAD,
|
||||
goog.bind(ol.renderer.canvas.Vector.handleIconLoad_, null,
|
||||
opt_callback),
|
||||
false, ol.renderer.canvas.Vector.renderIcon);
|
||||
image.setAttribute('src', url);
|
||||
} else if (!goog.isNull(image)) {
|
||||
var width = icon.width,
|
||||
height = icon.height;
|
||||
if (goog.isDef(width) && goog.isDef(height)) {
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
} else if (goog.isDef(width)) {
|
||||
image.height = width / image.width * image.height;
|
||||
image.width = width;
|
||||
} else if (goog.isDef(height)) {
|
||||
image.width = height / image.height * image.width;
|
||||
image.height = height;
|
||||
}
|
||||
}
|
||||
return deferred ? null : image;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, HTMLImageElement>}
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.icons_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {function()=} opt_callback Callback.
|
||||
* @param {Event=} opt_event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.handleIconError_ =
|
||||
function(opt_callback, opt_event) {
|
||||
if (goog.isDef(opt_event)) {
|
||||
var url = opt_event.target.getAttribute('src');
|
||||
ol.renderer.canvas.Vector.icons_[url] = null;
|
||||
ol.renderer.canvas.Vector.handleIconLoad_(opt_callback, opt_event);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {function()=} opt_callback Callback.
|
||||
* @param {Event=} opt_event Event.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.Vector.handleIconLoad_ =
|
||||
function(opt_callback, opt_event) {
|
||||
if (goog.isDef(opt_event)) {
|
||||
var url = opt_event.target.getAttribute('src');
|
||||
ol.renderer.canvas.Vector.icons_[url] =
|
||||
/** @type {HTMLImageElement} */ (opt_event.target);
|
||||
}
|
||||
if (goog.isDef(opt_callback)) {
|
||||
opt_callback();
|
||||
}
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
@exportClass ol.source.Vector ol.source.VectorOptions
|
||||
@@ -1,96 +0,0 @@
|
||||
goog.provide('ol.source.Vector');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.net.XhrIo');
|
||||
goog.require('ol.source.Source');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.source.VectorLoadState = {
|
||||
IDLE: 0,
|
||||
LOADING: 1,
|
||||
LOADED: 2,
|
||||
ERROR: 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.source.Source}
|
||||
* @param {ol.source.VectorOptions} options Vector source options.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.source.Vector = function(options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object|string}
|
||||
*/
|
||||
this.data_ = goog.isDef(options.data) ? options.data : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.source.VectorLoadState}
|
||||
*/
|
||||
this.loadState_ = ol.source.VectorLoadState.IDLE;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.parser.Parser}
|
||||
*/
|
||||
this.parser_ = goog.isDef(options.parser) ? options.parser : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
goog.base(this, {
|
||||
attributions: options.attributions,
|
||||
extent: options.extent,
|
||||
logo: options.logo,
|
||||
projection: options.projection
|
||||
});
|
||||
};
|
||||
goog.inherits(ol.source.Vector, ol.source.Source);
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Vector} layer Layer that parses the data.
|
||||
* @param {ol.Extent} extent Extent that needs to be fetched.
|
||||
* @param {ol.proj.Projection} projection Projection of the view.
|
||||
* @param {function()=} opt_callback Callback which is called when features are
|
||||
* parsed after loading.
|
||||
* @return {ol.source.VectorLoadState} The current load state.
|
||||
*/
|
||||
ol.source.Vector.prototype.prepareFeatures = function(layer, extent, projection,
|
||||
opt_callback) {
|
||||
// TODO: Implement strategies. BBOX aware strategies will need the extent.
|
||||
if (goog.isDef(this.url_) &&
|
||||
this.loadState_ == ol.source.VectorLoadState.IDLE) {
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADING;
|
||||
goog.net.XhrIo.send(this.url_, goog.bind(function(event) {
|
||||
var xhr = event.target;
|
||||
if (xhr.isSuccess()) {
|
||||
// TODO: Get source projection from data if supported by parser.
|
||||
layer.parseFeatures(xhr.getResponseText(), this.parser_, projection);
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADED;
|
||||
if (goog.isDef(opt_callback)) {
|
||||
opt_callback();
|
||||
}
|
||||
} else {
|
||||
// TODO: Error handling.
|
||||
this.loadState_ = ol.source.VectorLoadState.ERROR;
|
||||
}
|
||||
}, this));
|
||||
} else if (!goog.isNull(this.data_)) {
|
||||
layer.parseFeatures(this.data_, this.parser_, projection);
|
||||
this.data_ = null;
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADED;
|
||||
}
|
||||
return this.loadState_;
|
||||
};
|
||||
Reference in New Issue
Block a user