how to re initialize webglglobe with vue - vue.js

I am using http://www.webglearth.org/api for a globe on my vue app.
I have a route called globe that initializes the globe with new WE.map. when I change routes and go back it re initializes but re adds scripts to my head which jam up the globe tiles from loading. Is there a way to keep and re use an instantiated object? Or any tips that could help with this
I tried saving my created globe in the store and re using it though it wont reload without doing a WE.map and that method adds the headers
this method is being called on vue create
initialize(data) {
var earth = WE.map("earth_div");
WE.tileLayer(
"https://webglearth.github.io/webglearth2-offline/{z}/{x}/{y}.jpg",
{
tileSize: 256,
bounds: [[-85, -180], [85, 180]],
minZoom: 0,
maxZoom: 16,
attribution: "WebGLEarth example",
tms: true
}
).addTo(earth);
data.forEach(doc => {
let latlng = [];
console.log(typeof doc.data().images);
console.log(doc.data().galleryTitle);
latlng[0] = doc.data().lat;
latlng[1] = doc.data().lng;
console.log(latlng);
var marker = WE.marker(latlng).addTo(earth);
marker.element.id = doc.data().safeTitle;
let popup = `${doc.data().location}`;
marker
.bindPopup(popup, { maxWidth: 150, closeButton: true })
.openPopup();
marker.element.onclick = e => {
console.log(e.target.parentElement.id);
var gallery = e.target.parentElement.id;
this.$router.push({ path: "/gallery/" + gallery });
};
});
// Start a simple rotation animation
var before = null;
requestAnimationFrame(function animate(now) {
console.log('animating')
var c = earth.getPosition();
var elapsed = before ? now - before : 0;
before = now;
earth.setCenter([c[0], c[1] + 0.1 * (elapsed / 30)]);
// requestAnimationFrame(animate);
});
earth.setView([46.8011, 8.2266], 3);
this.$store.commit('setEarth',earth)
},
I would like the globe to re initiate without re adding headers.

Related

ArcGIS map polygon store in ArcGIS

