Merge pull request #1368 from twpayne/vector-api-kml

[vector-api] ol.format.KML
This commit is contained in:
Tom Payne
2013-12-19 09:07:43 -08:00
23 changed files with 17978 additions and 70 deletions

View File

@@ -260,6 +260,12 @@
* Possible values are `barometric`, `gps`, and `none`. Default is `none`.
*/
/**
* @typedef {Object} olx.format.KMLOptions
* @property {boolean|undefined} extractAttributes Extract attributes.
* @property {boolean|undefined} extractStyles Extract styles.
*/
/**
* @typedef {Object} olx.interaction.DoubleClickZoomOptions
* @property {number|undefined} duration Animation duration in milliseconds. Default is `250`.
@@ -268,6 +274,19 @@
* @todo stability experimental
*/
/**
* @typedef {Object} olx.interaction.DragAndDropOptions
* @property {boolean|undefined} fitView Fit view. Default is `true`.
* @property {Array.<function(new: ol.format.Format)>|undefined}
* formatConstructors Format constructors.
* @property {ol.source.Vector|undefined} source Source. If this is defined
* then features will be added to this source.
* @property {ol.layer.Vector|undefined} layer Layer. If this is defined then
* features will be added to this layer's source. If neither `source` nor
* `layer` are defined then the dropped features will be added as a new
* layer.
*/
/**
* @typedef {Object} olx.interaction.DragPanOptions
* @property {ol.Kinetic|undefined} kinetic Kinetic inertia to apply to the pan.
@@ -530,6 +549,19 @@
* @property {Object|undefined} params Additional parameters.
*/
/**
* @typedef {Object} olx.source.KMLOptions
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
* @property {Document|undefined} doc Document.
* @property {ol.Extent|undefined} extent Extent.
* @property {string|undefined} logo Logo.
* @property {Node|undefined| node Node.
* @property {ol.proj.ProjectionLike} projection Projection.
* @property {ol.proj.ProjectionLike} reprojectTo Re-project to.
* @property {string|undefined} text Text.
* @property {string|undefined} url URL.
*/
/**
* @typedef {Object} olx.source.MapQuestOptions
* @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional

View File

@@ -23,6 +23,12 @@ ol.format.Format = function() {
};
/**
* @return {Array.<string>} Extensions.
*/
ol.format.Format.prototype.getExtensions = goog.abstractMethod;
/**
* @return {ol.format.FormatType} Format.
*/

View File

