You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
307 lines
9.5 KiB
JavaScript
307 lines
9.5 KiB
JavaScript
import defaultValue from "../../Core/defaultValue.js";
|
|
import defined from "../../Core/defined.js";
|
|
import DeveloperError from "../../Core/DeveloperError.js";
|
|
import Event from "../../Core/Event.js";
|
|
import wrapFunction from "../../Core/wrapFunction.js";
|
|
import CzmlDataSource from "../../DataSources/CzmlDataSource.js";
|
|
import GeoJsonDataSource from "../../DataSources/GeoJsonDataSource.js";
|
|
import KmlDataSource from "../../DataSources/KmlDataSource.js";
|
|
import getElement from "../getElement.js";
|
|
|
|
/**
|
|
* A mixin which adds default drag and drop support for CZML files to the Viewer widget.
|
|
* Rather than being called directly, this function is normally passed as
|
|
* a parameter to {@link Viewer#extend}, as shown in the example below.
|
|
* @function viewerDragDropMixin
|
|
|
|
* @param {Viewer} viewer The viewer instance.
|
|
* @param {Object} [options] Object with the following properties:
|
|
* @param {Element|String} [options.dropTarget=viewer.container] The DOM element which will serve as the drop target.
|
|
* @param {Boolean} [options.clearOnDrop=true] When true, dropping files will clear all existing data sources first, when false, new data sources will be loaded after the existing ones.
|
|
* @param {Boolean} [options.flyToOnDrop=true] When true, dropping files will fly to the data source once it is loaded.
|
|
* @param {Boolean} [options.clampToGround=true] When true, datasources are clamped to the ground.
|
|
* @param {Proxy} [options.proxy] The proxy to be used for KML network links.
|
|
*
|
|
* @exception {DeveloperError} Element with id <options.dropTarget> does not exist in the document.
|
|
* @exception {DeveloperError} dropTarget is already defined by another mixin.
|
|
* @exception {DeveloperError} dropEnabled is already defined by another mixin.
|
|
* @exception {DeveloperError} dropError is already defined by another mixin.
|
|
* @exception {DeveloperError} clearOnDrop is already defined by another mixin.
|
|
*
|
|
* @example
|
|
* // Add basic drag and drop support and pop up an alert window on error.
|
|
* var viewer = new Cesium.Viewer('cesiumContainer');
|
|
* viewer.extend(Cesium.viewerDragDropMixin);
|
|
* viewer.dropError.addEventListener(function(viewerArg, source, error) {
|
|
* window.alert('Error processing ' + source + ':' + error);
|
|
* });
|
|
*/
|
|
function viewerDragDropMixin(viewer, options) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (!defined(viewer)) {
|
|
throw new DeveloperError("viewer is required.");
|
|
}
|
|
if (viewer.hasOwnProperty("dropTarget")) {
|
|
throw new DeveloperError("dropTarget is already defined by another mixin.");
|
|
}
|
|
if (viewer.hasOwnProperty("dropEnabled")) {
|
|
throw new DeveloperError(
|
|
"dropEnabled is already defined by another mixin."
|
|
);
|
|
}
|
|
if (viewer.hasOwnProperty("dropError")) {
|
|
throw new DeveloperError("dropError is already defined by another mixin.");
|
|
}
|
|
if (viewer.hasOwnProperty("clearOnDrop")) {
|
|
throw new DeveloperError(
|
|
"clearOnDrop is already defined by another mixin."
|
|
);
|
|
}
|
|
if (viewer.hasOwnProperty("flyToOnDrop")) {
|
|
throw new DeveloperError(
|
|
"flyToOnDrop is already defined by another mixin."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
|
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
|
|
//Local variables to be closed over by defineProperties.
|
|
var dropEnabled = true;
|
|
var flyToOnDrop = defaultValue(options.flyToOnDrop, true);
|
|
var dropError = new Event();
|
|
var clearOnDrop = defaultValue(options.clearOnDrop, true);
|
|
var dropTarget = defaultValue(options.dropTarget, viewer.container);
|
|
var clampToGround = defaultValue(options.clampToGround, true);
|
|
var proxy = options.proxy;
|
|
|
|
dropTarget = getElement(dropTarget);
|
|
|
|
Object.defineProperties(viewer, {
|
|
/**
|
|
* Gets or sets the element to serve as the drop target.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Element}
|
|
*/
|
|
dropTarget: {
|
|
//TODO See https://github.com/CesiumGS/cesium/issues/832
|
|
get: function () {
|
|
return dropTarget;
|
|
},
|
|
set: function (value) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (!defined(value)) {
|
|
throw new DeveloperError("value is required.");
|
|
}
|
|
//>>includeEnd('debug');
|
|
|
|
unsubscribe(dropTarget, handleDrop);
|
|
dropTarget = value;
|
|
subscribe(dropTarget, handleDrop);
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets or sets a value indicating if drag and drop support is enabled.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Element}
|
|
*/
|
|
dropEnabled: {
|
|
get: function () {
|
|
return dropEnabled;
|
|
},
|
|
set: function (value) {
|
|
if (value !== dropEnabled) {
|
|
if (value) {
|
|
subscribe(dropTarget, handleDrop);
|
|
} else {
|
|
unsubscribe(dropTarget, handleDrop);
|
|
}
|
|
dropEnabled = value;
|
|
}
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets the event that will be raised when an error is encountered during drop processing.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Event}
|
|
*/
|
|
dropError: {
|
|
get: function () {
|
|
return dropError;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets or sets a value indicating if existing data sources should be cleared before adding the newly dropped sources.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Boolean}
|
|
*/
|
|
clearOnDrop: {
|
|
get: function () {
|
|
return clearOnDrop;
|
|
},
|
|
set: function (value) {
|
|
clearOnDrop = value;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets or sets a value indicating if the camera should fly to the data source after it is loaded.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Boolean}
|
|
*/
|
|
flyToOnDrop: {
|
|
get: function () {
|
|
return flyToOnDrop;
|
|
},
|
|
set: function (value) {
|
|
flyToOnDrop = value;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets or sets the proxy to be used for KML.
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Proxy}
|
|
*/
|
|
proxy: {
|
|
get: function () {
|
|
return proxy;
|
|
},
|
|
set: function (value) {
|
|
proxy = value;
|
|
},
|
|
},
|
|
|
|
/**
|
|
* Gets or sets a value indicating if the datasources should be clamped to the ground
|
|
* @memberof viewerDragDropMixin.prototype
|
|
* @type {Boolean}
|
|
*/
|
|
clampToGround: {
|
|
get: function () {
|
|
return clampToGround;
|
|
},
|
|
set: function (value) {
|
|
clampToGround = value;
|
|
},
|
|
},
|
|
});
|
|
|
|
function handleDrop(event) {
|
|
stop(event);
|
|
|
|
if (clearOnDrop) {
|
|
viewer.entities.removeAll();
|
|
viewer.dataSources.removeAll();
|
|
}
|
|
|
|
var files = event.dataTransfer.files;
|
|
var length = files.length;
|
|
for (var i = 0; i < length; i++) {
|
|
var file = files[i];
|
|
var reader = new FileReader();
|
|
reader.onload = createOnLoadCallback(viewer, file, proxy, clampToGround);
|
|
reader.onerror = createDropErrorCallback(viewer, file);
|
|
reader.readAsText(file);
|
|
}
|
|
}
|
|
|
|
//Enable drop by default;
|
|
subscribe(dropTarget, handleDrop);
|
|
|
|
//Wrap the destroy function to make sure all events are unsubscribed from
|
|
viewer.destroy = wrapFunction(viewer, viewer.destroy, function () {
|
|
viewer.dropEnabled = false;
|
|
});
|
|
|
|
//Specs need access to handleDrop
|
|
viewer._handleDrop = handleDrop;
|
|
}
|
|
|
|
function stop(event) {
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
}
|
|
|
|
function unsubscribe(dropTarget, handleDrop) {
|
|
var currentTarget = dropTarget;
|
|
if (defined(currentTarget)) {
|
|
currentTarget.removeEventListener("drop", handleDrop, false);
|
|
currentTarget.removeEventListener("dragenter", stop, false);
|
|
currentTarget.removeEventListener("dragover", stop, false);
|
|
currentTarget.removeEventListener("dragexit", stop, false);
|
|
}
|
|
}
|
|
|
|
function subscribe(dropTarget, handleDrop) {
|
|
dropTarget.addEventListener("drop", handleDrop, false);
|
|
dropTarget.addEventListener("dragenter", stop, false);
|
|
dropTarget.addEventListener("dragover", stop, false);
|
|
dropTarget.addEventListener("dragexit", stop, false);
|
|
}
|
|
|
|
function createOnLoadCallback(viewer, file, proxy, clampToGround) {
|
|
var scene = viewer.scene;
|
|
return function (evt) {
|
|
var fileName = file.name;
|
|
try {
|
|
var loadPromise;
|
|
|
|
if (/\.czml$/i.test(fileName)) {
|
|
loadPromise = CzmlDataSource.load(JSON.parse(evt.target.result), {
|
|
sourceUri: fileName,
|
|
});
|
|
} else if (
|
|
/\.geojson$/i.test(fileName) ||
|
|
/\.json$/i.test(fileName) ||
|
|
/\.topojson$/i.test(fileName)
|
|
) {
|
|
loadPromise = GeoJsonDataSource.load(JSON.parse(evt.target.result), {
|
|
sourceUri: fileName,
|
|
clampToGround: clampToGround,
|
|
});
|
|
} else if (/\.(kml|kmz)$/i.test(fileName)) {
|
|
loadPromise = KmlDataSource.load(file, {
|
|
sourceUri: fileName,
|
|
proxy: proxy,
|
|
camera: scene.camera,
|
|
canvas: scene.canvas,
|
|
clampToGround: clampToGround,
|
|
});
|
|
} else {
|
|
viewer.dropError.raiseEvent(
|
|
viewer,
|
|
fileName,
|
|
"Unrecognized file: " + fileName
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (defined(loadPromise)) {
|
|
viewer.dataSources
|
|
.add(loadPromise)
|
|
.then(function (dataSource) {
|
|
if (viewer.flyToOnDrop) {
|
|
viewer.flyTo(dataSource);
|
|
}
|
|
})
|
|
.otherwise(function (error) {
|
|
viewer.dropError.raiseEvent(viewer, fileName, error);
|
|
});
|
|
}
|
|
} catch (error) {
|
|
viewer.dropError.raiseEvent(viewer, fileName, error);
|
|
}
|
|
};
|
|
}
|
|
|
|
function createDropErrorCallback(viewer, file) {
|
|
return function (evt) {
|
|
viewer.dropError.raiseEvent(viewer, file.name, evt.target.error);
|
|
};
|
|
}
|
|
export default viewerDragDropMixin;
|