I have to store the created polygon in ArcGIS. Once the polygon is stored in ArcGIS, it returns an ID (Object ID). With the object ID, the administrator can access the polygon in ArcGIS. I found a piece of code in one of our old systems the code is written in version 3xx.
function SendFeaturesToParent()
{
editingEnabled = false;
editToolbar.deactivate();
lyrMeters.clearSelection();
polygon = currentEVT.graphic.geometry;
var query = new Query();
query.geometry = polygon;
lyrAreas.applyEdits(null, [currentEVT.graphic], null);
var attributes = [];
var featureValues = [];
for (var x = 0; x < selectedfeatures.length; x++) {
featureValues.push("METER_ID: " + selectedfeatures[x].attributes["METER_ID"] + ", Type: " + selectedfeatures[x].attributes["Type"]);
attributes.push(selectedfeatures[x].attributes);
}
console.log("attributes"+ attributes);
//Send the array of meter values back to the parent page.
var objectId = lyrAreas._defnExpr;
objectId = objectId.split('=');
window.parent.postMessage(
{
event_id: 'my_cors_message',
data: attributes,
objectId: objectId[1]
},
"*" //or "www.parentpage.com"
);
$('#modelConfirm').modal('hide');
}
I need to implement in latest version of arcGIS API 4.23. What are the applyEdits do?
/**** modified code in 4.23 */
var token = '';
const PermitAreaURL = "url_1";
const locatorUrl = "url_2";
const streetmapURL = "url_3";
const streetmapLebelsURL = "url_4";
const MetersURL = "url_5";
const MetersWholeURL = "url_6";
require(["esri/config",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/TileLayer",
"esri/layers/VectorTileLayer",
"esri/layers/GraphicsLayer",
"esri/widgets/Search",
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/geometryEngineAsync",
],
function (esriConfig, Map, MapView, FeatureLayer, TileLayer, VectorTileLayer, GraphicsLayer, Search, SketchViewModel, geometryEngineAsync) {
esriConfig.apiKey = "AAPK3f43082c24ae493196786c8b424e9f43HJcMvP1NYaqIN4p63qJnCswIPsyHq8TQHlNtMRLWokqJIWYIJjga9wIEzpy49c9v";
const graphicsLayer = new GraphicsLayer();
const streetmapTMLayer = new TileLayer({
url: streetmapURL
});
const streetmapLTMLayer = new VectorTileLayer({
url: streetmapLebelsURL
});
const lyrwholeMeters = new FeatureLayer({
url: MetersWholeURL,
outFields: ["*"],
});
const lyrMeters = new FeatureLayer({
url: MetersURL,
outFields: ["*"],
});
// const permitAreaUrl = new FeatureLayer({
// url: PermitAreaURL,
// outFields: ["*"],
// });
// console.log(lyrMeters);
const map = new Map({
basemap: "arcgis-topographic", // Basemap layer service
layers: [streetmapTMLayer, streetmapLTMLayer, lyrMeters, lyrwholeMeters, graphicsLayer]
});
const view = new MapView({
map: map,
center: [-95.9406, 41.26],
zoom: 16,
maxZoom: 21,
minZoom: 13,
container: "viewDiv" // Div element
});
view.when(() => {
const polygonSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [207, 34, 171, 0.5],
outline: {
// autocasts as new SimpleLineSymbol()
color: [247, 34, 101, 0.9],
}
};
const sketchViewModel = new SketchViewModel({
view: view,
layer: graphicsLayer,
polygonSymbol: polygonSymbol,
});
sketchViewModel.create("polygon", { mode: "hybrid" });
// Once user is done drawing a rectangle on the map
// use the rectangle to select features on the map and table
sketchViewModel.on("create", async (event) => {
if (event.state === "complete") {
// this polygon will be used to query features that intersect it
const geometries = graphicsLayer.graphics.map(function (graphic) {
return graphic.geometry
});
const queryGeometry = await geometryEngineAsync.union(geometries.toArray());
selectFeatures(queryGeometry);
}
});
});
// This function is called when user completes drawing a rectangle
// on the map. Use the rectangle to select features in the layer and table
function selectFeatures(geometry) {
console.log(geometry.rings);
// create a query and set its geometry parameter to the
// rectangle that was drawn on the view
const query = {
geometry: geometry,
outFields: ["*"]
};
lyrwholeMeters.queryFeatures(query).then(function (results) {
var lyr = results.features;
console.log(lyr);
// save the polygon
lyr.applyEdits({
addFeatures: [geometry] /*updates*/
});
lyr.forEach(element => {
console.log(`MeterID-${element.attributes.METER_ID}, OBJECTID-${element.attributes.OBJECTID}, Passport_ID-${element.attributes.Passport_ID}`);
});
});
}
// search widget
const searchWidget = new Search({
view: view,
});
view.ui.add(searchWidget, {
position: "top-left",
index: 2
});
});
applyEdits method is the way you to add/update/delete features in a feature layer. Both version of the library have the method although in version 4 takes an object that contain the edits instead of the separated parameters. In your code, version 3, it is,
lyrAreas.applyEdits(null, [currentEVT.graphic], null);
first parameter is for new features, second for updates on features and third for features to delete.
While in version 4 it should be,
lyrAreas.applyEdits({
updateFeatures: [currentEVT.graphic] /*updates*/
});
the object goes all the informations about the edits, in this case you only have updates.
I am not completely sure about this line,
var objectId = lyrAreas._defnExpr;
objectId = objectId.split('=');
I am guessing is the definition expression of the feature layer, a sql expression, that is why in the next line it is split, to use later the value. Version 3 library did not expose the property but gives set and get methods.
Version 4 have the property and works in similar way. In this case for latest version it should be,
var objectId = lyrAreas.definitionExpression;
objectId = objectId.split('=');
So I do not think you will have
ArcGIS API v3 - FeatureLayer
ArcGIS API v4 - FeatureLayer

Remove image overlay layer in Leaflet

