Add write support to KML format

This commit is contained in:
Éric Lemoine
2014-06-25 12:17:13 +02:00
parent 8dc9618adb
commit a4e95eb513
2 changed files with 1502 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
// FIXME http://earth.google.com/kml/1.0 namespace?
// FIXME why does node.getAttribute return an unknown type?
// FIXME text
// FIXME serialize arbitrary feature properties
goog.provide('ol.format.KML');
@@ -13,12 +14,15 @@ goog.require('goog.object');
goog.require('goog.string');
goog.require('ol.Feature');
goog.require('ol.array');
goog.require('ol.color');
goog.require('ol.feature');
goog.require('ol.format.XMLFeature');
goog.require('ol.format.XSD');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
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');
@@ -32,6 +36,7 @@ goog.require('ol.style.IconOrigin');
goog.require('ol.style.Image');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
goog.require('ol.xml');
@@ -1641,3 +1646,889 @@ ol.format.KML.prototype.readProjectionFromDocument = function(doc) {
ol.format.KML.prototype.readProjectionFromNode = function(node) {
return ol.proj.get('EPSG:4326');
};
/**
* @param {Node} node Node to append a TextNode with the boolean to.
* @param {boolean} bool Boolean.
* @private
*/
ol.format.KML.writeBooleanTextNode_ = function(node, bool) {
ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0');
};
/**
* @param {Node} node Node to append a TextNode with the color to.
* @param {ol.Color|string} color Color.
* @private
*/
ol.format.KML.writeColorTextNode_ = function(node, color) {
var rgba = ol.color.asArray(color);
var opacity = (rgba.length == 4) ? rgba[3] : 1;
var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]];
var i;
for (i = 0; i < 4; ++i) {
var hex = parseInt(abgr[i], 10).toString(16);
abgr[i] = (hex.length == 1) ? '0' + hex : hex;
}
ol.format.XSD.writeStringTextNode(node, abgr.join(''));
};
/**
* @param {Node} node Node to append a TextNode with the coordinates to.
* @param {Array.<number>} coordinates Coordinates.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeCoordinatesTextNode_ =
function(node, coordinates, objectStack) {
var context = objectStack[objectStack.length - 1];
goog.asserts.assert(goog.isObject(context));
var layout = goog.object.get(context, 'layout');
var stride = goog.object.get(context, 'stride');
var dimension;
if (layout == ol.geom.GeometryLayout.XY ||
layout == ol.geom.GeometryLayout.XYM) {
dimension = 2;
} else if (layout == ol.geom.GeometryLayout.XYZ ||
layout == ol.geom.GeometryLayout.XYZM) {
dimension = 3;
} else {
goog.asserts.fail();
}
var d, i;
var ii = coordinates.length;
var text = '';
if (ii > 0) {
text += coordinates[0];
for (d = 1; d < dimension; ++d) {
text += ',' + coordinates[d];
}
for (i = stride; i < ii; i += stride) {
text += ' ' + coordinates[i];
for (d = 1; d < dimension; ++d) {
text += ',' + coordinates[i + d];
}
}
}
ol.format.XSD.writeStringTextNode(node, text);
};
/**
* @param {Node} node Node.
* @param {Array.<ol.Feature>} features Features.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeDocument_ = function(node, features, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_,
ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack);
};
/**
* @param {Node} node Node.
* @param {Object} icon Icon object.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeIcon_ = function(node, icon, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(icon, orderedKeys);
ol.xml.pushSerializeAndPop(context,
ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
values, objectStack, orderedKeys);
orderedKeys =
ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]];
values = ol.xml.makeSequence(icon, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_,
ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.style.Icon} style Icon style.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeIconStyle_ = function(node, style, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
var properties = {};
var src = style.getSrc();
var size = style.getSize();
var iconImageSize = style.getImageSize();
var iconProperties = {
'href': src
};
if (!goog.isNull(size)) {
goog.object.set(iconProperties, 'w', size[0]);
goog.object.set(iconProperties, 'h', size[1]);
var anchor = style.getAnchor(); // top-left
var origin = style.getOrigin(); // top-left
if (!goog.isNull(origin) && !goog.isNull(iconImageSize) &&
origin[0] !== 0 && origin[1] !== size[1]) {
goog.object.set(iconProperties, 'x', origin[0]);
goog.object.set(iconProperties, 'y',
iconImageSize[1] - (origin[1] + size[1]));
}
if (!goog.isNull(anchor) &&
anchor[0] !== 0 && anchor[1] !== size[1]) {
var /** @type {ol.format.KMLVec2_} */ hotSpot = {
x: anchor[0],
xunits: ol.style.IconAnchorUnits.PIXELS,
y: size[1] - anchor[1],
yunits: ol.style.IconAnchorUnits.PIXELS
};
goog.object.set(properties, 'hotSpot', hotSpot);
}
}
goog.object.set(properties, 'Icon', iconProperties);
var scale = style.getScale();
if (scale !== 1) {
goog.object.set(properties, 'scale', scale);
}
var rotation = style.getRotation();
if (rotation !== 0) {
goog.object.set(properties, 'heading', rotation); // 0-360
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.style.Text} style style.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
var properties = {};
var fill = style.getFill();
if (!goog.isNull(fill)) {
goog.object.set(properties, 'color', fill.getColor());
}
var scale = style.getScale();
if (goog.isDef(scale) && scale !== 1) {
goog.object.set(properties, 'scale', scale);
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys =
ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.style.Stroke} style style.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeLineStyle_ = function(node, style, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
var properties = {
'color': style.getColor(),
'width': style.getWidth()
};
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.geom.Geometry} geometry Geometry.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeMultiGeometry_ =
function(node, geometry, objectStack) {
goog.asserts.assert(
(geometry instanceof ol.geom.MultiPoint) ||
(geometry instanceof ol.geom.MultiLineString) ||
(geometry instanceof ol.geom.MultiPolygon));
/** @type {ol.xml.NodeStackItem} */
var context = {node: node};
var type = geometry.getType();
/** @type {Array.<ol.geom.Geometry>} */
var geometries;
/** @type {function(*, Array.<*>, string=): (Node|undefined)} */
var factory;
if (type == ol.geom.GeometryType.MULTI_POINT) {
geometries =
(/** @type {ol.geom.MultiPoint} */ (geometry)).getPoints();
factory = ol.format.KML.POINT_NODE_FACTORY_;
} else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) {
geometries =
(/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings();
factory = ol.format.KML.LINE_STRING_NODE_FACTORY_;
} else if (type == ol.geom.GeometryType.MULTI_POLYGON) {
geometries =
(/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons();
factory = ol.format.KML.POLYGON_NODE_FACTORY_;
} else {
goog.asserts.fail();
}
ol.xml.pushSerializeAndPop(context,
ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory,
geometries, objectStack);
};
/**
* @param {Node} node Node.
* @param {ol.geom.LinearRing} linearRing Linear ring.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
ol.xml.pushSerializeAndPop(context,
ol.format.KML.BOUNDARY_IS_SERIALIZERS_,
ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack);
};
/**
* FIXME currently we do serialize arbitrary/custom feature properties
* (ExtendedData).
* @param {Node} node Node.
* @param {ol.Feature} feature Feature.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writePlacemark_ = function(node, feature, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
// set id
if (goog.isDefAndNotNull(feature.getId())) {
node.setAttribute('id', feature.getId());
}
// serialize geometry
ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
ol.format.KML.GEOMETRY_NODE_FACTORY_,
[feature.getGeometry()], objectStack);
// serialize properties (properties unknown to KML are not serialized)
var properties = feature.getProperties();
var styleFunction = feature.getStyleFunction();
if (goog.isDef(styleFunction)) {
// FIXME the styles returned by the style function are supposed to be
// resolution-independent here
var styles = styleFunction.call(feature, 0);
if (!goog.isNull(styles) && styles.length > 0) {
goog.object.set(properties, 'Style', styles[0]);
var textStyle = styles[0].getText();
if (!goog.isNull(textStyle)) {
goog.object.set(properties, 'name', textStyle.getText());
}
}
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node.
* @param {ol.geom.SimpleGeometry} geometry Geometry.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) {
goog.asserts.assert(
(geometry instanceof ol.geom.Point) ||
(geometry instanceof ol.geom.LineString) ||
(geometry instanceof ol.geom.LinearRing));
var flatCoordinates = geometry.getFlatCoordinates();
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
goog.object.set(context, 'layout', geometry.getLayout());
goog.object.set(context, 'stride', geometry.getStride());
ol.xml.pushSerializeAndPop(context,
ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_,
ol.format.KML.COORDINATES_NODE_FACTORY_,
[flatCoordinates], objectStack);
};
/**
* @param {Node} node Node.
* @param {ol.geom.Polygon} polygon Polygon.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writePolygon_ = function(node, polygon, objectStack) {
goog.asserts.assertInstanceof(polygon, ol.geom.Polygon);
var linearRings = polygon.getLinearRings();
goog.asserts.assert(linearRings.length > 0);
var outerRing = linearRings.shift();
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
// inner rings
ol.xml.pushSerializeAndPop(context,
ol.format.KML.POLYGON_SERIALIZERS_,
ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_,
linearRings, objectStack);
// outer ring
ol.xml.pushSerializeAndPop(context,
ol.format.KML.POLYGON_SERIALIZERS_,
ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_,
[outerRing], objectStack);
};
/**
* @param {Node} node Node.
* @param {ol.style.Fill} style Style.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writePolyStyle_ = function(node, style, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_,
ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack);
};
/**
* @param {Node} node Node to append a TextNode with the scale to.
* @param {number|undefined} scale Scale.
* @private
*/
ol.format.KML.writeScaleTextNode_ = function(node, scale) {
ol.format.XSD.writeDecimalTextNode(node, scale * scale);
};
/**
* @param {Node} node Node.
* @param {ol.style.Style} style Style.
* @param {Array.<*>} objectStack Object stack.
* @private
*/
ol.format.KML.writeStyle_ = function(node, style, objectStack) {
var /** @type {ol.xml.NodeStackItem} */ context = {node: node};
var properties = {};
var fillStyle = style.getFill();
var strokeStyle = style.getStroke();
var imageStyle = style.getImage();
var textStyle = style.getText();
if (!goog.isNull(imageStyle)) {
goog.object.set(properties, 'IconStyle', imageStyle);
}
if (!goog.isNull(textStyle)) {
goog.object.set(properties, 'LabelStyle', textStyle);
}
if (!goog.isNull(strokeStyle)) {
goog.object.set(properties, 'LineStyle', strokeStyle);
}
if (!goog.isNull(fillStyle)) {
goog.object.set(properties, 'PolyStyle', fillStyle);
}
var parentNode = objectStack[objectStack.length - 1].node;
var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
};
/**
* @param {Node} node Node to append a TextNode with the Vec2 to.
* @param {ol.format.KMLVec2_} vec2 Vec2.
* @private
*/
ol.format.KML.writeVec2_ = function(node, vec2) {
node.setAttribute('x', vec2.x);
node.setAttribute('y', vec2.y);
node.setAttribute('xunits', vec2.xunits);
node.setAttribute('yunits', vec2.yunits);
};
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'Document', 'Placemark'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_),
'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.DOCUMENT_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'Placemark'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
});
/**
* @const
* @type {Object.<string, string>}
* @private
*/
ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = {
'Point': 'Point',
'LineString': 'LineString',
'LinearRing': 'LinearRing',
'Polygon': 'Polygon',
'MultiPoint': 'MultiGeometry',
'MultiLineString': 'MultiGeometry',
'MultiPolygon': 'MultiGeometry'
};
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'href'
],
ol.xml.makeStructureNS(
ol.format.KML.GX_NAMESPACE_URIS_, [
'x', 'y', 'w', 'h'
]));
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
}, ol.xml.makeStructureNS(
ol.format.KML.GX_NAMESPACE_URIS_, {
'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
}));
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'Icon', 'heading', 'hotSpot', 'scale'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_),
'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_),
'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'color', 'scale'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'color', 'width'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'LinearRing': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'LineString': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_),
'Point': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_),
'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'Style', 'address', 'description', 'name', 'open',
'phoneNumber', 'styleUrl', 'visibility'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'MultiGeometry': ol.xml.makeChildAppender(
ol.format.KML.writeMultiGeometry_),
'LineString': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_),
'LinearRing': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_),
'Point': ol.xml.makeChildAppender(
ol.format.KML.writePrimitiveGeometry_),
'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),
'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_),
'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'description': ol.xml.makeChildAppender(
ol.format.XSD.writeStringTextNode),
'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'open': ol.xml.makeChildAppender(ol.format.KML.writeBooleanTextNode_),
'phoneNumber': ol.xml.makeChildAppender(
ol.format.XSD.writeStringTextNode),
'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
'visibility': ol.xml.makeChildAppender(
ol.format.KML.writeBooleanTextNode_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'coordinates': ol.xml.makeChildAppender(
ol.format.KML.writeCoordinatesTextNode_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'outerBoundaryIs': ol.xml.makeChildAppender(
ol.format.KML.writeBoundaryIs_),
'innerBoundaryIs': ol.xml.makeChildAppender(
ol.format.KML.writeBoundaryIs_)
});
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_)
});
/**
* @const
* @type {Object.<string, Array.<string>>}
* @private
*/
ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, [
'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle'
]);
/**
* @const
* @type {Object.<string, Object.<string, ol.xml.Serializer>>}
* @private
*/
ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
ol.format.KML.NAMESPACE_URIS_, {
'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_),
'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_),
'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_),
'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_)
});
/**
* @const
* @param {*} value Value.
* @param {Array.<*>} objectStack Object stack.
* @param {string=} opt_nodeName Node name.
* @return {Node|undefined} Node.
* @private
*/
ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0],
'gx:' + opt_nodeName);
};
/**
* @const
* @param {*} value Value.
* @param {Array.<*>} objectStack Object stack.
* @param {string=} opt_nodeName Node name.
* @return {Node|undefined} Node.
* @private
*/
ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack,
opt_nodeName) {
goog.asserts.assertInstanceof(value, ol.Feature);
var parentNode = objectStack[objectStack.length - 1].node;
goog.asserts.assert(ol.xml.isNode(parentNode));
return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark');
};
/**
* @const
* @param {*} value Value.
* @param {Array.<*>} objectStack Object stack.
* @param {string=} opt_nodeName Node name.
* @return {Node|undefined} Node.
* @private
*/
ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack,
opt_nodeName) {
if (goog.isDefAndNotNull(value)) {
goog.asserts.assertInstanceof(value, ol.geom.Geometry);
var parentNode = objectStack[objectStack.length - 1].node;
goog.asserts.assert(ol.xml.isNode(parentNode));
return ol.xml.createElementNS(parentNode.namespaceURI,
ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[value.getType()]);
}
};
/**
* A factory for creating coordinates nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color');
/**
* A factory for creating coordinates nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.COORDINATES_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('coordinates');
/**
* A factory for creating innerBoundaryIs nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('innerBoundaryIs');
/**
* A factory for creating Point nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.POINT_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('Point');
/**
* A factory for creating LineString nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.LINE_STRING_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('LineString');
/**
* A factory for creating LinearRing nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.LINEAR_RING_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('LinearRing');
/**
* A factory for creating Polygon nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.POLYGON_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('Polygon');
/**
* A factory for creating outerBoundaryIs nodes.
* @const
* @type {function(*, Array.<*>, string=): (Node|undefined)}
* @private
*/
ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ =
ol.xml.makeSimpleNodeFactory('outerBoundaryIs');
/**
* Encode an array of features in the KML format.
*
* @function
* @param {Array.<ol.Feature>} features Features.
* @return {ArrayBuffer|Node|Object|string} Result.
* @todo api
*/
ol.format.KML.prototype.writeFeatures;
/**
* @inheritDoc
*/
ol.format.KML.prototype.writeFeaturesNode = function(features) {
var kml = ol.xml.createElementNS('http://earth.google.com/kml/2.2', 'kml');
kml.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:gx',
ol.format.KML.GX_NAMESPACE_URIS_[0]);
var /** @type {ol.xml.NodeStackItem} */ context = {node: kml};
var properties = {};
if (features.length > 1) {
goog.object.set(properties, 'Document', features);
} else if (features.length == 1) {
goog.object.set(properties, 'Placemark', features[0]);
}
var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI];
var values = ol.xml.makeSequence(properties, orderedKeys);
ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_,
ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [], orderedKeys);
return kml;
};

