geospatiale/files/maptalks_kmz_framework.js

if (!global.Geospatiale) 
	global.Geospatiale = {};

/**
 * Handles GeoKMZ/KML files for Maptalks and allows them to be rendered.
 * 
 * @type {Geospatiale.maptalks_GeoKMZ}
 */
Geospatiale.maptalks_GeoKMZ = class {
	constructor (arg0_kmz_file, arg1_options) {
		//Convert from parameters
		let kmz_file = arg0_kmz_file;
		let options = (arg1_options) ? arg1_options : {};
		
		//Declare local instance variables
		this.leaflet_html = document.createElement("div");
		this.map = L.map(this.leaflet_html);
		this.options = options;
		
		//Load KMZ
		this.geometries_obj = {};
		this.layer = new maptalks.VectorLayer(kmz_file);
		
		//Populate this.kmz
		if (kmz_file) this.loadKMZ(kmz_file, {
			window_options: {
				width: "25rem",
			},
			...options
		});
	}
	
	/**
	 * Adds the current GeoKMZ to a Maptalks map.
	 * - Method of: {@link Geospatiale.maptalks_GeoKMZ}
	 * 
	 * @param {maptalks.Map} arg0_map_obj
	 */
	addTo (arg0_map_obj) { try { arg0_map_obj.addLayer(this.layer); } catch (e) {} }
	
	/**
	 * Loads a KMZ into the current collated layer.
	 * - Method of: {@link Geospatiale.maptalks_GeoKMZ}
	 * 
	 * @param {string} arg0_input_file_path
	 * @param {Object} [arg1_options]
	 *  @param {string[]} [arg1_options.exclude_types] - Any types to exclude. Either 'polygon'/'line'/'point'.
	 *  @param {boolean} [arg1_options.do_not_display_popups=false]
	 *  @param {function} [arg1_options.onload] - (arg0_geokmz_obj, arg1_geometries). The method to call once loading is finished.
	 *  @param {Object} [arg1_options.window_options]
	 */
	loadKMZ (arg0_input_file_path, arg1_options) {
		//Convert from parameters
		let input_file_path = arg0_input_file_path;
		let options = (arg1_options) ? arg1_options : {};
		
		//Initialise options
		if (!options.exclude_types) options.exclude_types = [];
		
		//Internal guard clause if KMZ can't be found
		if (!fs.existsSync(input_file_path)) {
			console.warn(`maptalks_GeoKMZ: Could not load ${input_file_path}. File does not exist.`);
			return;
		}
		if (this.geometries_obj[input_file_path]) this.unloadKMZ(input_file_path); //Unload conflicting geometries_obj first
		
		//Declare local instance variables
		this.geometries_obj[input_file_path] = [];
		let geometries = this.geometries_obj[input_file_path];
		let kmz = L.kmzLayer().addTo(this.map);
		
		kmz.load(input_file_path);
		kmz.on("load", (e) => {
			Object.iterate(e.layer._layers, (local_key, local_value) => {
				let geometry_type = Geospatiale.getLeafletGeometryType(local_value);
				
				if (options.exclude_types.length === 0 || !options.exclude_types.includes(geometry_type)) {
					//Check geometry_type
					if (["polygon", "line"].includes(geometry_type)) {
						geometries.push({
							geometry: local_value.toGeoJSON(),
							symbol: Geospatiale.convertLeafletSymbolToMaptalks(local_value.options),
							type: geometry_type
						});
					} else if (geometry_type === "point") {
						let icon_url;
							try { icon_url = local_value.options.iconUrl; } catch (e) {}
						let popup_title;
							try { popup_title = local_value._tooltip._content; } catch (e) {}
						let popup_description;
							try { popup_description = local_value._popup._content; } catch (e) {}
						
						geometries.push({
							geometry: local_value.toGeoJSON(),
							properties: {
								popup_title: popup_title,
								popup_description: popup_description
							},
							symbol: {
								...Geospatiale.convertLeafletSymbolToMaptalks(local_value.options),
								markerFile: icon_url
							},
							type: geometry_type
						});
					}
				}
			});
			
			//Iterate over all geometries and add it to the map
			for (let i = 0; i < geometries.length; i++) { //[WIP] - Use Vercengen popups instead
				let local_geometry = maptalks.GeoJSON.toGeometry(geometries[i].geometry);
				let local_properties = geometries[i].properties;
				
				try {
					if (!options.do_not_display_popups)
						local_geometry.addEventListener("click", (e) => {
							veWindow(local_properties.popup_description, {
								name: (local_properties.popup_title) ? local_properties.popup_title : "",
								width: "20rem",
								...options.window_options
							});
						});
				} catch (e) {}
				local_geometry.updateSymbol(geometries[i].symbol);
				local_geometry.addTo(this.layer);
				
				geometries[i].maptalks_obj = local_geometry;
			}
			
			if (this.options.onload)
				this.options.onload(this, this.geometries_obj[input_file_path]);
			
			//Free memory for kmz
			kmz.clearLayers();
			kmz.remove();
		});
		
	}
	
	/**
	 * Removes the current GeoKMZ from a Maptalks map.
	 * - Method of: {@link Geospatiale.maptalks_GeoKMZ}
	 */
	remove () {
		Object.iterate(this.geometries_obj, (local_key, local_value) => 
			this.unloadKMZ(local_key));
	}
	
	/**
	 * Removes the KMZ from the given Maptalks map if possible.
	 * - Method of: {@link Geospatiale.maptalks_GeoKMZ}
	 * 
	 * @param {maptalks.Map} arg0_map_obj
	 */
	removeFrom (arg0_map_obj) { try { arg0_map_obj.removeLayer(this.layer); } catch (e) {} }
	
	/**
	 * Unloads the given GeoKMZ given an input path.
	 * - Method of: {@link Geospatiale.maptalks_GeoKMZ}
	 * 
	 * @param {string} arg0_input_file_path
	 */
	unloadKMZ (arg0_input_file_path) {
		//Convert from parameters
		let input_file_path = arg0_input_file_path;
		
		//Internal guard clause if KMZ isn't in cache
		if (!this.geometries_obj[input_file_path]) return;
		
		//Declare local instance variables
		let geometries = this.geometries_obj[input_file_path];
		
		//Iterate over all geometries and unload it
		for (let i = 0; i < geometries.length; i++)
			geometries[i].maptalks_obj.remove(this.layer);
		delete this.geometries_obj[input_file_path];
	}
};