I'm trying to place a sketch on a building on the map with Leaflet. I succeeded in this as well, I can place and scale an image in svg format on the map. But when I add a new sketch to the map, I want the old sketch to be deleted from the map.
map.removeLayer(sketchLayer)
sketchLayer.removeFrom(map)
map.removeLayer(L.sketchLayer)
i tried these
My codes,
splitCoordinate (value) {
const topLeftCoordinates = value.top_left.split(',')
const topRightCoordinates = value.top_right.split(',')
const bottomLeftCoordinates = value.bottom_left.split(',')
this.initMap(topLeftCoordinates, topRightCoordinates, bottomLeftCoordinates)
},
initMap (topLeftCoordinates, topRightCoordinates, bottomLeftCoordinates) {
let map = this.$refs.map.mapObject
map.flyTo(new L.LatLng(topLeftCoordinates[0], topLeftCoordinates[1]), 20, { animation: true })
const vm = this
var topleft = L.latLng(topLeftCoordinates[0], topLeftCoordinates[1])
var topright = L.latLng(topRightCoordinates[0], topRightCoordinates[1])
var bottomleft = L.latLng(bottomLeftCoordinates[0], bottomLeftCoordinates[1])
var sketchLayer = L.imageOverlay.rotated(vm.imgUrl, topleft, topright, bottomleft, {
opacity: 1,
interactive: true
})
map.addLayer(sketchLayer)
}
Fix:
The error was related to the javascript scope. I defined the sketchLayer in the data and my problem solved.

Adding markerclustergroup to leaflet overlay does not update in Vue.js app

