import CircleStyle from '../../../../../src/ol/style/Circle.js';
import Feature from '../../../../../src/ol/Feature.js';
import Fill from '../../../../../src/ol/style/Fill.js';
import GeoJSON from '../../../../../src/ol/format/GeoJSON.js';
import GeometryCollection from '../../../../../src/ol/geom/GeometryCollection.js';
import Icon from '../../../../../src/ol/style/Icon.js';
import IconAnchorUnits from '../../../../../src/ol/style/IconAnchorUnits.js';
import IconOrigin from '../../../../../src/ol/style/IconOrigin.js';
import ImageState from '../../../../../src/ol/ImageState.js';
import KML, {
getDefaultFillStyle,
getDefaultImageStyle,
getDefaultStrokeStyle,
getDefaultStyle,
getDefaultStyleArray,
getDefaultTextStyle,
readFlatCoordinates,
} from '../../../../../src/ol/format/KML.js';
import LineString from '../../../../../src/ol/geom/LineString.js';
import LinearRing from '../../../../../src/ol/geom/LinearRing.js';
import MultiLineString from '../../../../../src/ol/geom/MultiLineString.js';
import MultiPoint from '../../../../../src/ol/geom/MultiPoint.js';
import MultiPolygon from '../../../../../src/ol/geom/MultiPolygon.js';
import Point from '../../../../../src/ol/geom/Point.js';
import Polygon from '../../../../../src/ol/geom/Polygon.js';
import Projection from '../../../../../src/ol/proj/Projection.js';
import Stroke from '../../../../../src/ol/style/Stroke.js';
import Style from '../../../../../src/ol/style/Style.js';
import Text from '../../../../../src/ol/style/Text.js';
import {
addCoordinateTransforms,
addProjection,
get as getProjection,
transform,
} from '../../../../../src/ol/proj.js';
import {find} from '../../../../../src/ol/array.js';
import {parse} from '../../../../../src/ol/xml.js';
import {remove as removeTransform} from '../../../../../src/ol/proj/transforms.js';
describe('ol.format.KML', function () {
let format;
describe('using defaultStyle', function () {
const dfltStyle = new Style();
beforeEach(function () {
format = new KML({
defaultStyle: [dfltStyle],
});
});
it('set constant variables', function () {
expect(getDefaultStyleArray()).to.be.an(Array);
});
describe('#readFeatures', function () {
it('can apply a default style to a feature', function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style).to.be(dfltStyle);
});
});
});
describe('without parameters', function () {
beforeEach(function () {
format = new KML();
});
it('set constant variables', function () {
expect(getDefaultStyleArray()).to.be.an(Array);
});
describe('#readProjection', function () {
it('returns the default projection from document', function () {
const projection = format.readProjectionFromDocument();
expect(projection).to.eql(getProjection('EPSG:4326'));
});
it('returns the default projection from node', function () {
const projection = format.readProjectionFromNode();
expect(projection).to.eql(getProjection('EPSG:4326'));
});
});
describe('#readFeatures', function () {
describe('id', function () {
it("can read a Feature's id", function () {
const text =
'' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getId()).to.be('foo');
});
it('treats a missing id as undefined', function () {
const text =
'' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getId()).to.be(undefined);
});
it('can write a Feature', function () {
const features = [new Feature()];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write a Feature as string', function () {
const features = [new Feature()];
const node = format.writeFeatures(features);
const text =
'' +
' ' +
'';
expect(parse(node)).to.xmleql(parse(text));
});
it("can write a Feature's id", function () {
const feature = new Feature();
feature.setId('foo');
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
});
describe('geometry', function () {
it('treats a missing geometry as null', function () {
const text =
'' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be(null);
});
it('can write feature with null geometries', function () {
const features = [new Feature(null)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write properties', function () {
const lineString = new LineString([
[1, 2],
[3, 4],
]);
lineString.set('extrude', false);
lineString.set('tessellate', true);
lineString.set('altitudeMode', 'clampToGround');
lineString.set('unsupportedProperty', 'foo');
const features = [new Feature(lineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 0' +
' 1' +
' clampToGround' +
' 1,2 3,4' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read Point geometries', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' 0' +
' absolute' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([1, 2, 3]);
expect(g.get('extrude')).to.be(false);
expect(g.get('altitudeMode')).to.be('absolute');
});
it('can transform and read Point geometries', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
const fs = format.readFeatures(text, {
featureProjection: 'EPSG:3857',
});
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Point);
const expectedPoint = transform([1, 2], 'EPSG:4326', 'EPSG:3857');
expectedPoint.push(3);
expect(g.getCoordinates()).to.eql(expectedPoint);
});
it('can read a single Point geometry', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
const f = format.readFeature(text);
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Point);
expect(g.getCoordinates()).to.eql([1, 2, 3]);
});
it('can transform and read a single Point geometry', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
const f = format.readFeature(text, {
featureProjection: 'EPSG:3857',
});
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Point);
const expectedPoint = transform([1, 2], 'EPSG:4326', 'EPSG:3857');
expectedPoint.push(3);
expect(g.getCoordinates()).to.eql(expectedPoint);
});
it('can write XY Point geometries', function () {
const layout = 'XY';
const point = new Point([1, 2], layout);
const features = [new Feature(point)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZ Point geometries', function () {
const layout = 'XYZ';
const point = new Point([1, 2, 3], layout);
const features = [new Feature(point)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can transform and write XYZ Point geometries', function () {
addProjection(new Projection({code: 'double'}));
addCoordinateTransforms(
'EPSG:4326',
'double',
function (coordinate) {
return [2 * coordinate[0], 2 * coordinate[1]];
},
function (coordinate) {
return [coordinate[0] / 2, coordinate[1] / 2];
}
);
const layout = 'XYZ';
const point = new Point([1, 2, 3], layout).transform(
'EPSG:4326',
'double'
);
const features = [new Feature(point)];
const node = format.writeFeaturesNode(features, {
featureProjection: 'double',
});
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
removeTransform(getProjection('EPSG:4326'), getProjection('double'));
removeTransform(getProjection('double'), getProjection('EPSG:4326'));
});
it('can write XYM Point geometries', function () {
const layout = 'XYM';
const point = new Point([1, 2, 100], layout);
const features = [new Feature(point)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZM Point geometries', function () {
const layout = 'XYZM';
const point = new Point([1, 2, 3, 100], layout);
const features = [new Feature(point)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read LineString geometries', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6' +
' 0' +
' 1' +
' absolute' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([
[1, 2, 3],
[4, 5, 6],
]);
expect(g.get('extrude')).to.be(false);
expect(g.get('tessellate')).to.be(true);
expect(g.get('altitudeMode')).to.be('absolute');
});
it('can read XY coordinates', function () {
const text =
'' +
' ' +
' ' +
' 1,2 3,4' +
' 0' +
' 1' +
' absolute' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([
[1, 2, 0],
[3, 4, 0],
]);
});
it('can read empty Z coordinates', function () {
const text =
'' +
' ' +
' ' +
' 1,2, 3,4,' +
' 0' +
' 1' +
' absolute' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(LineString);
expect(g.getCoordinates()).to.eql([
[1, 2, 0],
[3, 4, 0],
]);
});
it('can write XY LineString geometries', function () {
const layout = 'XY';
const lineString = new LineString(
[
[1, 2],
[3, 4],
],
layout
);
const features = [new Feature(lineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZ LineString geometries', function () {
const layout = 'XYZ';
const lineString = new LineString(
[
[1, 2, 3],
[4, 5, 6],
],
layout
);
const features = [new Feature(lineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYM LineString geometries', function () {
const layout = 'XYM';
const lineString = new LineString(
[
[1, 2, 100],
[3, 4, 200],
],
layout
);
const features = [new Feature(lineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZM LineString geometries', function () {
const layout = 'XYZM';
const lineString = new LineString(
[
[1, 2, 3, 100],
[4, 5, 6, 200],
],
layout
);
const features = [new Feature(lineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read LinearRing geometries', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6 7,8,9' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
],
]);
});
it('can write XY LinearRing geometries', function () {
const layout = 'XY';
const linearRing = new LinearRing(
[
[1, 2],
[3, 4],
[1, 2],
],
layout
);
const features = [new Feature(linearRing)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2 3,4 1,2' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZ LinearRing geometries', function () {
const layout = 'XYZ';
const linearRing = new LinearRing(
[
[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
],
layout
);
const features = [new Feature(linearRing)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6 1,2,3' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYM LinearRing geometries', function () {
const layout = 'XYM';
const linearRing = new LinearRing(
[
[1, 2, 100],
[3, 4, 200],
[1, 2, 100],
],
layout
);
const features = [new Feature(linearRing)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2 3,4 1,2' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZM LinearRing geometries', function () {
const layout = 'XYZM';
const linearRing = new LinearRing(
[
[1, 2, 3, 100],
[4, 5, 6, 200],
[1, 2, 3, 100],
],
layout
);
const features = [new Feature(linearRing)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' 1,2,3 4,5,6 1,2,3' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read Polygon geometries', function () {
const text =
'' +
' ' +
' ' +
' 0' +
' absolute' +
' ' +
' ' +
' 0,0,1 0,5,1 5,5,2 5,0,3' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([
[
[0, 0, 1],
[0, 5, 1],
[5, 5, 2],
[5, 0, 3],
],
]);
expect(g.get('extrude')).to.be(false);
expect(g.get('altitudeMode')).to.be('absolute');
});
it('can write XY Polygon geometries', function () {
const layout = 'XY';
const polygon = new Polygon(
[
[
[0, 0],
[0, 2],
[2, 2],
[2, 0],
[0, 0],
],
],
layout
);
const features = [new Feature(polygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 0,0 0,2 2,2 2,0 0,0' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZ Polygon geometries', function () {
const layout = 'XYZ';
const polygon = new Polygon(
[
[
[0, 0, 1],
[0, 2, 2],
[2, 2, 3],
[2, 0, 4],
[0, 0, 5],
],
],
layout
);
const features = [new Feature(polygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 0,0,1 0,2,2 2,2,3 2,0,4 0,0,5' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYM Polygon geometries', function () {
const layout = 'XYM';
const polygon = new Polygon(
[
[
[0, 0, 1],
[0, 2, 1],
[2, 2, 1],
[2, 0, 1],
[0, 0, 1],
],
],
layout
);
const features = [new Feature(polygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 0,0 0,2 2,2 2,0 0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write XYZM Polygon geometries', function () {
const layout = 'XYZM';
const polygon = new Polygon(
[
[
[0, 0, 1, 1],
[0, 2, 2, 1],
[2, 2, 3, 1],
[2, 0, 4, 1],
[0, 0, 5, 1],
],
],
layout
);
const features = [new Feature(polygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 0,0,1 0,2,2 2,2,3 2,0,4 0,0,5' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read complex Polygon geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,1,0 1,2,0 2,2,0 2,1,0' +
' ' +
' ' +
' ' +
' ' +
' 3,3,0 3,4,0 4,4,0 4,3,0' +
' ' +
' ' +
' ' +
' ' +
' 0,0,1 0,5,1 5,5,2 5,0,3' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([
[
[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],
],
]);
});
it('can read multiple LinearRings from one innerBoundaryIs', function () {
const text = `
1,1,0 1,2,0 2,2,0 2,1,0
3,3,0 3,4,0 4,4,0 4,3,0
0,0,1 0,5,1 5,5,2 5,0,3
`;
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Polygon);
expect(g.getCoordinates()).to.eql([
[
[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],
],
]);
});
it('can write complex Polygon geometries', function () {
const layout = 'XYZ';
const polygon = new 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
);
const features = [new Feature(polygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,1,0 1,2,0 2,2,0 2,1,0' +
' ' +
' ' +
' ' +
' ' +
' 3,3,0 3,4,0 4,4,0 4,3,0' +
' ' +
' ' +
' ' +
' ' +
' 0,0,1 0,5,1 5,5,2 5,0,3' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read MultiPolygon geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 0' +
' absolute' +
' ' +
' ' +
' 0,0,0 0,1,0 1,1,0 1,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 3,0,0 3,1,0 4,1,0 4,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[
[
[0, 0, 0],
[0, 1, 0],
[1, 1, 0],
[1, 0, 0],
],
],
[
[
[3, 0, 0],
[3, 1, 0],
[4, 1, 0],
[4, 0, 0],
],
],
]);
expect(g.get('extrude')).to.be.an('array');
expect(g.get('extrude')).to.have.length(2);
expect(g.get('extrude')[0]).to.be(false);
expect(g.get('extrude')[1]).to.be(undefined);
expect(g.get('altitudeMode')).to.be.an('array');
expect(g.get('altitudeMode')).to.have.length(2);
expect(g.get('altitudeMode')[0]).to.be('absolute');
expect(g.get('altitudeMode')[1]).to.be(undefined);
});
it('can write MultiPolygon geometries', function () {
const layout = 'XYZ';
const multiPolygon = new 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
);
const features = [new Feature(multiPolygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 0,0,0 0,1,0 1,1,0 1,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 3,0,0 3,1,0 4,1,0 4,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read MultiPoint geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 1,2,3' +
' 0' +
' absolute' +
' ' +
' ' +
' 4,5,6' +
' 1' +
' clampToGround' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(MultiPoint);
expect(g.getCoordinates()).to.eql([
[1, 2, 3],
[4, 5, 6],
]);
expect(g.get('extrude')).to.be.an('array');
expect(g.get('extrude')).to.have.length(2);
expect(g.get('extrude')[0]).to.be(false);
expect(g.get('extrude')[1]).to.be(true);
expect(g.get('altitudeMode')).to.be.an('array');
expect(g.get('altitudeMode')).to.have.length(2);
expect(g.get('altitudeMode')[0]).to.be('absolute');
expect(g.get('altitudeMode')[1]).to.be('clampToGround');
});
it('can write MultiPoint geometries', function () {
const layout = 'XYZ';
const multiPoint = new MultiPoint(
[
[1, 2, 3],
[4, 5, 6],
],
layout
);
const features = [new Feature(multiPoint)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
' 4,5,6' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read MultiLineString geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 0' +
' 0' +
' absolute' +
' 1,2,3 4,5,6' +
' ' +
' ' +
' 7,8,9 10,11,12' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(MultiLineString);
expect(g.getCoordinates()).to.eql([
[
[1, 2, 3],
[4, 5, 6],
],
[
[7, 8, 9],
[10, 11, 12],
],
]);
expect(g.get('extrude')).to.be.an('array');
expect(g.get('extrude')).to.have.length(2);
expect(g.get('extrude')[0]).to.be(false);
expect(g.get('extrude')[1]).to.be(undefined);
expect(g.get('tessellate')).to.be.an('array');
expect(g.get('tessellate')).to.have.length(2);
expect(g.get('tessellate')[0]).to.be(false);
expect(g.get('tessellate')[1]).to.be(undefined);
expect(g.get('altitudeMode')).to.be.an('array');
expect(g.get('altitudeMode')).to.have.length(2);
expect(g.get('altitudeMode')[0]).to.be('absolute');
expect(g.get('altitudeMode')[1]).to.be(undefined);
});
it('can write MultiLineString geometries', function () {
const layout = 'XYZ';
const multiLineString = new MultiLineString(
[
[
[1, 2, 3],
[4, 5, 6],
],
[
[7, 8, 9],
[10, 11, 12],
],
],
layout
);
const features = [new Feature(multiLineString)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' 1,2,3 4,5,6' +
' ' +
' ' +
' 7,8,9 10,11,12' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read MultiPolygon geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 0' +
' absolute' +
' ' +
' ' +
' 0,0,0 0,1,0 1,1,0 1,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 3,0,0 3,1,0 4,1,0 4,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(MultiPolygon);
expect(g.getCoordinates()).to.eql([
[
[
[0, 0, 0],
[0, 1, 0],
[1, 1, 0],
[1, 0, 0],
],
],
[
[
[3, 0, 0],
[3, 1, 0],
[4, 1, 0],
[4, 0, 0],
],
],
]);
expect(g.get('extrude')).to.be.an('array');
expect(g.get('extrude')).to.have.length(2);
expect(g.get('extrude')[0]).to.be(false);
expect(g.get('extrude')[1]).to.be(undefined);
expect(g.get('altitudeMode')).to.be.an('array');
expect(g.get('altitudeMode')).to.have.length(2);
expect(g.get('altitudeMode')[0]).to.be('absolute');
expect(g.get('altitudeMode')[1]).to.be(undefined);
});
it('can write MultiPolygon geometries', function () {
const layout = 'XYZ';
const multiPolygon = new 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
);
const features = [new Feature(multiPolygon)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 0,0,0 0,1,0 1,1,0 1,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 3,0,0 3,1,0 4,1,0 4,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read empty GeometryCollection geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(GeometryCollection);
expect(g.getGeometries()).to.be.empty();
});
it('can read heterogeneous GeometryCollection geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
' 1,2,3 4,5,6' +
' ' +
' ' +
' 1,2,3 4,5,6 7,8,9' +
' ' +
' ' +
' ' +
' ' +
' 0,0,0 0,1,0 1,1,0 1,0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(GeometryCollection);
const gs = g.getGeometries();
expect(gs).to.have.length(4);
expect(gs[0]).to.be.an(Point);
expect(gs[1]).to.be.an(LineString);
expect(gs[2]).to.be.an(Polygon);
expect(gs[3]).to.be.an(Polygon);
});
it('can read nested GeometryCollection geometries', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(GeometryCollection);
const gs = g.getGeometries();
expect(gs).to.have.length(1);
expect(gs[0]).to.be.an(GeometryCollection);
});
it('can write GeometryCollection geometries', function () {
const collection = new GeometryCollection([
new GeometryCollection([
new Point([1, 2]),
new LineString([
[1, 2],
[3, 4],
]),
new Polygon([
[
[1, 2],
[3, 4],
[3, 2],
[1, 2],
],
]),
]),
new GeometryCollection([
new MultiPoint([
[5, 6],
[9, 10],
]),
new MultiLineString([
[
[5, 6],
[7, 8],
],
[
[9, 10],
[11, 12],
],
]),
new MultiPolygon([
[
[
[5, 6],
[7, 8],
[7, 6],
[5, 6],
],
],
[
[
[9, 10],
[11, 12],
[11, 10],
[9, 10],
],
],
]),
]),
]);
const features = [new Feature(collection)];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' 1,2' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
' ' +
' ' +
' 1,2 3,4 3,2 1,2' +
' ' +
' ' +
' ' +
' ' +
' 5,6' +
' ' +
' ' +
' 9,10' +
' ' +
' ' +
' 5,6 7,8' +
' ' +
' ' +
' 9,10 11,12' +
' ' +
' ' +
' ' +
' ' +
' 5,6 7,8 7,6 5,6' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 9,10 11,12 11,10 9,10' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read gx:Track', function () {
const text =
'' +
' ' +
' ' +
' 2014-01-06T19:38:55Z' +
' 2014-01-06T19:39:03Z' +
' 2014-01-06T19:39:10Z' +
' 2014-01-06T19:39:17Z' +
' 8.1 46.1 1909.9' +
' 8.2 46.2 1925.2' +
' 8.3 46.3 1926.2' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(LineString);
});
it('can read gx:MultiTrack', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 2014-01-06T19:38:55Z' +
' 8.1 46.1 1909.9' +
' ' +
' ' +
' 2014-01-06T19:38:55Z' +
' 2014-01-06T19:39:10Z' +
' 8.1 46.1 1909.9' +
' 8.2 46.2 1925.2' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(MultiLineString);
const gs = g.getLineStrings();
expect(gs).to.have.length(2);
expect(gs[0]).to.be.an(LineString);
});
it('can read dateTime', function () {
const text =
'' +
' ' +
' ' +
' 2014' +
' 2014-02' +
' 2014-02-06' +
' 2014-02-06T19:39:03Z' +
' 2014-02-06T19:39:10+03:00' +
' 8.1 46.1 1909.9' +
' 8.2 46.2 1925.2' +
' 8.3 46.3 1926.2' +
' 8.4 46.4 1927.2' +
' 8.5 46.5 1928.2' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
const f = fs[0];
const g = f.getGeometry();
const flatCoordinates = g.flatCoordinates;
expect(flatCoordinates[3]).to.be.eql(Date.UTC(2014, 0, 1, 0, 0, 0));
expect(flatCoordinates[7]).to.be.eql(Date.UTC(2014, 1, 1, 0, 0, 0));
expect(flatCoordinates[11]).to.be.eql(Date.UTC(2014, 1, 6, 0, 0, 0));
expect(flatCoordinates[15]).to.be.eql(
Date.UTC(2014, 1, 6, 19, 39, 3)
);
expect(flatCoordinates[19]).to.be.eql(
Date.UTC(2014, 1, 6, 16, 39, 10)
);
});
});
describe('attributes', function () {
it('can read boolean attributes', function () {
const text =
'' +
' ' +
' 1' +
' 0' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('open')).to.be(true);
expect(f.get('visibility')).to.be(false);
});
it('can read string attributes', function () {
const text =
'' +
' ' +
' My address' +
' My description' +
' My name' +
' My phone number' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('address')).to.be('My address');
expect(f.get('description')).to.be('My description');
expect(f.get('name')).to.be('My name');
expect(f.get('phoneNumber')).to.be('My phone number');
});
it('strips leading and trailing whitespace in strings', function () {
const text =
'' +
' ' +
' \n\nMy description\n\n' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('description')).to.be('My description');
});
it('can read CDATA sections in strings', function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('name')).to.be('My name in CDATA');
});
it('strips leading and trailing whitespace around CDATA', function () {
const text =
'' +
' ' +
' \n\n\n\n' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('name')).to.be('My name in CDATA');
});
it("can write Feature's string attributes", function () {
const feature = new Feature();
feature.set('address', 'My address');
feature.set('description', 'My description');
feature.set('name', 'My name');
feature.set('phoneNumber', 'My phone number');
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' My name' +
' My address' +
' My phone number' +
' My description' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it("can write Feature's boolean attributes", function () {
const feature = new Feature();
feature.set('open', true);
feature.set('visibility', false);
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' 1' +
' 0' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
});
describe('region', function () {
it('can read Region', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 43.651015' +
' 43.540908' +
' 1.514582' +
' 1.384133' +
' 133.57' +
' 146.16' +
' relativeToGround' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const extent = f.get('extent');
expect(extent).to.be.an(Array);
expect(extent).to.have.length(4);
expect(extent[0]).to.be(1.384133);
expect(extent[1]).to.be(43.540908);
expect(extent[2]).to.be(1.514582);
expect(extent[3]).to.be(43.651015);
expect(f.get('altitudeMode')).to.be('relativeToGround');
expect(f.get('minAltitude')).to.be(133.57);
expect(f.get('maxAltitude')).to.be(146.16);
});
it('can read Lod', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' 128' +
' 2048' +
' 0.2' +
' 10.5' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('minLodPixels')).to.be(128);
expect(f.get('maxLodPixels')).to.be(2048);
expect(f.get('minFadeExtent')).to.be(0.2);
expect(f.get('maxFadeExtent')).to.be(10.5);
});
});
describe('extended data', function () {
it('can write ExtendedData with no values', function () {
const feature = new Feature();
feature.set('foo', null);
feature.set('bar', undefined);
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write ExtendedData with values', function () {
const feature = new Feature();
feature.set('foo', 'bar');
feature.set('aNumber', 1000);
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' 1000' +
' ' +
' ' +
' bar' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write ExtendedData pair with displayName and value', function () {
const pair = {
value: 'bar',
displayName: 'display name',
};
const feature = new Feature();
feature.set('foo', pair);
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' bar' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write ExtendedData after Style tag', function () {
const style = new Style({
stroke: new Stroke({
color: '#112233',
width: 2,
}),
});
const feature = new Feature();
feature.set('foo', null);
feature.setStyle([style]);
const features = [feature];
const node = format.writeFeaturesNode(features);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can read ExtendedData', function () {
const text =
'' +
' ' +
' ' +
' ' +
' bar' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getProperties()).to.only.have.keys(['foo', 'geometry']);
expect(f.get('foo')).to.be('bar');
});
it('can read ExtendedData with no values', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 200' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getProperties()).to.only.have.keys([
'foo',
'bar',
'geometry',
]);
expect(f.get('foo')).to.be('200');
expect(f.get('bar')).to.be(undefined);
});
it('can read ExtendedData with displayName instead of name', function () {
const text =
'' +
' ' +
' ' +
' ' +
' foo' +
' bar' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('foo')).to.be('bar');
});
it('can read SchemaData', function () {
const text =
'' +
' ' +
' ' +
' ' +
' London' +
' 60000000' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('capital')).to.be('London');
expect(f.get('population')).to.be('60000000');
});
it('can read ExtendedData with displayName', function () {
const text =
'' +
' ' +
' ' +
' ' +
' capital' +
' London' +
' ' +
' ' +
' Country' +
' United-Kingdom' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('capital')).to.be('London');
expect(f.get('country').value).to.be('United-Kingdom');
expect(f.get('country').displayName).to.be('Country');
});
});
describe('styles', function () {
it('applies the default style if no style is defined', function () {
const text =
'' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getFill().getColor()).to.eql([255, 255, 255, 1]);
expect(style.getImage()).to.be(getDefaultImageStyle());
// FIXME check image style
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
expect(style.getStroke().getColor()).to.eql([255, 255, 255, 1]);
expect(style.getStroke().getWidth()).to.be(1);
});
it("can read a feature's IconStyle using default crossOrigin", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://foo.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.eql('anonymous');
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's IconStyle (and set the crossOrigin option)", function () {
format = new KML({crossOrigin: null});
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://foo.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.be(null);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's IconStyle and apply an iconUrlFunction", function () {
format = new KML({
iconUrlFunction: function (href) {
return href.replace(/^http:/, 'https:');
},
});
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('https://foo.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.eql('anonymous');
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's IconStyle, load the image and reset the scale", function (done) {
format = new KML({
iconUrlFunction: function (href) {
return href.replace('http://foo/', 'spec/ol/data/');
},
});
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = /** @type {Array' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(5);
fs.forEach(function (f) {
expect(f).to.be.an(Feature);
expect(f.getId()).to.be.within(1, 5);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://foo.png').href
);
expect(imageStyle.anchor_).to.be.an(Array);
expect(imageStyle.anchor_).to.have.length(2);
if (f.getId() == 1) {
expect(imageStyle.anchor_[0]).to.be(0.5);
expect(imageStyle.anchor_[1]).to.be(0.5);
expect(imageStyle.anchorOrigin_).to.be(IconOrigin.BOTTOM_LEFT);
expect(imageStyle.anchorXUnits_).to.be(IconAnchorUnits.FRACTION);
expect(imageStyle.anchorYUnits_).to.be(IconAnchorUnits.FRACTION);
} else {
expect(imageStyle.anchor_[0]).to.be(5);
expect(imageStyle.anchor_[1]).to.be(5);
expect(imageStyle.anchorXUnits_).to.be(IconAnchorUnits.PIXELS);
expect(imageStyle.anchorYUnits_).to.be(IconAnchorUnits.PIXELS);
if (f.getId() == 2) {
expect(imageStyle.anchorOrigin_).to.be(IconOrigin.BOTTOM_LEFT);
}
if (f.getId() == 3) {
expect(imageStyle.anchorOrigin_).to.be(IconOrigin.BOTTOM_RIGHT);
}
if (f.getId() == 4) {
expect(imageStyle.anchorOrigin_).to.be(IconOrigin.TOP_LEFT);
}
if (f.getId() == 5) {
expect(imageStyle.anchorOrigin_).to.be(IconOrigin.TOP_RIGHT);
}
}
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
});
it("can read a complex feature's IconStyle", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
imageStyle.iconImage_.size_ = [144, 192];
expect(imageStyle.getSize()).to.eql([48, 48]);
expect(imageStyle.getAnchor()).to.eql([24, 36]);
expect(imageStyle.getOrigin()).to.eql([24, 108]);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getScale()).to.eql(2.0); // 3.0 * 32 / 48
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's IconStyle and set color of image", () => {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle.getColor()).to.eql([0xff, 0, 0, 0xff / 255]);
});
it("can read a feature's LabelStyle", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getImage()).to.be(getDefaultImageStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const textStyle = style.getText();
expect(textStyle).to.be.an(Text);
expect(textStyle.getScale()).to.be(0.25);
const textFillStyle = textStyle.getFill();
expect(textFillStyle).to.be.an(Fill);
expect(textFillStyle.getColor()).to.eql([
0x78,
0x56,
0x34,
0x12 / 255,
]);
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's LineStyle", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getImage()).to.be(getDefaultImageStyle());
const strokeStyle = style.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(strokeStyle.getWidth()).to.be(9);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's PolyStyle", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
const fillStyle = style.getFill();
expect(fillStyle).to.be.an(Fill);
expect(fillStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(style.getImage()).to.be(getDefaultImageStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("can read a feature's LineStyle and PolyStyle", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
const fillStyle = style.getFill();
expect(fillStyle).to.be.an(Fill);
expect(fillStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(style.getImage()).to.be(getDefaultImageStyle());
const strokeStyle = style.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(strokeStyle.getWidth()).to.be(9);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it("disables the fill when fill is '0'", function () {
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(null);
expect(style.getImage()).to.be(getDefaultImageStyle());
const strokeStyle = style.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(strokeStyle.getWidth()).to.be(9);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
const lineString = new LineString([
[1, 2],
[3, 4],
]);
const polygon = new Polygon([
[
[0, 0],
[0, 2],
[2, 2],
[2, 0],
[0, 0],
],
]);
const collection = new GeometryCollection([lineString, polygon]);
f.setGeometry(collection);
const node = format.writeFeaturesNode(fs);
const text1 =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
' ' +
' ' +
' 0,0 0,2 2,2 2,0 0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text1));
});
it("disables the stroke when outline is '0'", function () {
const lineString = new LineString([
[1, 2],
[3, 4],
]);
const polygon = new Polygon([
[
[0, 0],
[0, 2],
[2, 2],
[2, 0],
[0, 0],
],
]);
const lineStringFeature = new Feature(lineString);
const polygonFeature = new Feature(polygon);
const collectionFeature = new Feature(
new GeometryCollection([lineString, polygon])
);
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(2);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getGeometryFunction()(lineStringFeature)).to.be(
lineString
);
expect(style.getGeometryFunction()(polygonFeature)).to.be(undefined);
const gc = style.getGeometryFunction()(collectionFeature);
expect(gc).to.be.an(GeometryCollection);
const gs = gc.getGeometries();
expect(gs).to.be.an(Array);
expect(gs).to.have.length(1);
expect(gs[0]).to.be.an(LineString);
expect(gs[0].getCoordinates()).to.eql(lineString.getCoordinates());
const fillStyle = style.getFill();
expect(fillStyle).to.be.an(Fill);
expect(fillStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(style.getImage()).to.be(getDefaultImageStyle());
const strokeStyle = style.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(strokeStyle.getWidth()).to.be(9);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
const style1 = styleArray[1];
expect(style1).to.be.an(Style);
expect(style1.getGeometryFunction()(lineStringFeature)).to.be(
undefined
);
expect(style1.getGeometryFunction()(polygonFeature)).to.be(polygon);
const gc1 = style1.getGeometryFunction()(collectionFeature);
expect(gc1).to.be.an(GeometryCollection);
const gs1 = gc1.getGeometries();
expect(gs1).to.be.an(Array);
expect(gs1).to.have.length(1);
expect(gs1[0]).to.be.an(Polygon);
expect(gs1[0].getCoordinates()).to.eql(polygon.getCoordinates());
expect(style1.getFill()).to.be(fillStyle);
expect(style1.getStroke()).to.be(null);
expect(style1.getZIndex()).to.be(undefined);
f.setGeometry(collectionFeature.getGeometry());
const node = format.writeFeaturesNode(fs);
const text1 =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
' ' +
' ' +
' 0,0 0,2 2,2 2,0 0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text1));
});
it("disables both fill and stroke when fill and outline are '0'", function () {
const lineString = new LineString([
[1, 2],
[3, 4],
]);
const polygon = new Polygon([
[
[0, 0],
[0, 2],
[2, 2],
[2, 0],
[0, 0],
],
]);
const lineStringFeature = new Feature(lineString);
const polygonFeature = new Feature(polygon);
const collectionFeature = new Feature(
new GeometryCollection([lineString, polygon])
);
const text =
'' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(2);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getGeometryFunction()(lineStringFeature)).to.be(
lineString
);
expect(style.getGeometryFunction()(polygonFeature)).to.be(undefined);
const gc = style.getGeometryFunction()(collectionFeature);
expect(gc).to.be.an(GeometryCollection);
const gs = gc.getGeometries();
expect(gs).to.be.an(Array);
expect(gs).to.have.length(1);
expect(gs[0]).to.be.an(LineString);
expect(gs[0].getCoordinates()).to.eql(lineString.getCoordinates());
expect(style.getFill()).to.be(null);
expect(style.getImage()).to.be(getDefaultImageStyle());
const strokeStyle = style.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
expect(strokeStyle.getWidth()).to.be(9);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
const style1 = styleArray[1];
expect(style1).to.be.an(Style);
expect(style1.getGeometryFunction()(lineStringFeature)).to.be(
undefined
);
expect(style1.getGeometryFunction()(polygonFeature)).to.be(polygon);
const gc1 = style1.getGeometryFunction()(collectionFeature);
expect(gc1).to.be.an(GeometryCollection);
const gs1 = gc1.getGeometries();
expect(gs1).to.be.an(Array);
expect(gs1).to.have.length(1);
expect(gs1[0]).to.be.an(Polygon);
expect(gs1[0].getCoordinates()).to.eql(polygon.getCoordinates());
expect(style1.getFill()).to.be(null);
expect(style1.getStroke()).to.be(null);
expect(style1.getZIndex()).to.be(undefined);
f.setGeometry(collectionFeature.getGeometry());
const node = format.writeFeaturesNode(fs);
const text1 =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,2 3,4' +
' ' +
' ' +
' ' +
' ' +
' 0,0 0,2 2,2 2,0 0,0' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text1));
});
it('can create text style for named point placemarks (including html character codes)', function () {
const text =
'' +
' ' +
' ' +
' ' +
' normal' +
' #sn_ylw-pushpin' +
' ' +
' ' +
' highlight' +
' #sh_ylw-pushpin' +
' ' +
' ' +
' ' +
' Joe's Test' +
' #msn_ylw-pushpin0' +
' ' +
' 1,2' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const style = styleFunction(f, 0);
expect(style).to.be.an(Style);
expect(style.getText().getText()).to.eql("Joe's Test");
});
it("can write an feature's icon style", function () {
const style = new Style({
image: new Icon({
anchor: [0.25, 36],
anchorOrigin: 'top-left',
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
crossOrigin: 'anonymous',
offset: [96, 96],
offsetOrigin: 'top-left',
rotation: 45,
scale: 0.5,
size: [48, 48],
src: 'http://foo.png',
color: 'rgba(255,0,0,1)',
}),
});
const imageStyle = style.getImage();
imageStyle.iconImage_.size_ = [192, 144]; // sprite de 12 images(4*3)
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('does not write styles when writeStyles option is false', function () {
format = new KML({writeStyles: false});
const style = new Style({
image: new Icon({
src: 'http://foo.png',
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('skips image styles that are not icon styles', function () {
const style = new Style({
image: new CircleStyle({
radius: 4,
fill: new Fill({
color: 'rgb(12, 34, 223)',
}),
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it("can write an feature's text style", function () {
const style = new Style({
text: new Text({
scale: 0.5,
text: 'foo',
fill: new Fill({
color: 'rgb(12, 34, 223)',
}),
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' foo' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it("can write an feature's stroke style without fill", function () {
const style = new Style({
stroke: new Stroke({
color: '#112233',
width: 2,
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it("can write an feature's fill style without outline", function () {
const style = new Style({
fill: new Fill({
color: 'rgba(12, 34, 223, 0.7)',
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it("can write an feature's fill style and outline", function () {
const style = new Style({
fill: new Fill({
color: 'rgba(12, 34, 223, 0.7)',
}),
stroke: new Stroke({
color: '#112233',
width: 2,
}),
});
const feature = new Feature();
feature.setStyle([style]);
const node = format.writeFeaturesNode([feature]);
const text =
'' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
it('can write multiple features with Style', function () {
const style = new Style({
fill: new Fill({
color: 'rgba(12, 34, 223, 0.7)',
}),
});
const feature = new Feature();
feature.setStyle(style);
const feature2 = new Feature();
feature2.setStyle(style);
const node = format.writeFeaturesNode([feature, feature2]);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
});
describe('style maps', function () {
it('can read a normal style', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' normal' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s.getFill()).not.to.be(null);
expect(s.getFill().getColor()).to.eql([0, 0, 0, 0]);
});
it('can read a normal IconStyle (and set the crossOrigin option)', function () {
format = new KML({crossOrigin: null});
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' normal' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://bar.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.be(null);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it('ignores highlight styles', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' highlight' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s).to.be(getDefaultStyle());
});
it('uses normal styles instead of highlight styles', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' normal' +
' ' +
' ' +
' ' +
' highlight' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s.getFill()).not.to.be(null);
expect(s.getFill().getColor()).to.eql([0, 0, 0, 0]);
});
it('can read normal styleUrls', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' normal' +
' #foo' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s.getFill()).not.to.be(null);
expect(s.getFill().getColor()).to.eql([0, 0, 0, 0]);
});
it('ignores highlight styleUrls', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' highlight' +
' #foo' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s).to.be(getDefaultStyle());
});
it('can use Styles in StyleMaps before they are defined', function () {
const text =
'' +
' ' +
' ' +
' ' +
' normal' +
' #foo' +
' ' +
' ' +
' ' +
' ' +
' #fooMap' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s.getFill()).not.to.be(null);
expect(s.getFill().getColor()).to.eql([120, 86, 52, 18 / 255]);
});
it('can use Styles in StyleMaps if # is missing', function () {
const text =
'' +
' ' +
' ' +
' ' +
' normal' +
' foo' +
' ' +
' ' +
' ' +
' ' +
' fooMap' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const s = styleArray[0];
expect(s).to.be.an(Style);
expect(s.getFill()).not.to.be(null);
expect(s.getFill().getColor()).to.eql([120, 86, 52, 18 / 255]);
});
it('can use IconStyles in StyleMaps before they are defined (and set the crossOrigin option)', function () {
format = new KML({crossOrigin: null});
const text =
'' +
' ' +
' ' +
' ' +
' normal' +
' #foo' +
' ' +
' ' +
' ' +
' ' +
' #fooMap' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://bar.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.be(null);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
});
describe('shared styles', function () {
it('can apply a shared style to a feature', function () {
const text =
'' +
' ' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
const fillStyle = style.getFill();
expect(fillStyle).to.be.an(Fill);
expect(fillStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
});
it('can apply a shared IconStyle to a feature (and set the crossOrigin option)', function () {
format = new KML({crossOrigin: null});
const text =
'' +
' ' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://bar.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.be(null);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it('can read a shared style from a Folder', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
const fillStyle = style.getFill();
expect(fillStyle).to.be.an(Fill);
expect(fillStyle.getColor()).to.eql([0x78, 0x56, 0x34, 0x12 / 255]);
});
it('can read a shared IconStyle from a Folder (and set the crossOrigin option)', function () {
format = new KML({crossOrigin: null});
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(1);
const style = styleArray[0];
expect(style).to.be.an(Style);
expect(style.getFill()).to.be(getDefaultFillStyle());
expect(style.getStroke()).to.be(getDefaultStrokeStyle());
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(new URL(imageStyle.getSrc()).href).to.eql(
new URL('http://bar.png').href
);
expect(imageStyle.getAnchor()).to.be(null);
expect(imageStyle.getOrigin()).to.be(null);
expect(imageStyle.getRotation()).to.eql(0);
expect(imageStyle.getSize()).to.be(null);
expect(imageStyle.getScale()).to.be(1);
expect(imageStyle.getImage().crossOrigin).to.be(null);
expect(style.getText()).to.be(getDefaultTextStyle());
expect(style.getZIndex()).to.be(undefined);
});
it('can apply a shared style to multiple features', function () {
const text =
'' +
' ' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
' #foo' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(2);
const f1 = fs[0];
expect(f1).to.be.an(Feature);
const styleFunction1 = f1.getStyleFunction();
expect(styleFunction1).not.to.be(undefined);
const styleArray1 = styleFunction1(f1, 0);
expect(styleArray1).to.be.an(Array);
const f2 = fs[1];
expect(f2).to.be.an(Feature);
const styleFunction2 = f2.getStyleFunction();
expect(styleFunction2).not.to.be(undefined);
const styleArray2 = styleFunction2(f2, 0);
expect(styleArray2).to.be.an(Array);
expect(styleArray1).to.be(styleArray2);
});
});
describe('multiple features', function () {
it('returns no features from an empty Document', function () {
const text =
'' +
'';
const fs = format.readFeatures(text);
expect(fs).to.be.empty();
});
it('can read a single feature from a Document', function () {
const text =
'' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can read a single feature from nested Document', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can transform and read a single feature from a Document', function () {
const text =
'' +
' ' +
' ' +
' 1,2,3' +
' ' +
' ' +
'';
const fs = format.readFeatures(text, {
featureProjection: 'EPSG:3857',
});
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(Point);
const expectedPoint = transform([1, 2], 'EPSG:4326', 'EPSG:3857');
expectedPoint.push(3);
expect(g.getCoordinates()).to.eql(expectedPoint);
});
it('can read a multiple features from a Document', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(2);
expect(fs[0]).to.be.an(Feature);
expect(fs[0].getId()).to.be('1');
expect(fs[1]).to.be.an(Feature);
expect(fs[1].getId()).to.be('2');
});
it('returns no features from an empty Folder', function () {
const text =
'' + '';
const fs = format.readFeatures(text);
expect(fs).to.be.empty();
});
it('can read a single feature from a Folder', function () {
const text =
'' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can read a multiple features from a Folder', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(2);
expect(fs[0]).to.be.an(Feature);
expect(fs[0].getId()).to.be('1');
expect(fs[1]).to.be.an(Feature);
expect(fs[1].getId()).to.be('2');
});
it('can read features from Folders nested in Documents', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can read features from Folders nested in Folders', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can read a single feature', function () {
const text =
'' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(1);
expect(fs[0]).to.be.an(Feature);
});
it('can read features at multiple levels', function () {
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(text);
expect(fs).to.have.length(5);
expect(fs[0]).to.be.an(Feature);
expect(fs[0].getId()).to.be('a');
expect(fs[1]).to.be.an(Feature);
expect(fs[1].getId()).to.be('b');
expect(fs[2]).to.be.an(Feature);
expect(fs[2].getId()).to.be('c');
expect(fs[3]).to.be.an(Feature);
expect(fs[3].getId()).to.be('d');
expect(fs[4]).to.be.an(Feature);
expect(fs[4].getId()).to.be('e');
});
it('supports common namespaces', function () {
expect(
format.readFeatures(
'' +
' ' +
''
)
).to.have.length(1);
expect(
format.readFeatures(
'' +
' ' +
''
)
).to.have.length(1);
expect(
format.readFeatures(
'' +
' ' +
''
)
).to.have.length(1);
});
it('ignores unknown namespaces', function () {
expect(
format.readFeatures(
'' +
' ' +
''
)
).to.be.empty();
});
it('can write multiple features', function () {
const feature1 = new Feature();
feature1.setId('1');
const feature2 = new Feature();
feature2.setId('2');
const node = format.writeFeaturesNode([feature1, feature2]);
const text =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(node).to.xmleql(parse(text));
});
});
describe('error handling', function () {
it('should ignore invalid coordinates', function () {
const doc = new DOMParser().parseFromString(
'INVALID',
'application/xml'
);
const node = doc.firstChild;
expect(readFlatCoordinates(node)).to.be(undefined);
});
it('should ignore Points with invalid coordinates', function () {
const kml =
'' +
' ' +
' ' +
' INVALID COORDINATES' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getGeometry()).to.be(null);
});
it('should ignore LineStrings with invalid coordinates', function () {
const kml =
'' +
' ' +
' ' +
' INVALID COORDINATES' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getGeometry()).to.be(null);
});
it('should ignore Polygons with no rings', function () {
const kml =
'' +
' ' +
' ' +
' INVALID COORDINATES' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getGeometry()).to.be(null);
});
it('should ignore Polygons with no outer ring', function () {
const kml =
'' +
' ' +
' ' +
' ' +
' ' +
' 1,2,3 4,5,6 7,8,9' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.getGeometry()).to.be(null);
});
it('should ignore geometries with invalid coordinates', function () {
const kml =
'' +
' ' +
' ' +
' ' +
' INVALID COORDINATES' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
const g = f.getGeometry();
expect(g).to.be.an(GeometryCollection);
expect(g.getGeometries()).to.be.empty();
});
it('should ignore invalid booleans', function () {
const kml =
'' +
' ' +
' foo' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(1);
const f = fs[0];
expect(f).to.be.an(Feature);
expect(f.get('visibility')).to.be(undefined);
});
it('parse all valid features in a Folder, without error', function () {
const kml =
'' +
' ' +
' ' +
' ' +
' ' +
' foo' +
' ' +
' ' +
' ' +
' ' +
'';
const fs = format.readFeatures(kml);
expect(fs).to.be.an(Array);
expect(fs).to.have.length(5);
expect(fs[0]).to.be.an(Feature);
expect(fs[0].getId()).to.be('a');
expect(fs[1]).to.be.an(Feature);
expect(fs[1].getId()).to.be('b');
expect(fs[2]).to.be.an(Feature);
expect(fs[2].getId()).to.be('c');
expect(fs[3]).to.be.an(Feature);
expect(fs[3].getId()).to.be('d');
expect(fs[4]).to.be.an(Feature);
expect(fs[4].getId()).to.be('e');
});
});
});
describe('when parsing states.kml', function () {
let features;
before(function (done) {
afterLoadText('spec/ol/format/kml/states.kml', function (xml) {
try {
features = format.readFeatures(xml);
} catch (e) {
done(e);
}
done();
});
});
it('creates 50 features', function () {
expect(features).to.have.length(50);
});
it('creates features with heterogeneous geometry collections', function () {
// FIXME decide if we should instead create features with multiple geoms
const feature = features[0];
expect(feature).to.be.an(Feature);
const geometry = feature.getGeometry();
expect(geometry).to.be.an(GeometryCollection);
});
it('creates a Point and a MultiPolygon for Alaska', function () {
const alaska = find(features, function (feature) {
return feature.get('name') === 'Alaska';
});
expect(alaska).to.be.an(Feature);
const geometry = alaska.getGeometry();
expect(geometry).to.be.an(GeometryCollection);
const components = geometry.getGeometries();
expect(components).to.have.length(2);
expect(components[0]).to.be.an(Point);
expect(components[1]).to.be.an(MultiPolygon);
});
it('reads style and icon', function () {
const f = features[0];
const styleFunction = f.getStyleFunction();
expect(styleFunction).not.to.be(undefined);
const styleArray = styleFunction(f, 0);
expect(styleArray).to.be.an(Array);
expect(styleArray).to.have.length(2);
const style = styleArray[0];
expect(style).to.be.an(Style);
const gc = style.getGeometryFunction()(f);
expect(gc).to.be.an(GeometryCollection);
const gs = gc.getGeometries();
expect(gs).to.be.an(Array);
expect(gs).to.have.length(1);
expect(gs[0]).to.be.an(Point);
expect(gs[0].getCoordinates()).to.eql(
f.getGeometry().getGeometries()[0].getCoordinates()
);
const imageStyle = style.getImage();
expect(imageStyle).to.be.an(Icon);
expect(imageStyle.getScale()).to.eql(0.4);
expect(imageStyle.getSrc()).to.eql(
'http://maps.google.com/mapfiles/kml/shapes/star.png'
);
const textStyle = style.getText();
expect(textStyle).to.be.an(Text);
const textFillStyle = textStyle.getFill();
expect(textFillStyle).to.be.an(Fill);
expect(textFillStyle.getColor()).to.eql([0xff, 0xff, 0x00, 0x99 / 255]);
expect(textStyle.getText()).to.eql(f.get('name'));
const style1 = styleArray[1];
expect(style1).to.be.an(Style);
expect(style1.getGeometryFunction()(f)).to.be(f.getGeometry());
expect(style1.getFill()).to.be(null);
expect(style1.getImage()).to.be(null);
const strokeStyle = style1.getStroke();
expect(strokeStyle).to.be.an(Stroke);
expect(strokeStyle.getColor()).to.eql([0xff, 0x00, 0xff, 0xff / 255]);
expect(strokeStyle.getWidth()).to.be(2);
expect(style1.getText()).to.be(null);
});
});
describe('#JSONExport', function () {
let features;
before(function (done) {
afterLoadText('spec/ol/format/kml/style.kml', function (xml) {
try {
features = format.readFeatures(xml);
} catch (e) {
done(e);
}
done();
});
});
it('feature must not have a properties property', function () {
const geojsonFormat = new GeoJSON();
features.forEach(function (feature) {
const geojsonFeature = geojsonFormat.writeFeatureObject(feature);
expect(geojsonFeature.properties).to.be(null);
JSON.stringify(geojsonFeature);
});
});
});
describe('#readName', function () {
it('returns undefined if there is no name', function () {
const kml =
'' +
' ' +
' ' +
' ' +
' ' +
' ' +
'';
expect(format.readName(kml)).to.be(undefined);
});
it('returns the name of the first Document', function () {
const kml =
'' +
' ' +
' Document name' +
' ' +
'';
expect(format.readName(kml)).to.be('Document name');
});
it('returns the name of the first Folder', function () {
const kml =
'' +
' ' +
' Folder name' +
' ' +
'';
expect(format.readName(kml)).to.be('Folder name');
});
it('returns the name of the first Placemark', function () {
const kml =
'' +
' ' +
' Placemark name' +
' ' +
'';
expect(format.readName(kml)).to.be('Placemark name');
});
it('searches breadth-first', function () {
const kml =
'' +
' ' +
' ' +
' Placemark name' +
' ' +
' Document name' +
' ' +
'';
expect(format.readName(kml)).to.be('Document name');
});
});
describe('#readNetworkLinks', function () {
it('returns empty array if no network links found', function () {
const text =
'' +
' ' +
' ' +
'';
const nl = format.readNetworkLinks(text);
expect(nl).to.have.length(0);
});
it('returns an array of network links', function () {
const text =
'' +
' ' +
' ' +
' bar' +
' ' +
' bar/bar.kml' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' http://foo.com/foo.kml' +
' ' +
' ' +
' ' +
'';
const nl = format.readNetworkLinks(text);
expect(nl).to.have.length(2);
expect(nl[0].name).to.be('bar');
expect(nl[0].href.replace(window.location.origin, '')).to.be(
'/bar/bar.kml'
);
expect(nl[1].href).to.be('http://foo.com/foo.kml');
});
});
describe('#readNetworkLinksFile', function () {
let nl;
before(function (done) {
afterLoadText('spec/ol/format/kml/networklinks.kml', function (xml) {
try {
nl = format.readNetworkLinks(xml);
} catch (e) {
done(e);
}
done();
});
});
it('returns an array of network links', function () {
expect(nl).to.have.length(2);
expect(nl[0].name).to.be('bar');
expect(/\/bar\/bar\.kml$/.test(nl[0].href)).to.be.ok();
expect(nl[1].href).to.be('http://foo.com/foo.kml');
});
});
describe('#readRegion', function () {
it('returns an array of regions', function () {
const text =
'' +
' ' +
' ' +
' ' +
' 0' +
' -90' +
' 0' +
' -180' +
' 0' +
' 4000' +
' clampToGround' +
' ' +
' ' +
' 0' +
' -1' +
' 0' +
' 0' +
' ' +
' ' +
' ' +
' ' +
' ' +
' ' +
' 90' +
' 0' +
' 180' +
' 0' +
' 0' +
' 0' +
' clampToGround' +
' ' +
' ' +
' 0' +
' -1' +
' 0' +
' 0' +
' ' +
' ' +
' ' +
'';
const nl = format.readRegion(text);
expect(nl).to.have.length(2);
expect(nl[0].extent).to.eql([-180, -90, 0, 0]);
expect(nl[0].minAltitude).to.be(0);
expect(nl[0].maxAltitude).to.be(4000);
expect(nl[0].altitudeMode).to.be('clampToGround');
expect(nl[0].minLodPixels).to.be(0);
expect(nl[0].maxLodPixels).to.be(-1);
expect(nl[0].minFadeExtent).to.be(0);
expect(nl[0].maxFadeExtent).to.be(0);
expect(nl[1].extent).to.eql([0, 0, 180, 90]);
});
});
});
});