1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024 |
- import Cartesian2 from "../Core/Cartesian2.js";
- import Cartesian3 from "../Core/Cartesian3.js";
- import ClockRange from "../Core/ClockRange.js";
- import ClockStep from "../Core/ClockStep.js";
- import Color from "../Core/Color.js";
- import createGuid from "../Core/createGuid.js";
- import defaultValue from "../Core/defaultValue.js";
- import defer from "../Core/defer.js";
- import defined from "../Core/defined.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import Event from "../Core/Event.js";
- import Iso8601 from "../Core/Iso8601.js";
- import JulianDate from "../Core/JulianDate.js";
- import NearFarScalar from "../Core/NearFarScalar.js";
- import PinBuilder from "../Core/PinBuilder.js";
- import Resource from "../Core/Resource.js";
- import RuntimeError from "../Core/RuntimeError.js";
- import TimeInterval from "../Core/TimeInterval.js";
- import TimeIntervalCollection from "../Core/TimeIntervalCollection.js";
- import HeightReference from "../Scene/HeightReference.js";
- import HorizontalOrigin from "../Scene/HorizontalOrigin.js";
- import LabelStyle from "../Scene/LabelStyle.js";
- import VerticalOrigin from "../Scene/VerticalOrigin.js";
- import Autolinker from "../ThirdParty/Autolinker.js";
- import BillboardGraphics from "./BillboardGraphics.js";
- import ConstantProperty from "./ConstantProperty.js";
- import DataSource from "./DataSource.js";
- import DataSourceClock from "./DataSourceClock.js";
- import EntityCluster from "./EntityCluster.js";
- import EntityCollection from "./EntityCollection.js";
- import LabelGraphics from "./LabelGraphics.js";
- import PolylineGraphics from "./PolylineGraphics.js";
- import PolylineOutlineMaterialProperty from "./PolylineOutlineMaterialProperty.js";
- import SampledPositionProperty from "./SampledPositionProperty.js";
- let parser;
- if (typeof DOMParser !== "undefined") {
- parser = new DOMParser();
- }
- const autolinker = new Autolinker({
- stripPrefix: false,
- email: false,
- replaceFn: function (linker, match) {
- if (!match.protocolUrlMatch) {
- // Prevent matching of non-explicit urls.
- // i.e. foo.id won't match but http://foo.id will
- return false;
- }
- },
- });
- const BILLBOARD_SIZE = 32;
- const BILLBOARD_NEAR_DISTANCE = 2414016;
- const BILLBOARD_NEAR_RATIO = 1.0;
- const BILLBOARD_FAR_DISTANCE = 1.6093e7;
- const BILLBOARD_FAR_RATIO = 0.1;
- const gpxNamespaces = [null, undefined, "http://www.topografix.com/GPX/1/1"];
- const namespaces = {
- gpx: gpxNamespaces,
- };
- function readBlobAsText(blob) {
- const deferred = defer();
- const reader = new FileReader();
- reader.addEventListener("load", function () {
- deferred.resolve(reader.result);
- });
- reader.addEventListener("error", function () {
- deferred.reject(reader.error);
- });
- reader.readAsText(blob);
- return deferred.promise;
- }
- function getOrCreateEntity(node, entityCollection) {
- let id = queryStringAttribute(node, "id");
- id = defined(id) ? id : createGuid();
- const entity = entityCollection.getOrCreateEntity(id);
- return entity;
- }
- function readCoordinateFromNode(node) {
- const longitude = queryNumericAttribute(node, "lon");
- const latitude = queryNumericAttribute(node, "lat");
- const elevation = queryNumericValue(node, "ele", namespaces.gpx);
- return Cartesian3.fromDegrees(longitude, latitude, elevation);
- }
- function queryNumericAttribute(node, attributeName) {
- if (!defined(node)) {
- return undefined;
- }
- const value = node.getAttribute(attributeName);
- if (value !== null) {
- const result = parseFloat(value);
- return !isNaN(result) ? result : undefined;
- }
- return undefined;
- }
- function queryStringAttribute(node, attributeName) {
- if (!defined(node)) {
- return undefined;
- }
- const value = node.getAttribute(attributeName);
- return value !== null ? value : undefined;
- }
- function queryFirstNode(node, tagName, namespace) {
- if (!defined(node)) {
- return undefined;
- }
- const childNodes = node.childNodes;
- const length = childNodes.length;
- for (let q = 0; q < length; q++) {
- const child = childNodes[q];
- if (
- child.localName === tagName &&
- namespace.indexOf(child.namespaceURI) !== -1
- ) {
- return child;
- }
- }
- return undefined;
- }
- function queryNodes(node, tagName, namespace) {
- if (!defined(node)) {
- return undefined;
- }
- const result = [];
- const childNodes = node.getElementsByTagName(tagName);
- const length = childNodes.length;
- for (let q = 0; q < length; q++) {
- const child = childNodes[q];
- if (
- child.localName === tagName &&
- namespace.indexOf(child.namespaceURI) !== -1
- ) {
- result.push(child);
- }
- }
- return result;
- }
- function queryNumericValue(node, tagName, namespace) {
- const resultNode = queryFirstNode(node, tagName, namespace);
- if (defined(resultNode)) {
- const result = parseFloat(resultNode.textContent);
- return !isNaN(result) ? result : undefined;
- }
- return undefined;
- }
- function queryStringValue(node, tagName, namespace) {
- const result = queryFirstNode(node, tagName, namespace);
- if (defined(result)) {
- return result.textContent.trim();
- }
- return undefined;
- }
- function createDefaultBillboard(image) {
- const billboard = new BillboardGraphics();
- billboard.width = BILLBOARD_SIZE;
- billboard.height = BILLBOARD_SIZE;
- billboard.scaleByDistance = new NearFarScalar(
- BILLBOARD_NEAR_DISTANCE,
- BILLBOARD_NEAR_RATIO,
- BILLBOARD_FAR_DISTANCE,
- BILLBOARD_FAR_RATIO
- );
- billboard.pixelOffsetScaleByDistance = new NearFarScalar(
- BILLBOARD_NEAR_DISTANCE,
- BILLBOARD_NEAR_RATIO,
- BILLBOARD_FAR_DISTANCE,
- BILLBOARD_FAR_RATIO
- );
- billboard.verticalOrigin = new ConstantProperty(VerticalOrigin.BOTTOM);
- billboard.image = image;
- return billboard;
- }
- function createDefaultLabel() {
- const label = new LabelGraphics();
- label.translucencyByDistance = new NearFarScalar(3000000, 1.0, 5000000, 0.0);
- label.pixelOffset = new Cartesian2(17, 0);
- label.horizontalOrigin = HorizontalOrigin.LEFT;
- label.font = "16px sans-serif";
- label.style = LabelStyle.FILL_AND_OUTLINE;
- return label;
- }
- function createDefaultPolyline(color) {
- const polyline = new PolylineGraphics();
- polyline.width = 4;
- polyline.material = new PolylineOutlineMaterialProperty();
- polyline.material.color = defined(color) ? color : Color.RED;
- polyline.material.outlineWidth = 2;
- polyline.material.outlineColor = Color.BLACK;
- return polyline;
- }
- // This is a list of the Optional Description Information:
- // <cmt> GPS comment of the waypoint
- // <desc> Descriptive description of the waypoint
- // <src> Source of the waypoint data
- // <type> Type (category) of waypoint
- const descriptiveInfoTypes = {
- time: {
- text: "Time",
- tag: "time",
- },
- comment: {
- text: "Comment",
- tag: "cmt",
- },
- description: {
- text: "Description",
- tag: "desc",
- },
- source: {
- text: "Source",
- tag: "src",
- },
- number: {
- text: "GPS track/route number",
- tag: "number",
- },
- type: {
- text: "Type",
- tag: "type",
- },
- };
- let scratchDiv;
- if (typeof document !== "undefined") {
- scratchDiv = document.createElement("div");
- }
- function processDescription(node, entity) {
- let i;
- let text = "";
- const infoTypeNames = Object.keys(descriptiveInfoTypes);
- const length = infoTypeNames.length;
- for (i = 0; i < length; i++) {
- const infoTypeName = infoTypeNames[i];
- const infoType = descriptiveInfoTypes[infoTypeName];
- infoType.value = defaultValue(
- queryStringValue(node, infoType.tag, namespaces.gpx),
- ""
- );
- if (defined(infoType.value) && infoType.value !== "") {
- text = `${text}<p>${infoType.text}: ${infoType.value}</p>`;
- }
- }
- if (!defined(text) || text === "") {
- // No description
- return;
- }
- // Turns non-explicit links into clickable links.
- text = autolinker.link(text);
- // Use a temporary div to manipulate the links
- // so that they open in a new window.
- scratchDiv.innerHTML = text;
- const links = scratchDiv.querySelectorAll("a");
- for (i = 0; i < links.length; i++) {
- links[i].setAttribute("target", "_blank");
- }
- const background = Color.WHITE;
- const foreground = Color.BLACK;
- let tmp = '<div class="cesium-infoBox-description-lighter" style="';
- tmp += "overflow:auto;";
- tmp += "word-wrap:break-word;";
- tmp += `background-color:${background.toCssColorString()};`;
- tmp += `color:${foreground.toCssColorString()};`;
- tmp += '">';
- tmp += `${scratchDiv.innerHTML}</div>`;
- scratchDiv.innerHTML = "";
- // return the final HTML as the description.
- return tmp;
- }
- function processWpt(dataSource, geometryNode, entityCollection, options) {
- const position = readCoordinateFromNode(geometryNode);
- const entity = getOrCreateEntity(geometryNode, entityCollection);
- entity.position = position;
- // Get billboard image
- const image = defined(options.waypointImage)
- ? options.waypointImage
- : dataSource._pinBuilder.fromMakiIconId(
- "marker",
- Color.RED,
- BILLBOARD_SIZE
- );
- entity.billboard = createDefaultBillboard(image);
- const name = queryStringValue(geometryNode, "name", namespaces.gpx);
- entity.name = name;
- entity.label = createDefaultLabel();
- entity.label.text = name;
- entity.description = processDescription(geometryNode, entity);
- if (options.clampToGround) {
- entity.billboard.heightReference = HeightReference.CLAMP_TO_GROUND;
- entity.label.heightReference = HeightReference.CLAMP_TO_GROUND;
- }
- }
- // rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination
- function processRte(dataSource, geometryNode, entityCollection, options) {
- const entity = getOrCreateEntity(geometryNode, entityCollection);
- entity.description = processDescription(geometryNode, entity);
- // a list of waypoint
- const routePoints = queryNodes(geometryNode, "rtept", namespaces.gpx);
- const coordinateTuples = new Array(routePoints.length);
- for (let i = 0; i < routePoints.length; i++) {
- processWpt(dataSource, routePoints[i], entityCollection, options);
- coordinateTuples[i] = readCoordinateFromNode(routePoints[i]);
- }
- entity.polyline = createDefaultPolyline(options.routeColor);
- if (options.clampToGround) {
- entity.polyline.clampToGround = true;
- }
- entity.polyline.positions = coordinateTuples;
- }
- // trk represents a track - an ordered list of points describing a path.
- function processTrk(dataSource, geometryNode, entityCollection, options) {
- const entity = getOrCreateEntity(geometryNode, entityCollection);
- entity.description = processDescription(geometryNode, entity);
- const trackSegs = queryNodes(geometryNode, "trkseg", namespaces.gpx);
- let positions = [];
- let times = [];
- let trackSegInfo;
- let isTimeDynamic = true;
- const property = new SampledPositionProperty();
- for (let i = 0; i < trackSegs.length; i++) {
- trackSegInfo = processTrkSeg(trackSegs[i]);
- positions = positions.concat(trackSegInfo.positions);
- if (trackSegInfo.times.length > 0) {
- times = times.concat(trackSegInfo.times);
- property.addSamples(times, positions);
- // if one track segment is non dynamic the whole track must also be
- isTimeDynamic = isTimeDynamic && true;
- } else {
- isTimeDynamic = false;
- }
- }
- if (isTimeDynamic) {
- // Assign billboard image
- const image = defined(options.waypointImage)
- ? options.waypointImage
- : dataSource._pinBuilder.fromMakiIconId(
- "marker",
- Color.RED,
- BILLBOARD_SIZE
- );
- entity.billboard = createDefaultBillboard(image);
- entity.position = property;
- if (options.clampToGround) {
- entity.billboard.heightReference = HeightReference.CLAMP_TO_GROUND;
- }
- entity.availability = new TimeIntervalCollection();
- entity.availability.addInterval(
- new TimeInterval({
- start: times[0],
- stop: times[times.length - 1],
- })
- );
- }
- entity.polyline = createDefaultPolyline(options.trackColor);
- entity.polyline.positions = positions;
- if (options.clampToGround) {
- entity.polyline.clampToGround = true;
- }
- }
- function processTrkSeg(node) {
- const result = {
- positions: [],
- times: [],
- };
- const trackPoints = queryNodes(node, "trkpt", namespaces.gpx);
- let time;
- for (let i = 0; i < trackPoints.length; i++) {
- const position = readCoordinateFromNode(trackPoints[i]);
- result.positions.push(position);
- time = queryStringValue(trackPoints[i], "time", namespaces.gpx);
- if (defined(time)) {
- result.times.push(JulianDate.fromIso8601(time));
- }
- }
- return result;
- }
- // Processes a metadataType node and returns a metadata object
- // {@link http://www.topografix.com/gpx/1/1/#type_metadataType|GPX Schema}
- function processMetadata(node) {
- const metadataNode = queryFirstNode(node, "metadata", namespaces.gpx);
- if (defined(metadataNode)) {
- const metadata = {
- name: queryStringValue(metadataNode, "name", namespaces.gpx),
- desc: queryStringValue(metadataNode, "desc", namespaces.gpx),
- author: getPerson(metadataNode),
- copyright: getCopyright(metadataNode),
- link: getLink(metadataNode),
- time: queryStringValue(metadataNode, "time", namespaces.gpx),
- keywords: queryStringValue(metadataNode, "keywords", namespaces.gpx),
- bounds: getBounds(metadataNode),
- };
- if (
- defined(metadata.name) ||
- defined(metadata.desc) ||
- defined(metadata.author) ||
- defined(metadata.copyright) ||
- defined(metadata.link) ||
- defined(metadata.time) ||
- defined(metadata.keywords) ||
- defined(metadata.bounds)
- ) {
- return metadata;
- }
- }
- return undefined;
- }
- // Receives a XML node and returns a personType object, refer to
- // {@link http://www.topografix.com/gpx/1/1/#type_personType|GPX Schema}
- function getPerson(node) {
- const personNode = queryFirstNode(node, "author", namespaces.gpx);
- if (defined(personNode)) {
- const person = {
- name: queryStringValue(personNode, "name", namespaces.gpx),
- email: getEmail(personNode),
- link: getLink(personNode),
- };
- if (defined(person.name) || defined(person.email) || defined(person.link)) {
- return person;
- }
- }
- return undefined;
- }
- // Receives a XML node and returns an email address (from emailType), refer to
- // {@link http://www.topografix.com/gpx/1/1/#type_emailType|GPX Schema}
- function getEmail(node) {
- const emailNode = queryFirstNode(node, "email", namespaces.gpx);
- if (defined(emailNode)) {
- const id = queryStringValue(emailNode, "id", namespaces.gpx);
- const domain = queryStringValue(emailNode, "domain", namespaces.gpx);
- return `${id}@${domain}`;
- }
- return undefined;
- }
- // Receives a XML node and returns a linkType object, refer to
- // {@link http://www.topografix.com/gpx/1/1/#type_linkType|GPX Schema}
- function getLink(node) {
- const linkNode = queryFirstNode(node, "link", namespaces.gpx);
- if (defined(linkNode)) {
- const link = {
- href: queryStringAttribute(linkNode, "href"),
- text: queryStringValue(linkNode, "text", namespaces.gpx),
- mimeType: queryStringValue(linkNode, "type", namespaces.gpx),
- };
- if (defined(link.href) || defined(link.text) || defined(link.mimeType)) {
- return link;
- }
- }
- return undefined;
- }
- // Receives a XML node and returns a copyrightType object, refer to
- // {@link http://www.topografix.com/gpx/1/1/#type_copyrightType|GPX Schema}
- function getCopyright(node) {
- const copyrightNode = queryFirstNode(node, "copyright", namespaces.gpx);
- if (defined(copyrightNode)) {
- const copyright = {
- author: queryStringAttribute(copyrightNode, "author"),
- year: queryStringValue(copyrightNode, "year", namespaces.gpx),
- license: queryStringValue(copyrightNode, "license", namespaces.gpx),
- };
- if (
- defined(copyright.author) ||
- defined(copyright.year) ||
- defined(copyright.license)
- ) {
- return copyright;
- }
- }
- return undefined;
- }
- // Receives a XML node and returns a boundsType object, refer to
- // {@link http://www.topografix.com/gpx/1/1/#type_boundsType|GPX Schema}
- function getBounds(node) {
- const boundsNode = queryFirstNode(node, "bounds", namespaces.gpx);
- if (defined(boundsNode)) {
- const bounds = {
- minLat: queryNumericValue(boundsNode, "minlat", namespaces.gpx),
- maxLat: queryNumericValue(boundsNode, "maxlat", namespaces.gpx),
- minLon: queryNumericValue(boundsNode, "minlon", namespaces.gpx),
- maxLon: queryNumericValue(boundsNode, "maxlon", namespaces.gpx),
- };
- if (
- defined(bounds.minLat) ||
- defined(bounds.maxLat) ||
- defined(bounds.minLon) ||
- defined(bounds.maxLon)
- ) {
- return bounds;
- }
- }
- return undefined;
- }
- const complexTypes = {
- wpt: processWpt,
- rte: processRte,
- trk: processTrk,
- };
- function processGpx(dataSource, node, entityCollection, options) {
- const complexTypeNames = Object.keys(complexTypes);
- const complexTypeNamesLength = complexTypeNames.length;
- for (let i = 0; i < complexTypeNamesLength; i++) {
- const typeName = complexTypeNames[i];
- const processComplexTypeNode = complexTypes[typeName];
- const childNodes = node.childNodes;
- const length = childNodes.length;
- for (let q = 0; q < length; q++) {
- const child = childNodes[q];
- if (
- child.localName === typeName &&
- namespaces.gpx.indexOf(child.namespaceURI) !== -1
- ) {
- processComplexTypeNode(dataSource, child, entityCollection, options);
- }
- }
- }
- }
- function loadGpx(dataSource, gpx, options) {
- const entityCollection = dataSource._entityCollection;
- entityCollection.removeAll();
- const element = gpx.documentElement;
- const version = queryStringAttribute(element, "version");
- const creator = queryStringAttribute(element, "creator");
- let name;
- const metadata = processMetadata(element);
- if (defined(metadata)) {
- name = metadata.name;
- }
- if (element.localName === "gpx") {
- processGpx(dataSource, element, entityCollection, options);
- } else {
- console.log(`GPX - Unsupported node: ${element.localName}`);
- }
- let clock;
- const availability = entityCollection.computeAvailability();
- let start = availability.start;
- let stop = availability.stop;
- const isMinStart = JulianDate.equals(start, Iso8601.MINIMUM_VALUE);
- const isMaxStop = JulianDate.equals(stop, Iso8601.MAXIMUM_VALUE);
- if (!isMinStart || !isMaxStop) {
- let date;
- // If start is min time just start at midnight this morning, local time
- if (isMinStart) {
- date = new Date();
- date.setHours(0, 0, 0, 0);
- start = JulianDate.fromDate(date);
- }
- // If stop is max value just stop at midnight tonight, local time
- if (isMaxStop) {
- date = new Date();
- date.setHours(24, 0, 0, 0);
- stop = JulianDate.fromDate(date);
- }
- clock = new DataSourceClock();
- clock.startTime = start;
- clock.stopTime = stop;
- clock.currentTime = JulianDate.clone(start);
- clock.clockRange = ClockRange.LOOP_STOP;
- clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
- clock.multiplier = Math.round(
- Math.min(
- Math.max(JulianDate.secondsDifference(stop, start) / 60, 1),
- 3.15569e7
- )
- );
- }
- let changed = false;
- if (dataSource._name !== name) {
- dataSource._name = name;
- changed = true;
- }
- if (dataSource._creator !== creator) {
- dataSource._creator = creator;
- changed = true;
- }
- if (metadataChanged(dataSource._metadata, metadata)) {
- dataSource._metadata = metadata;
- changed = true;
- }
- if (dataSource._version !== version) {
- dataSource._version = version;
- changed = true;
- }
- if (clock !== dataSource._clock) {
- changed = true;
- dataSource._clock = clock;
- }
- if (changed) {
- dataSource._changed.raiseEvent(dataSource);
- }
- DataSource.setLoading(dataSource, false);
- return dataSource;
- }
- function metadataChanged(old, current) {
- if (!defined(old) && !defined(current)) {
- return false;
- } else if (defined(old) && defined(current)) {
- if (
- old.name !== current.name ||
- old.dec !== current.desc ||
- old.src !== current.src ||
- old.author !== current.author ||
- old.copyright !== current.copyright ||
- old.link !== current.link ||
- old.time !== current.time ||
- old.bounds !== current.bounds
- ) {
- return true;
- }
- return false;
- }
- return true;
- }
- function load(dataSource, entityCollection, data, options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- let promise = data;
- if (typeof data === "string" || data instanceof Resource) {
- data = Resource.createIfNeeded(data);
- promise = data.fetchBlob();
- // Add resource credits to our list of credits to display
- const resourceCredits = dataSource._resourceCredits;
- const credits = data.credits;
- if (defined(credits)) {
- const length = credits.length;
- for (let i = 0; i < length; i++) {
- resourceCredits.push(credits[i]);
- }
- }
- }
- return Promise.resolve(promise)
- .then(function (dataToLoad) {
- if (dataToLoad instanceof Blob) {
- return readBlobAsText(dataToLoad).then(function (text) {
- // There's no official way to validate if a parse was successful.
- // The following check detects the error on various browsers.
- // IE raises an exception
- let gpx;
- let error;
- try {
- gpx = parser.parseFromString(text, "application/xml");
- } catch (e) {
- error = e.toString();
- }
- // The parse succeeds on Chrome and Firefox, but the error
- // handling is different in each.
- if (
- defined(error) ||
- gpx.body ||
- gpx.documentElement.tagName === "parsererror"
- ) {
- // Firefox has error information as the firstChild nodeValue.
- let msg = defined(error)
- ? error
- : gpx.documentElement.firstChild.nodeValue;
- // Chrome has it in the body text.
- if (!msg) {
- msg = gpx.body.innerText;
- }
- // Return the error
- throw new RuntimeError(msg);
- }
- return loadGpx(dataSource, gpx, options);
- });
- }
- return loadGpx(dataSource, dataToLoad, options);
- })
- .catch(function (error) {
- dataSource._error.raiseEvent(dataSource, error);
- console.log(error);
- return Promise.reject(error);
- });
- }
- /**
- * A {@link DataSource} which processes the GPS Exchange Format (GPX).
- *
- * @alias GpxDataSource
- * @constructor
- *
- * @see {@link http://www.topografix.com/gpx.asp|Topografix GPX Standard}
- * @see {@link http://www.topografix.com/gpx/1/1/|Topografix GPX Documentation}
- *
- * @demo {@link http://sandcastle.cesium.com/index.html?src=GPX.html}
- *
- * @example
- * const viewer = new Cesium.Viewer('cesiumContainer');
- * viewer.dataSources.add(Cesium.GpxDataSource.load('../../SampleData/track.gpx'));
- */
- function GpxDataSource() {
- this._changed = new Event();
- this._error = new Event();
- this._loading = new Event();
- this._clock = undefined;
- this._entityCollection = new EntityCollection();
- this._entityCluster = new EntityCluster();
- this._name = undefined;
- this._version = undefined;
- this._creator = undefined;
- this._metadata = undefined;
- this._isLoading = false;
- this._pinBuilder = new PinBuilder();
- }
- /**
- * Creates a Promise to a new instance loaded with the provided GPX data.
- *
- * @param {String|Document|Blob} data A url, parsed GPX document, or Blob containing binary GPX data.
- * @param {Object} [options] An object with the following properties:
- * @param {Boolean} [options.clampToGround] True if the symbols should be rendered at the same height as the terrain
- * @param {String} [options.waypointImage] Image to use for waypoint billboards.
- * @param {String} [options.trackImage] Image to use for track billboards.
- * @param {String} [options.trackColor] Color to use for track lines.
- * @param {String} [options.routeColor] Color to use for route lines.
- * @returns {Promise.<GpxDataSource>} A promise that will resolve to a new GpxDataSource instance once the gpx is loaded.
- */
- GpxDataSource.load = function (data, options) {
- return new GpxDataSource().load(data, options);
- };
- Object.defineProperties(GpxDataSource.prototype, {
- /**
- * Gets a human-readable name for this instance.
- * This will be automatically be set to the GPX document name on load.
- * @memberof GpxDataSource.prototype
- * @type {String}
- */
- name: {
- get: function () {
- return this._name;
- },
- },
- /**
- * Gets the version of the GPX Schema in use.
- * @memberof GpxDataSource.prototype
- * @type {String}
- */
- version: {
- get: function () {
- return this._version;
- },
- },
- /**
- * Gets the creator of the GPX document.
- * @memberof GpxDataSource.prototype
- * @type {String}
- */
- creator: {
- get: function () {
- return this._creator;
- },
- },
- /**
- * Gets an object containing metadata about the GPX file.
- * @memberof GpxDataSource.prototype
- * @type {Object}
- */
- metadata: {
- get: function () {
- return this._metadata;
- },
- },
- /**
- * Gets the clock settings defined by the loaded GPX. This represents the total
- * availability interval for all time-dynamic data. If the GPX does not contain
- * time-dynamic data, this value is undefined.
- * @memberof GpxDataSource.prototype
- * @type {DataSourceClock}
- */
- clock: {
- get: function () {
- return this._clock;
- },
- },
- /**
- * Gets the collection of {@link Entity} instances.
- * @memberof GpxDataSource.prototype
- * @type {EntityCollection}
- */
- entities: {
- get: function () {
- return this._entityCollection;
- },
- },
- /**
- * Gets a value indicating if the data source is currently loading data.
- * @memberof GpxDataSource.prototype
- * @type {Boolean}
- */
- isLoading: {
- get: function () {
- return this._isLoading;
- },
- },
- /**
- * Gets an event that will be raised when the underlying data changes.
- * @memberof GpxDataSource.prototype
- * @type {Event}
- */
- changedEvent: {
- get: function () {
- return this._changed;
- },
- },
- /**
- * Gets an event that will be raised if an error is encountered during processing.
- * @memberof GpxDataSource.prototype
- * @type {Event}
- */
- errorEvent: {
- get: function () {
- return this._error;
- },
- },
- /**
- * Gets an event that will be raised when the data source either starts or stops loading.
- * @memberof GpxDataSource.prototype
- * @type {Event}
- */
- loadingEvent: {
- get: function () {
- return this._loading;
- },
- },
- /**
- * Gets whether or not this data source should be displayed.
- * @memberof GpxDataSource.prototype
- * @type {Boolean}
- */
- show: {
- get: function () {
- return this._entityCollection.show;
- },
- set: function (value) {
- this._entityCollection.show = value;
- },
- },
- /**
- * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
- *
- * @memberof GpxDataSource.prototype
- * @type {EntityCluster}
- */
- clustering: {
- get: function () {
- return this._entityCluster;
- },
- set: function (value) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(value)) {
- throw new DeveloperError("value must be defined.");
- }
- //>>includeEnd('debug');
- this._entityCluster = value;
- },
- },
- });
- /**
- * Updates the data source to the provided time. This function is optional and
- * is not required to be implemented. It is provided for data sources which
- * retrieve data based on the current animation time or scene state.
- * If implemented, update will be called by {@link DataSourceDisplay} once a frame.
- *
- * @param {JulianDate} time The simulation time.
- * @returns {Boolean} True if this data source is ready to be displayed at the provided time, false otherwise.
- */
- GpxDataSource.prototype.update = function (time) {
- return true;
- };
- /**
- * Asynchronously loads the provided GPX data, replacing any existing data.
- *
- * @param {String|Document|Blob} data A url, parsed GPX document, or Blob containing binary GPX data or a parsed GPX document.
- * @param {Object} [options] An object with the following properties:
- * @param {Boolean} [options.clampToGround] True if the symbols should be rendered at the same height as the terrain
- * @param {String} [options.waypointImage] Image to use for waypoint billboards.
- * @param {String} [options.trackImage] Image to use for track billboards.
- * @param {String} [options.trackColor] Color to use for track lines.
- * @param {String} [options.routeColor] Color to use for route lines.
- * @returns {Promise.<GpxDataSource>} A promise that will resolve to this instances once the GPX is loaded.
- */
- GpxDataSource.prototype.load = function (data, options) {
- if (!defined(data)) {
- throw new DeveloperError("data is required.");
- }
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- DataSource.setLoading(this, true);
- const oldName = this._name;
- const that = this;
- return load(this, this._entityCollection, data, options)
- .then(function () {
- let clock;
- const availability = that._entityCollection.computeAvailability();
- let start = availability.start;
- let stop = availability.stop;
- const isMinStart = JulianDate.equals(start, Iso8601.MINIMUM_VALUE);
- const isMaxStop = JulianDate.equals(stop, Iso8601.MAXIMUM_VALUE);
- if (!isMinStart || !isMaxStop) {
- let date;
- // If start is min time just start at midnight this morning, local time
- if (isMinStart) {
- date = new Date();
- date.setHours(0, 0, 0, 0);
- start = JulianDate.fromDate(date);
- }
- // If stop is max value just stop at midnight tonight, local time
- if (isMaxStop) {
- date = new Date();
- date.setHours(24, 0, 0, 0);
- stop = JulianDate.fromDate(date);
- }
- clock = new DataSourceClock();
- clock.startTime = start;
- clock.stopTime = stop;
- clock.currentTime = JulianDate.clone(start);
- clock.clockRange = ClockRange.LOOP_STOP;
- clock.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
- clock.multiplier = Math.round(
- Math.min(
- Math.max(JulianDate.secondsDifference(stop, start) / 60, 1),
- 3.15569e7
- )
- );
- }
- let changed = false;
- if (clock !== that._clock) {
- that._clock = clock;
- changed = true;
- }
- if (oldName !== that._name) {
- changed = true;
- }
- if (changed) {
- that._changed.raiseEvent(that);
- }
- DataSource.setLoading(that, false);
- return that;
- })
- .catch(function (error) {
- DataSource.setLoading(that, false);
- that._error.raiseEvent(that, error);
- console.log(error);
- return Promise.reject(error);
- });
- };
- export default GpxDataSource;
|