I have an overlay control on my leaflet map in a vue.js application. It contains two layers. The ILZipCodes layer renders perfectly. However, the "markers" layer does not appear when I select the checkbox in the layer control. Why is this? I reckon I may be setting up the layer control and populating the clusters in the wrong sequence.
Cheers
<template>
<div>
<div class="mx-auto my-6 loader" v-if="isSearching"></div>
<div class="tooManyResultsError" v-if="tooManyResults">
Your search brought back too many results to display. Please zoom in or refine your search with the text box and
filters.
</div>
<div id="leafletMapId"></div>
</div>
</template>
<script>
//The center coordinate and zoom level that the map should initialize to
// to capture all of the continental United States
const INITIAL_CENTER_LATITUDE = 34;
const INITIAL_CENTER_LONGITUDE = -96;
const INITIAL_ZOOM = 4;
/* Leaflet performs slowly with reactivity ("observable" data object variables).
* To work around this, I removed myMap and markers from the data object.
*/
/* If the user zooms out or pans beyond the boundaries of the previous fetch's dataset, then
* the client fetches location data from the server to replace the previous map data. If the user
* zooms or pans but stays within the boundaries of the dataset currently displayed on the map, then
* the client does not run another fetch.
* */
import axios from "axios";
import store from "../store.js";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet.markercluster/dist/MarkerCluster.css";
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
import "leaflet.markercluster/dist/leaflet.markercluster-src.js";
import "leaflet-ajax/dist/leaflet.ajax.js";
import icon from "leaflet/dist/images/marker-icon.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";
export default {
name: "ContactsMap",
mounted() {
this.fetchAggregatedDistrictStats();
},
methods: {
async fetchAggregatedDistrictStats() {
axios.get(... // fetches some statistics for the other overlay layers
);
},
createMapWithLeafletAndMapTiler() {
var $this = this;
var streetTilesLayer = L.tileLayer(MAPTILER_STREETS_URL, {
maxZoom: 18,
minZoom: 2,
attribution: MAPBOX_ATTRIBUTION,
tileSize: 512,
zoomOffset: -1
});
// eslint-disable-next-line
var satelliteTilesLayer = L.tileLayer(MAPTILER_SATELLITE_URL, {
maxZoom: 18,
minZoom: 2,
tileSize: 512,
zoomOffset: -1
});
var baseMaps = {
Satellite: satelliteTilesLayer,
Streets: streetTilesLayer
};
if (myMap != undefined) {
myMap.remove();
}
var myMap = L.map("leafletMapId", {
layers: [streetTilesLayer],
}).setView(this.center, this.zoom);
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var count = cluster.getChildCount();
var digits = (count + "").length;
return L.divIcon({
html: "<b>" + count + "</b>" + digits,
className: "cluster digits-" + digits,
iconSize: 22 + 10 * digits
});
}
});
async function fetchLocations(shouldProgrammaticallyFitBounds) {
markers.clearLayers();
markers = L.markerClusterGroup({
chunkedLoading: true,
iconCreateFunction: function(cluster) {
var count = cluster.getChildCount();
var digits = (count + "").length;
return L.divIcon({
html: "<b>" + count + "</b>",
className: "cluster digits-" + digits,
iconSize: 22 + 10 * digits
});
}
});
axios
.get("/maps/" + $this.list.list_id, {
//fetches markerclusters
})
.then(
response => {
$this.tooManyResults = false;
var addressPoints = response.data.recordsList;
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = L.marker(L.latLng(a[0], a[1]));
marker.bindPopup(title);
markers.addLayer(marker); // This is where I'm adding the markers and markerclusters to the layer titled "markers"
// myMap.addLayer(markers); //If I uncomment this, then the markers layer is always on the map, i.e. not as an overlay layer
}
},
error => {
$this.isSearching = false;
document.getElementById("leafletMapId").style.display = "block";
store.setErrorMessage("Network error searching list", error);
}
);
}
myMap.on("zoomend", handlerFunction);
myMap.on("dragend", handlerFunction);
var defaultPolygonStyle = {
color: "black",
weight: 1,
opacity: 0.8,
fillOpacity: 0.1
};
var NationalCongressional = new L.geoJson.ajax(
"http://localhost:8080/assets/geo/NationalCongressional.json",
{
style: defaultPolygonStyle,
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.NAMELSAD);
if (feature.properties.NAMELSAD == "Congressional District 8") {
layer.setStyle({ color: "orange" });
}
}
}
);
function getColorFromRedBlueRange(d) {
return d > 0.8
? "#FF0000"
: d > 0.7
? "#FF006F"
: d > 0.55
? "#FF00EF"
: d > 0.45
? "#DE00FF"
: d > 0.3
? "#BC00FF"
: d > 0.2
? "#6600FF"
: "#00009FF";
}
var ILZipCodes = new L.geoJson.ajax(
"https://raw.githubusercontent.com/OpenDataDE/State-zip-code-GeoJSON/master/il_illinois_zip_codes_geo.min.json",
{
// style: defaultPolygonStyle,
onEachFeature: function(feature, layer) {
layer.bindPopup(
feature.properties.ZCTA5CE10 +
", " +
$this.zipData[feature.properties.ZCTA5CE10]
);
layer.setStyle({
color: getColorFromRedBlueRange(
$this.zipData[feature.properties.ZCTA5CE10]
),
weight: 0,
fillOpacity: 0.3
});
}
}
);
var overlays = {
Voters: voterGroup,
ILZipCodes: ILZipCodes,
};
L.control.layers(baseMaps, overlays).addTo(myMap);
fetchLocations(true);
}
}
};
You add voterGroup to your Layers Control, instead of your markers.
Then simply do not re-assign a MarkerClusterGroup into your markers variable (after you use clearLayers) and you should be fine.

Can’t access to custom canvas attribute in Vue