View File

@@ -36,6 +36,28 @@ describe('ol.format.KML', function() {
expect(f.getId()).to.be(undefined);
});
it('can write a Feature', function() {
var features = [new ol.Feature()];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark/>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write a Feature\'s id', function() {
var feature = new ol.Feature();
feature.setId('foo');
var features = [feature];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark id="foo"/>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
});
describe('geometry', function() {
@@ -53,6 +75,16 @@ describe('ol.format.KML', function() {
expect(g).to.be(null);
});
it('can write feature with null geometries', function() {
var features = [new ol.Feature(null)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark/>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read Point geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -71,6 +103,70 @@ describe('ol.format.KML', function() {
expect(g.getCoordinates()).to.eql([1, 2, 3]);
});
it('can write XY Point geometries', function() {
var layout = ol.geom.GeometryLayout.XY;
var point = new ol.geom.Point([1, 2], layout);
var features = [new ol.Feature(point)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Point>' +
' <coordinates>1,2</coordinates>' +
' </Point>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZ Point geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var point = new ol.geom.Point([1, 2, 3], layout);
var features = [new ol.Feature(point)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Point>' +
' <coordinates>1,2,3</coordinates>' +
' </Point>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYM Point geometries', function() {
var layout = ol.geom.GeometryLayout.XYM;
var point = new ol.geom.Point([1, 2, 100], layout);
var features = [new ol.Feature(point)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Point>' +
' <coordinates>1,2</coordinates>' +
' </Point>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZM Point geometries', function() {
var layout = ol.geom.GeometryLayout.XYZM;
var point = new ol.geom.Point([1, 2, 3, 100], layout);
var features = [new ol.Feature(point)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Point>' +
' <coordinates>1,2,3</coordinates>' +
' </Point>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read LineString geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -89,6 +185,73 @@ describe('ol.format.KML', function() {
expect(g.getCoordinates()).to.eql([[1, 2, 3], [4, 5, 6]]);
});
it('can write XY LineString geometries', function() {
var layout = ol.geom.GeometryLayout.XY;
var lineString = new ol.geom.LineString([[1, 2], [3, 4]], layout);
var features = [new ol.Feature(lineString)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LineString>' +
' <coordinates>1,2 3,4</coordinates>' +
' </LineString>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZ LineString geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var lineString = new ol.geom.LineString(
[[1, 2, 3], [4, 5, 6]], layout);
var features = [new ol.Feature(lineString)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LineString>' +
' <coordinates>1,2,3 4,5,6</coordinates>' +
' </LineString>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYM LineString geometries', function() {
var layout = ol.geom.GeometryLayout.XYM;
var lineString = new ol.geom.LineString(
[[1, 2, 100], [3, 4, 200]], layout);
var features = [new ol.Feature(lineString)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LineString>' +
' <coordinates>1,2 3,4</coordinates>' +
' </LineString>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZM LineString geometries', function() {
var layout = ol.geom.GeometryLayout.XYZM;
var lineString = new ol.geom.LineString(
[[1, 2, 3, 100], [4, 5, 6, 200]], layout);
var features = [new ol.Feature(lineString)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LineString>' +
' <coordinates>1,2,3 4,5,6</coordinates>' +
' </LineString>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read LinearRing geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -107,6 +270,74 @@ describe('ol.format.KML', function() {
expect(g.getCoordinates()).to.eql([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]);
});
it('can write XY LinearRing geometries', function() {
var layout = ol.geom.GeometryLayout.XY;
var linearRing = new ol.geom.LinearRing(
[[1, 2], [3, 4], [1, 2]], layout);
var features = [new ol.Feature(linearRing)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LinearRing>' +
' <coordinates>1,2 3,4 1,2</coordinates>' +
' </LinearRing>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZ LinearRing geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var linearRing = new ol.geom.LinearRing(
[[1, 2, 3], [4, 5, 6], [1, 2, 3]], layout);
var features = [new ol.Feature(linearRing)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LinearRing>' +
' <coordinates>1,2,3 4,5,6 1,2,3</coordinates>' +
' </LinearRing>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYM LinearRing geometries', function() {
var layout = ol.geom.GeometryLayout.XYM;
var linearRing = new ol.geom.LinearRing(
[[1, 2, 100], [3, 4, 200], [1, 2, 100]], layout);
var features = [new ol.Feature(linearRing)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LinearRing>' +
' <coordinates>1,2 3,4 1,2</coordinates>' +
' </LinearRing>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZM LinearRing geometries', function() {
var layout = ol.geom.GeometryLayout.XYZM;
var linearRing = new ol.geom.LinearRing(
[[1, 2, 3, 100], [4, 5, 6, 200], [1, 2, 3, 100]], layout);
var features = [new ol.Feature(linearRing)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <LinearRing>' +
' <coordinates>1,2,3 4,5,6 1,2,3</coordinates>' +
' </LinearRing>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read Polygon geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -130,6 +361,95 @@ describe('ol.format.KML', function() {
[[[0, 0, 1], [0, 5, 1], [5, 5, 2], [5, 0, 3]]]);
});
it('can write XY Polygon geometries', function() {
var layout = ol.geom.GeometryLayout.XY;
var polygon = new ol.geom.Polygon(
[[[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]]], layout);
var features = [new ol.Feature(polygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>0,0 0,2 2,2 2,0 0,0</coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZ Polygon geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var polygon = new ol.geom.Polygon(
[[[0, 0, 1], [0, 2, 2], [2, 2, 3], [2, 0, 4], [0, 0, 5]]], layout);
var features = [new ol.Feature(polygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>' +
' 0,0,1 0,2,2 2,2,3 2,0,4 0,0,5' +
' </coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYM Polygon geometries', function() {
var layout = ol.geom.GeometryLayout.XYM;
var polygon = new ol.geom.Polygon(
[[[0, 0, 1], [0, 2, 1], [2, 2, 1], [2, 0, 1], [0, 0, 1]]], layout);
var features = [new ol.Feature(polygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>' +
' 0,0 0,2 2,2 2,0 0,0' +
' </coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write XYZM Polygon geometries', function() {
var layout = ol.geom.GeometryLayout.XYZM;
var polygon = new ol.geom.Polygon(
[[[0, 0, 1, 1], [0, 2, 2, 1], [2, 2, 3, 1],
[2, 0, 4, 1], [0, 0, 5, 1]]], layout);
var features = [new ol.Feature(polygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>0,0,1 0,2,2 2,2,3 2,0,4 0,0,5</coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read complex Polygon geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -165,6 +485,39 @@ describe('ol.format.KML', function() {
[[3, 3, 0], [3, 4, 0], [4, 4, 0], [4, 3, 0]]]);
});
it('can write complex Polygon geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var polygon = new ol.geom.Polygon(
[[[0, 0, 1], [0, 5, 1], [5, 5, 2], [5, 0, 3]],
[[1, 1, 0], [1, 2, 0], [2, 2, 0], [2, 1, 0]],
[[3, 3, 0], [3, 4, 0], [4, 4, 0], [4, 3, 0]]], layout);
var features = [new ol.Feature(polygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <Polygon>' +
' <innerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>1,1,0 1,2,0 2,2,0 2,1,0</coordinates>' +
' </LinearRing>' +
' </innerBoundaryIs>' +
' <innerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>3,3,0 3,4,0 4,4,0 4,3,0</coordinates>' +
' </LinearRing>' +
' </innerBoundaryIs>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>0,0,1 0,5,1 5,5,2 5,0,3</coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read MultiPoint geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -188,6 +541,28 @@ describe('ol.format.KML', function() {
expect(g.getCoordinates()).to.eql([[1, 2, 3], [4, 5, 6]]);
});
it('can write MultiPoint geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var multiPoint = new ol.geom.MultiPoint(
[[1, 2, 3], [4, 5, 6]], layout);
var features = [new ol.Feature(multiPoint)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <MultiGeometry>' +
' <Point>' +
' <coordinates>1,2,3</coordinates>' +
' </Point>' +
' <Point>' +
' <coordinates>4,5,6</coordinates>' +
' </Point>' +
' </MultiGeometry>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read MultiLineString geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -212,6 +587,28 @@ describe('ol.format.KML', function() {
[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]);
});
it('can write MultiLineString geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var multiLineString = new ol.geom.MultiLineString(
[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]], layout);
var features = [new ol.Feature(multiLineString)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <MultiGeometry>' +
' <LineString>' +
' <coordinates>1,2,3 4,5,6</coordinates>' +
' </LineString>' +
' <LineString>' +
' <coordinates>7,8,9 10,11,12</coordinates>' +
' </LineString>' +
' </MultiGeometry>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read MultiPolygon geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -245,6 +642,37 @@ describe('ol.format.KML', function() {
[[[3, 0, 0], [3, 1, 0], [4, 1, 0], [4, 0, 0]]]]);
});
it('can write MultiPolygon geometries', function() {
var layout = ol.geom.GeometryLayout.XYZ;
var multiPolygon = new ol.geom.MultiPolygon(
[[[[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0]]],
[[[3, 0, 0], [3, 1, 0], [4, 1, 0], [4, 0, 0]]]], layout);
var features = [new ol.Feature(multiPolygon)];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <MultiGeometry>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>0,0,0 0,1,0 1,1,0 1,0,0</coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' <Polygon>' +
' <outerBoundaryIs>' +
' <LinearRing>' +
' <coordinates>3,0,0 3,1,0 4,1,0 4,0,0</coordinates>' +
' </LinearRing>' +
' </outerBoundaryIs>' +
' </Polygon>' +
' </MultiGeometry>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can read empty GeometryCollection geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
@@ -488,6 +916,42 @@ describe('ol.format.KML', function() {
expect(f.get('name')).to.be('My name in CDATA');
});
it('can write Feature\'s string attributes', function() {
var feature = new ol.Feature();
feature.set('address', 'My address');
feature.set('description', 'My description');
feature.set('name', 'My name');
feature.set('phoneNumber', 'My phone number');
var features = [feature];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <address>My address</address>' +
' <description>My description</description>' +
' <name>My name</name>' +
' <phoneNumber>My phone number</phoneNumber>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write Feature\'s boolean attributes', function() {
var feature = new ol.Feature();
feature.set('open', true);
feature.set('visibility', false);
var features = [feature];
var node = format.writeFeatures(features);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
' <open>1</open>' +
' <visibility>0</visibility>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
});
describe('extended data', function() {
@@ -719,6 +1183,9 @@ describe('ol.format.KML', function() {
' </Placemark>' +
'</kml>';
var fs = format.readFeatures(text);
expect(fs).to.have.length(1);
var f = fs[0];
expect(f).to.be.an(ol.Feature);
@@ -850,6 +1317,127 @@ describe('ol.format.KML', function() {
expect(style.getZIndex()).to.be(undefined);
});
it('can write an feature\'s icon style', function() {
var style = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.25, 36],
anchorOrigin: ol.style.IconOrigin.TOP_LEFT,
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
crossOrigin: 'anonymous',
offset: [96, 96],
offsetOrigin: ol.style.IconOrigin.TOP_LEFT,
rotation: 45,
scale: 0.5,
size: [48, 48],
src: 'http://foo.png'
})
});
var imageStyle = style.getImage();
imageStyle.iconImage_.size_ = [192, 144]; // sprite de 12 images(4*3)
var feature = new ol.Feature();
feature.setStyle([style]);
var node = format.writeFeatures([feature]);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2"' +
' xmlns:gx="http://www.google.com/kml/ext/2.2">' +
' <Placemark>' +
' <Style>' +
' <IconStyle>' +
' <Icon>' +
' <href>http://foo.png</href>' +
' <gx:x>96</gx:x>' +
' <gx:y>0</gx:y>' +
' <gx:w>48</gx:w>' +
' <gx:h>48</gx:h>' +
' </Icon>' +
' <heading>45</heading>' +
' <hotSpot x="12" y="12" xunits="pixels" ' +
' yunits="pixels"/>' +
' <scale>0.25</scale>' +
' </IconStyle>' +
' </Style>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write an feature\'s text style', function() {
var style = new ol.style.Style({
text: new ol.style.Text({
scale: 0.5,
text: 'foo',
fill: new ol.style.Fill({
color: 'rgb(12, 34, 223)'
})
})
});
var feature = new ol.Feature();
feature.setStyle([style]);
var node = format.writeFeatures([feature]);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2"' +
' xmlns:gx="http://www.google.com/kml/ext/2.2">' +
' <Placemark>' +
' <Style>' +
' <LabelStyle>' +
' <color>ffdf220c</color>' +
' <scale>0.25</scale>' +
' </LabelStyle>' +
' </Style>' +
' <name>foo</name>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write an feature\'s stroke style', function() {
var style = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#112233',
width: 2
})
});
var feature = new ol.Feature();
feature.setStyle([style]);
var node = format.writeFeatures([feature]);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2"' +
' xmlns:gx="http://www.google.com/kml/ext/2.2">' +
' <Placemark>' +
' <Style>' +
' <LineStyle>' +
' <color>ff332211</color>' +
' <width>2</width>' +
' </LineStyle>' +
' </Style>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
it('can write an feature\'s fill style', function() {
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(12, 34, 223, 0.7)'
})
});
var feature = new ol.Feature();
feature.setStyle([style]);
var node = format.writeFeatures([feature]);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2"' +
' xmlns:gx="http://www.google.com/kml/ext/2.2">' +
' <Placemark>' +
' <Style>' +
' <PolyStyle>' +
' <color>b2df220c</color>' +
' </PolyStyle>' +
' </Style>' +
' </Placemark>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
});
describe('style maps', function() {
@@ -1323,6 +1911,25 @@ describe('ol.format.KML', function() {
'</kml>')).to.be.empty();
});
it('can write multiple features', function() {
var feature1 = new ol.Feature();
feature1.setId('1');
var feature2 = new ol.Feature();
feature2.setId('2');
var node = format.writeFeatures([feature1, feature2]);
var text =
'<kml xmlns="http://earth.google.com/kml/2.2" ' +
' xmlns:gx="http://www.google.com/kml/ext/2.2">' +
' <Document>' +
' <Placemark id="1">' +
' </Placemark>' +
' <Placemark id="2">' +
' </Placemark>' +
' </Document>' +
'</kml>';
expect(node).to.xmleql(ol.xml.load(text));
});
});
describe('error handling', function() {
@@ -1582,6 +2189,7 @@ goog.require('ol.Feature');
goog.require('ol.format.KML');
goog.require('ol.geom.GeometryCollection');
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');
@@ -1589,5 +2197,8 @@ goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.style.Fill');
goog.require('ol.style.Icon');
goog.require('ol.style.IconOrigin');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.style.Text');
goog.require('ol.xml');