@@ -41,6 +41,13 @@ ol.format.GeoJSON = function(opt_options) {
goog.inherits(ol.format.GeoJSON, ol.format.JSON);
/**
* @const {Array.<string>}
* @private
*/
ol.format.GeoJSON.EXTENSIONS_ = ['.geojson'];
/**
* @param {GeoJSONObject} object Object.
* @private
@@ -278,6 +285,14 @@ ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
};
/**
* @inheritDoc
*/
ol.format.GeoJSON.prototype.getExtensions = function() {
return ol.format.GeoJSON.EXTENSIONS_;
};
/**
* @inheritDoc
*/

View File

@@ -0,0 +1 @@
@exportSymbol ol.format.KML

1409
src/ol/format/kmlformat.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
goog.provide('ol.format.XML');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.dom.xml');
goog.require('ol.format.Format');
goog.require('ol.format.FormatType');
@@ -17,57 +19,6 @@ ol.format.XML = function() {
goog.inherits(ol.format.XML, ol.format.Format);
/**
* @param {Document|Node|Object|string} source Source.
* @private
* @return {Document} Document.
*/
ol.format.XML.prototype.getDocument_ = function(source) {
if (source instanceof Document) {
return source;
} else if (goog.isString(source)) {
return goog.dom.xml.loadXml(source);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document|Node|Object|string} source Source.
* @private
* @return {Document|Node} Document.
*/
ol.format.XML.prototype.getDocumentOrNode_ = function(source) {
if (source instanceof Document) {
return source;
} else if (source instanceof Node) {
return source;
} else if (goog.isString(source)) {
return goog.dom.xml.loadXml(source);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document|Node|Object|string} source Source.
* @private
* @return {Node} Node.
*/
ol.format.XML.prototype.getNode_ = function(source) {
if (source instanceof Node) {
return source;
} else {
goog.asserts.fail();
return null;
}
};
/**
* @inheritDoc
*/
@@ -80,7 +31,31 @@ ol.format.XML.prototype.getType = function() {
* @inheritDoc
*/
ol.format.XML.prototype.readFeature = function(source) {
return this.readFeatureFromNode(this.getNode_(source));
if (source instanceof Document) {
return this.readFeatureFromDocument(source);
} else if (source instanceof Node) {
return this.readFeatureFromNode(source);
} else if (goog.isString(source)) {
var doc = goog.dom.xml.loadXml(source);
return this.readFeatureFromDocument(doc);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @return {ol.Feature} Feature.
*/
ol.format.XML.prototype.readFeatureFromDocument = function(doc) {
var features = this.readFeaturesFromDocument(doc);
if (features.length > 0) {
return features[0];
} else {
return null;
}
};
@@ -95,11 +70,13 @@ ol.format.XML.prototype.readFeatureFromNode = goog.abstractMethod;
* @inheritDoc
*/
ol.format.XML.prototype.readFeatures = function(source) {
var documentOrNode = this.getDocumentOrNode_(source);
if (documentOrNode instanceof Document) {
return this.readFeaturesFromDocument(documentOrNode);
} else if (documentOrNode instanceof Node) {
return this.readFeaturesFromNode(documentOrNode);
if (source instanceof Document) {
return this.readFeaturesFromDocument(source);
} else if (source instanceof Node) {
return this.readFeaturesFromNode(source);
} else if (goog.isString(source)) {
var doc = goog.dom.xml.loadXml(source);
return this.readFeaturesFromDocument(doc);
} else {
goog.asserts.fail();
return null;
@@ -113,8 +90,15 @@ ol.format.XML.prototype.readFeatures = function(source) {
* @return {Array.<ol.Feature>} Features.
*/
ol.format.XML.prototype.readFeaturesFromDocument = function(doc) {
goog.asserts.assert(doc.childNodes.length == 1);
return this.readFeaturesFromNode(doc.firstChild);
/** @type {Array.<ol.Feature>} */
var features = [];
var n;
for (n = doc.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
goog.array.extend(features, this.readFeaturesFromNode(n));
}
}
return features;
};
@@ -130,10 +114,28 @@ ol.format.XML.prototype.readFeaturesFromNode = goog.abstractMethod;
* @inheritDoc
*/
ol.format.XML.prototype.readGeometry = function(source) {
return this.readGeometryFromNode(this.getNode_(source));
if (source instanceof Document) {
return this.readGeometryFromDocument(source);
} else if (source instanceof Node) {
return this.readGeometryFromNode(source);
} else if (goog.isString(source)) {
var doc = goog.dom.xml.loadXml(source);
return this.readGeometryFromDocument(doc);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @protected
* @return {ol.geom.Geometry} Geometry.
*/
ol.format.XML.prototype.readGeometryFromDocument = goog.abstractMethod;
/**
* @param {Node} node Node.
* @protected
@@ -146,10 +148,28 @@ ol.format.XML.prototype.readGeometryFromNode = goog.abstractMethod;
* @inheritDoc
*/
ol.format.XML.prototype.readProjection = function(source) {
return this.readProjectionFromNode(this.getNode_(source));
if (source instanceof Document) {
return this.readProjectionFromDocument(source);
} else if (source instanceof Node) {
return this.readProjectionFromNode(source);
} else if (goog.isString(source)) {
var doc = goog.dom.xml.loadXml(source);
return this.readProjectionFromDocument(doc);
} else {
goog.asserts.fail();
return null;
}
};
/**
* @param {Document} doc Document.
* @protected
* @return {ol.proj.Projection} Projection.
*/
ol.format.XML.prototype.readProjectionFromDocument = goog.abstractMethod;
/**
* @param {Node} node Node.
* @protected

View File

@@ -0,0 +1 @@
@exportSymbol ol.interaction.DragAndDrop

View File

@@ -0,0 +1,202 @@
// FIXME should handle all geo-referenced data, not just vector data
goog.provide('ol.interaction.DragAndDrop');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.FileDropHandler');
goog.require('goog.events.FileDropHandler.EventType');
goog.require('goog.fs.FileReader');
goog.require('goog.functions');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.proj');
goog.require('ol.source.Vector');
/**
* @constructor
* @extends {ol.interaction.Interaction}
* @param {olx.interaction.DragAndDropOptions=} opt_options Options.
*/
ol.interaction.DragAndDrop = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this);
/**
* @private
* @type {boolean}
*/
this.fitView_ = goog.isDef(options.fitView) ? options.fitView : true;
/**
* @private
* @type {Array.<function(new: ol.format.Format)>}
*/
this.formatConstructors_ = goog.isDef(options.formatConstructors) ?
options.formatConstructors : [];
/**
* @private
* @type {ol.source.Vector}
*/
this.source_ = goog.isDef(options.source) ? options.source : null;
/**
* @private
* @type {ol.layer.Vector}
*/
this.layer_ = goog.isDef(options.layer) ? options.layer : null;
/**
* @private
* @type {goog.events.FileDropHandler}
*/
this.fileDropHandler_ = null;
/**
* @private
* @type {goog.events.Key|undefined}
*/
this.dropListenKey_ = undefined;
};
goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);
/**
* @inheritDoc
*/
ol.interaction.DragAndDrop.prototype.disposeInternal = function() {
if (goog.isDef(this.dropListenKey_)) {
goog.events.unlistenByKey(this.dropListenKey_);
}
goog.base(this, 'disposeInternal');
};
/**
* @param {goog.events.BrowserEvent} event Event.
* @private
*/
ol.interaction.DragAndDrop.prototype.handleDrop_ = function(event) {
var files = event.getBrowserEvent().dataTransfer.files;
var i, ii;
for (i = 0, ii = files.length; i < ii; ++i) {
var reader = goog.fs.FileReader.readAsText(files[i]);
reader.addCallback(this.handleResult_, this);
}
};
/**
* @param {string} result Result.
* @private
*/
ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) {
var map = this.getMap();
goog.asserts.assert(!goog.isNull(map));
var view = map.getView();
goog.asserts.assert(goog.isDef(view));
var view2D = view.getView2D();
var targetProjection;
if (!goog.isNull(this.source_)) {
targetProjection = this.source_.getProjection();
} else if (!goog.isNull(this.layer_)) {
targetProjection = this.layer_.getSource().getProjection();
} else {
targetProjection = view2D.getProjection();
}
var formatConstructors = this.formatConstructors_;
var features = [];
var i, ii;
for (i = 0, ii = formatConstructors.length; i < ii; ++i) {
var formatConstructor = formatConstructors[i];
var format = new formatConstructor();
var readFeatures = this.tryReadFeatures_(format, result);
if (!goog.isNull(readFeatures)) {
var featureProjection = format.readProjection(result);
var transform = ol.proj.getTransform(featureProjection, targetProjection);
var j, jj;
for (j = 0, jj = readFeatures.length; j < jj; ++j) {
var feature = readFeatures[j];
var geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
geometry.transform(transform);
}
features.push(feature);
}
}
}
if (features.length > 0) {
var source;
if (!goog.isNull(this.source_)) {
source = this.source_;
} else if (!goog.isNull(this.layer_)) {
source = this.layer_.getSource();
goog.asserts.assertInstanceof(source, ol.source.Vector);
} else {
source = new ol.source.Vector();
}
for (i = 0, ii = features.length; i < ii; ++i) {
source.addFeature(features[i]);
}
if (goog.isNull(this.layer_)) {
map.getLayers().push(new ol.layer.Vector({
source: source
}));
}
if (this.fitView_) {
view2D.fitExtent(source.getExtent(), map.getSize());
}
}
};
/**
* @inheritDoc
*/
ol.interaction.DragAndDrop.prototype.handleMapBrowserEvent =
goog.functions.TRUE;
/**
* @inheritDoc
*/
ol.interaction.DragAndDrop.prototype.setMap = function(map) {
if (goog.isDef(this.dropListenKey_)) {
goog.events.unlistenByKey(this.dropListenKey_);
this.dropListenKey_ = undefined;
}
if (!goog.isNull(this.fileDropHandler_)) {
goog.dispose(this.fileDropHandler_);
this.fileDropHandler_ = null;
}
goog.asserts.assert(!goog.isDef(this.dropListenKey_));
goog.base(this, 'setMap', map);
if (!goog.isNull(map)) {
this.fileDropHandler_ = new goog.events.FileDropHandler(map.getViewport());
this.dropListenKey_ = goog.events.listen(
this.fileDropHandler_, goog.events.FileDropHandler.EventType.DROP,
this.handleDrop_, false, this);
}
};
/**
* @param {ol.format.Format} format Format.
* @param {string} text Text.
* @private
* @return {Array.<ol.Feature>} Features.
*/
ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) {
try {
return format.readFeatures(text);
} catch (e) {
return null;
}
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.source.KML

View File

@@ -0,0 +1,31 @@
goog.provide('ol.source.KML');
goog.require('ol.format.KML');
goog.require('ol.source.VectorFile');
/**
* @constructor
* @extends {ol.source.VectorFile}
* @param {olx.source.KMLOptions=} opt_options Options.
*/
ol.source.KML = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
goog.base(this, {
attributions: options.attributions,
doc: options.doc,
extent: options.extent,
format: new ol.format.KML(),
logo: options.logo,
node: options.node,
projection: options.projection,
reprojectTo: options.reprojectTo,
text: options.text,
url: options.url
});
};
goog.inherits(ol.source.KML, ol.source.VectorFile);

202
src/ol/xml.js Normal file
View File

@@ -0,0 +1,202 @@
goog.provide('ol.xml');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.NodeType');
goog.require('goog.object');
/**
* @typedef {function(Node, Array.<*>)}
*/
ol.xml.Parser;
/**
* @param {Node} node Node.
* @param {boolean} normalizeWhitespace Normalize whitespace.
* @return {string} All text content.
*/
ol.xml.getAllTextContent = function(node, normalizeWhitespace) {
return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join('');
};
/**
* @param {Node} node Node.
* @param {boolean} normalizeWhitespace Normalize whitespace.
* @param {Array.<String|string>} accumulator Accumulator.
* @private
* @return {Array.<String|string>} Accumulator.
*/
ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) {
if (node.nodeType == goog.dom.NodeType.CDATA_SECTION ||
node.nodeType == goog.dom.NodeType.TEXT) {
if (normalizeWhitespace) {
// FIXME understand why goog.dom.getTextContent_ uses String here
accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
} else {
accumulator.push(node.nodeValue);
}
} else {
var n;
for (n = node.firstChild; !goog.isNull(n); n = n.nextSibling) {
ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator);
}
}
return accumulator;
};
/**
* @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)}
* valueReader Value reader.
* @param {T=} opt_obj Scope.
* @return {ol.xml.Parser} Parser.
* @template T
*/
ol.xml.makeArrayExtender = function(valueReader, opt_obj) {
return (
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
*/
function(node, objectStack) {
var value = valueReader.call(opt_obj, node, objectStack);
if (goog.isDef(value)) {
goog.asserts.assert(goog.isArray(value));
var array = /** @type {Array.<*>} */
(objectStack[objectStack.length - 1]);
goog.asserts.assert(goog.isArray(array));
goog.array.extend(array, value);
}
});
};
/**
* @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
* @param {T=} opt_obj Scope.
* @return {ol.xml.Parser} Parser.
* @template T
*/
ol.xml.makeArrayPusher = function(valueReader, opt_obj) {
return (
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
*/
function(node, objectStack) {
var value = valueReader.call(opt_obj, node, objectStack);
if (goog.isDef(value)) {
var array = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isArray(array));
array.push(value);
}
});
};
/**
* @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
* @param {T=} opt_obj Scope.
* @return {ol.xml.Parser} Parser.
* @template T
*/
ol.xml.makeReplacer = function(valueReader, opt_obj) {
return (
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
*/
function(node, objectStack) {
var value = valueReader.call(opt_obj, node, objectStack);
if (goog.isDef(value)) {
objectStack[objectStack.length - 1] = value;
}
});
};
/**
* @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
* @param {string=} opt_property Property.
* @param {T=} opt_obj Scope.
* @return {ol.xml.Parser} Parser.
* @template T
*/
ol.xml.makeObjectPropertySetter = function(valueReader, opt_property, opt_obj) {
goog.asserts.assert(goog.isDef(valueReader));
return (
/**
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
*/
function(node, objectStack) {
var value = valueReader.call(opt_obj, node, objectStack);
if (goog.isDef(value)) {
var object = /** @type {Object} */
(objectStack[objectStack.length - 1]);
var property = goog.isDef(opt_property) ?
opt_property : node.localName;
goog.asserts.assert(goog.isObject(object));
goog.object.set(object, property, value);
}
});
};
/**
* @param {Array.<string>} namespaceURIs Namespace URIs.
* @param {Object.<string, ol.xml.Parser>} parsers Parsers.
* @return {Object.<string, Object.<string, ol.xml.Parser>>} Parsers NS.
*/
ol.xml.makeParsersNS = function(namespaceURIs, parsers) {
/** @type {Object.<string, Object.<string, ol.xml.Parser>>} */
var parsersNS = {};
var i, ii;
for (i = 0, ii = namespaceURIs.length; i < ii; ++i) {
parsersNS[namespaceURIs[i]] = parsers;
}
return parsersNS;
};
/**
* @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS
* Parsers by namespace.
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @param {*=} opt_obj Scope.
*/
ol.xml.parse = function(parsersNS, node, objectStack, opt_obj) {
var n;
for (n = node.firstChild; !goog.isNull(n); n = n.nextSibling) {
if (n.nodeType == goog.dom.NodeType.ELEMENT) {
var parsers = parsersNS[n.namespaceURI];
if (goog.isDef(parsers)) {
var parser = parsers[n.localName];
if (goog.isDef(parser)) {
parser.call(opt_obj, n, objectStack);
}
}
}
}
};
/**
* @param {T} object Object.
* @param {Object.<string, Object.<string, ol.xml.Parser>>} parsersNS
* Parsers by namespace.
* @param {Node} node Node.
* @param {Array.<*>} objectStack Object stack.
* @param {*=} opt_obj Scope.
* @return {T|undefined} Object.
* @template T
*/
ol.xml.pushAndParse = function(object, parsersNS, node, objectStack, opt_obj) {
objectStack.push(object);
ol.xml.parse(parsersNS, node, objectStack, opt_obj);
return objectStack.pop();
};