I have thousands of points that need to be plotted on google maps and got a very responsive maps using the example from https://github.com/ubilabs/google-maps-api-threejs-layer .
Did anyone have a play at this and wondering if it is possible to have different colored markers and possible marker click events?
Appreciate any pointers or examples online.
Millions of clickable data points can be painted on a google map using webgl.
A data point is represented by an x,y pair for a location on the canvas, an int for size, an off screen color, and an on screen color. These values are stored in separate typed arrays.
Each data point has a unique rgb color to act as a key in a lookup table of data point ids.
Create a texture to store the off screen colors and render it to an off screen buffer. On event, load the off screen buffer and use glReadPixels to retrieve the rgb color of the pixel clicked and then find the id in the lookup table. Points on the on screen buffer, what the user sees, can share a common color.
canvas.addEventListener('click', function(ev) {
# insert code to get mouse x,y position on canvas
pixels = new Uint8Array(4);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
if (colorToId[pixels[0] + " " + pixels[1] + " " + pixels[2]]) {
# Pixel clicked is a data point on the map
}
});
Webgl code is lengthy, so only the click event is included.
Here is a live demo and a repo. (angular and coffeescript)
Here is a second example using plain js: webgl-picking-geo-polygons
Here is react-webgl-leaflet
The solution is based on Brendan Kenny's Google Maps + HTML5 + Spatial Data Visualization which explains some of the code in the excerpt above at the 30 min mark, and Displaying WebGL data on Google Maps.
The demo features less than ten data points, but you can just as easily paint over 16 million pickable data points using all combinations of rgb values.
I discovered OpenLayers this past week. Very, very impressive framework. I would strongly suggest taking a look at it. OpenLayers.org is an open source JavaScript web mapping library distinguished from other alternatives, like Leaflet or Google Maps APIs, because of its huge set of components.
I spent the entire weekend creating sample apps by integrating OpenLayers with API's such as MapBox, WebGL etc... After all was said and done, I was extremely impressed with OpenLayers - and I plan to make use of OpenLayers in an upcoming POC/Project.
Here is a link to my test harness. From there you can also download the code for all of the examples, too.
Updates for 2021!!
Google Maps JS now has a WebglOverlayView class and exposes the WebGL context.
const webglOverlayView = new google.maps.WebglOverlayView();
webglOverlayView.onAdd = () => {
// Do setup that does not require access to rendering context.
}
webglOverlayView.onContextRestored = gl => {
// Do setup that requires access to rendering context before onDraw call.
}
webglOverlayView.onDraw = (gl, coordinateTransformer) => {
// Render objects.
}
webglOverlayView.onContextLost = () => {
// Clean up pre-existing GL state.
}
webglOverlayView.onRemove = () => {
// Remove all intermediate objects.
}
webglOverlayView.setMap(map);
Additionally, #googlemaps/three extends this class for easier use with ThreeJS.
// instantiate a ThreeJS Scene
const scene = new Scene();
// Create a box mesh
const box = new Mesh(
new BoxBufferGeometry(10, 50, 10),
new MeshNormalMaterial(),
);
// set position at center of map
box.position.copy(latLngToVector3(mapOptions.center));
// set position vertically
box.position.setY(25);
// add box mesh to the scene
scene.add(box);
// instantiate the ThreeJS Overlay with the scene and map
new ThreeJSOverlayView({
scene,
map,
});
Here is a link to a jQuery/google map app. Not exactly what you are looking for; however you might find the example useful. Feel free to use - it can be downloaded from my site.
Link to app on my website
Click here to download the zip
Related
I would like to link between elements from the 2D sheet and 3D model, so when I select the element from 2D it should reflect and select (isolate) in the 3D also if I change the color it does the same on both e.g. and the other way around.
so I can use the document browser extensions to open the 2d sheet on 1st viewer and the 3d model on the 2nd viewer:
const firstModel = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv1'));
const secondModel = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv2'));
Autodesk.Viewing.Initializer(options1, function() {
viewer1.start();
viewer1.load(...);
});
Autodesk.Viewing.Initializer(options2, function() {
viewer2.start();
viewer2.load(...);
});
if the example above is correct I am still missing how to links both viewers.
I hope someone could help me with this issue
Note that we have a viewer extension that might already give you what you're looking for: https://github.com/Autodesk-Forge/forge-extensions/blob/master/public/extensions/NestedViewerExtension/README.md.
If you want to implement the cross-selection between two viewer instances yourself, you can. Just subscribe to the SELECTION_CHANGED event in one of the viewers, get the selected IDs, and select the same IDs in the other viewer using the usual viewer.select([...]); method.
Btw. regarding your code snippet:
the Autodesk.Viewing.Initializer only needs to be called once per the entire webpage
the Autodesk.Viewing.Private.GuiViewer3D instances should be created after the initializer has done its work
i am using a CesiumJS instance to display a base map of the earth using a imageryProvider from source A.
var viewer = new Cesium.Viewer('cesiumContainer', imageryProvider:providerA);
Now while using the Viewer I would like to be able to change this map to get images from providerB at a certain event.
I tried:
viewer.scene.imageryLayers.get(0).imageryProvider.url = providerB.url
However that does not seem to work and also feels quite like hack anyway.
I could not find anything in Cesium's documentation .
Is this at all possible without restarting / recreating the viewer instance?
I know that there is a Cesium.BaseLayerPicker (https://cesium.com/docs/cesiumjs-ref-doc/BaseLayerPicker.html)
However I do not see what method this picker calls on "select" )
Thanks a lot.
The BaseLayerPicker widget calls this code when the user selects a new layer.
There's a lot of boilerplate widget management in that block of code, but for your sake, only a couple of the lines are critical. First, the old existing active imagery layer is searched for, and removed:
imageryLayers.remove(layer);
Then, a new imagery provider is constructed and added at index 0, the first position, which is the base imagery layer:
imageryLayers.addImageryProvider(newProviders, 0);
You can directly change the URL of the provider but you should also change appropriate parameters("layers" in case of WMS, "layer", "style", "format", "tileMatrixSetID " ... in case of WMTS) depending on the type of provider(WMS or WMTS).
I'm trying to draw polygon on my map using ngmap. The map is displayed correctly as this example is showing, but when I finish the draw, this is what I'm getting:
ng-map.min.js:25 Uncaught TypeError: Cannot read property 'onMapOverlayCompleted' of undefined
I used the same code of the example.
My questions:
1- How can I solve this error?
2- If I want to let the user draw only polygon form, I have tried to set the value of drawingMode to "polygon" but I'm always having the other draw options (circle...). How can let only the polygon draw?
3- How can I let the user clear the drawn polygon?
4- Is it possible to detect the action of putting (drawing) every points. I mean that to draw a line in the polygon for example I need at least two points. Can I detect when the user draw the first point then the second and get its coordinates?
Edit
This is the whole error that I see when I include ng-map.js instead of ng-map.min.js :
Uncaught TypeError: Cannot read property 'onMapOverlayCompleted' of undefined
at index (http://localhost:8080/bower_components/ngmap/build/scripts/ng-map.js:2690:44)
at Array.reduce (native)
at Uw.<anonymous> (http://localhost:8080/bower_components/ngmap/build/scripts/ng-map.js:2691:39)
at P4._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at P4.<anonymous> (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:37:81)
at C4._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at C4.<anonymous> (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:37:81)
at Object._.z.trigger (https://maps.google.com/maps/api/js?key=MY_API_KEY&libraries=placeses,visualization,drawing,geometry,places:99:121)
at F4 (https://maps.google.com/maps-api-v3/api/js/28/14/drawing_impl.js:7:70)
at G4 (https://maps.google.com/maps-api-v3/api/js/28/14/drawing_impl.js:4:249)
Edit 2
I solved the first question:
My problem was that I'm using routes in the app.js. So the html and the controller are linked in it. To solve the problem, I put $scope.onMapOverlayCompleted instead of
var vm = this;
vm.onMapOverlayCompleted because I don't write the the ng-controller="DrawingManagerCtrl as vm" in my HTML. Then in the HTML I put on-overlaycomplete="onMapOverlayCompleted()" and it works.
I solved also the second question by using:
drawing-control-options="{position: 'TOP_CENTER',drawingModes:['polygon']}"
I'm want now to solve the other problems.
Any help please?
3
As the example you referenced shows, the overlaycomplete callback function receives e (Event) as the first parameter. This OverlayCompleteEvent object contains reference to the drawn overlay at Event.overlay (see docs of the original Google Maps JS API more info, since ng-map is only wrapper of the original API after all, specifically "OverlayCompleteEvent object specification" section).
Using that you can get the reference to the created overlay, store it and then later call .setMap(null) on it to delete it from map. E.g:
$scope.myDrawnOverlays = []; //array where you store drawn overlays
$scope.onMapOverlayCompleted(e){
...
myDrawnOverlays.push(e.overlay); //store reference to the drawn overlay after it's drawn
}
$scope.deleteAllDrawnOverlays(){
for(var i = 0; i < myDrawnOverlays.length; i++){
myDrawnOverlays[i].setMap(null); //remove overlays from map one by one
}
myDrawnOverlays = [];
}
Then whenever you want to delete all overlays, just call the function $scope.deleteAllDrawnOverlays (you can tie it to some button using ng-click or do whatever you want with it).
4
This is NOT possible using google.maps.drawing.DrawingManager which is used in your example. The reason is that DrawingManager doesn't support events for clicking at the map while drawing (see docs again for possible events, section "DrawingManager class").
So except hacky workarounds which could break any time with new api release, the only possible solution is to implement drawing of polygon yourself and not use DrawingManager. Check for example this SO answer, specifically the referenced example (right-clicks on map). They don't use ng-map, but basically what would you have to do is to add on-click="mapClickHandler" to your ng-map, in the mapClickHandler get position where you clicked on map, draw Marker there which would look like a dot and if you have more dots connect them with lines.
This is however too much for one question, you would have to probably read up on ng-map and relevant sections of Google Maps Js Api yourself.
I am making an 2d rpg game with box2d. So, I've got a problem. When one of my bodies(the character) collides with another(a door) the map needs to change, should I just create new screens for maps and change them? Or is there a more simple solution?
You can change your current map on the same screen only. What you have to do is, Let's say your map variable name is testMap. Now let's say your player just collided with a door. Now let's say you will call a method called changeMap(). Here is what you will put inside changeMap() method. (Assuming you are using tiled maps, you can change logic accordingly here)
void changeMap() {
Gdx.app.postRunnable(() -> { //Post runnable posts the below task in opengl thread
testMap = new TmxMapLoader().load("someMap.tmx"); //load the new map
renderer.getMap().dispose(); //dispose the old map
renderer.setMap(testMap); //set the map in your renderer
});
}
I am trying to use draw feature of openlayer (polygon). It is possible for the end user to draw a polygon. But I want to draw the polygon through java script. I am trying to use insertXY and insertDeltaXY functions of openlayer, but there comes a js error "Object doesn't support property or method 'insertXY'".
Follow is my chunk of code.
var draw = new OpenLayers.Control.DrawFeature(
vectorLayer,
OpenLayers.Handler.Polygon }
);
map.addControl(draw);
draw.activate();
//Listen for sketch events on the layer
draw.layer.events.on({
featureadded: that.PolygonAdded
});
//Draw polygon if provided from codebehind
//Insert a point in the current sketch given x & y coordinates
handler.insertXY(cords[0], cords[1]);
//Insert a point given offsets from the previously inserted point.
handler.insertDeltaXY(cords[2], cords[3]);
handler.insertDeltaXY(cords[4], cords[5]);
.....
Any help is highly appreciated.
Try using the draw object to insert points. According to the OpenLayers documentation
the OpenLayers.Control.DrawFeature exposes the methods insertXY and insertDeltaXY. I don't know if your handler object has these methods.
//Insert a point in the current sketch given x & y coordinates
draw.insertXY(cords[0], cords[1]);