Has anyone used this component with Vue?
https://www.npmjs.com/package/aframe-draw-component.
I want to use Advanced Usage with “aframe-draw-component”.
it works with raw html but not vue.js. codepen example
// html
<a-scene fog="type: exponential; color:#000">
<a-sky acanvas rotation="-5 -10 0"></a-sky>
</a-scene>
// js
const chars = 'ABCDEFGHIJKLMNOPQRWXYZ'.split('')
const font_size = 8
AFRAME.registerComponent("acanvas", {
dependencies: ["draw"],
init: function(){
console.log(this.el.components)
this.draw = this.el.components.draw // get access to the draw component
this.draw.canvas.width = '512'
this.draw.canvas.height = '512'
this.cnvs = this.draw.canvas
const columns = this.cnvs.width / font_size
this.drops = []
for (let x = 0; x < columns; x++) {
this.drops[x] = 1
}
this.ctx = this.draw.ctx
},
tick: function() {
this.ctx.fillStyle = 'rgba(0,0,0,0.05)'
this.ctx.fillRect(0, 0, this.cnvs.width, this.cnvs.height)
this.ctx.fillStyle = '#0F0'
this.ctx.font = font_size + 'px helvetica'
for(let i = 0; i < this.drops.length; i++) {
const txt = chars[Math.floor(Math.random() * chars.length)]
this.ctx.fillText(txt, i * font_size, this.drops[i] * font_size)
if(this.drops[i] * font_size > this.cnvs.height && Math.random() > 0.975) {
this.drops[i] = 0 // back to the top!
}
this.drops[i] = this.drops[i] + 1
}
this.draw.render()
}
})
No matter where I put in Vue component, I get this error:
App.vue?b405:124 Uncaught (in promise) TypeError: Cannot read property ‘canvas’ of undefined
at NewComponent.init (eval at
It can’t find the custom dependency “draw”.
Can somebody help me ?
Thanks.
The canvas element is at Your disposal in the el.components.draw.canvas reference.
You can either create Your standalone vue script, or attach it to an existing component like this:
AFRAME.registerComponent("vue-draw", {
init: function() {
const vm = new Vue({
el: 'a-plane',
mounted: function() {
setTimeout(function() {
var draw = document.querySelector('a-plane').components.draw; /
var ctx = draw.ctx;
var canvas = draw.canvas;
ctx.fillStyle = 'red';
ctx.fillRect(68, 68, 120, 120);
draw.render();
}, 100)
}
});
}
})
Working fiddle: https://jsfiddle.net/6bado2q2/2/
Basically, I just accessed the canvas, and told it to draw a rectangle.
Please keep in mind, that Your error may persist when You try to access the canvas before the draw component managed to create it.
My no-brainer solution was just a timeout. Since the scene loads, and starts rendering faster, than the canvas is being made, I would suggest making a interval checking if the canvas element is defined somehow, and then fire the vue.js script.Also keep in mind, that You can work on existing canvas elements with the build in canvas texture: https://aframe.io/docs/0.6.0/components/material.html

Google Maps API - Map not showing on second initialize

I have a page setup that requires multiple instances of Google Maps via the API to be initialized. All works fine when one map is initialized the first time. When you re click on the button to do so, the map does not fully show.
var locations = [
['test1', 45.440188, -75.676309, 1, 'transportation.png'],
['test2', 45.439463, -75.675751, 1, 'medical.png'],
['test3', 45.439792, -75.683544, 1, 'schools.png'],
['test4', 45.439652, -75.676929, 1, 'shopping.png']
];
function initialize_1() {
var mapOptions = {
center: new google.maps.LatLng(45.438612, -75.677561),
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas_1"), mapOptions);
marker = new google.maps.Marker({
position: new google.maps.LatLng(45.438612, -75.677561),
map: map
});
var marker, i;
var iconBase = 'http://www.elkproperty.com/new/images/icons/';
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
,icon: iconBase + locations[i][4]
});
}
}
I think the issue is that you are initialising map to a hidden layer. Try to move call to initialize_1() after show():
onclick="$('#units_1').hide(); $('#unitArrow_1').hide(); $('#amenity_1').show(); $('#amenityArrow_1').show(); initialize_1();"
Other option is to force resize event after divs are visible. For this to work you would probably have to make map variable global.
google.maps.event.trigger(map, 'resize');
Maybe unrelated to your question but do you have to initialise the map layer each time you show div with map? Maybe you could test whether it is initialised or not, for example:
var isInit_1 = false;
function initialize_1() {
if (isInit_1) { return; }
isInit_1 = true;
var mapOptions = {
...