I need to place around 500,000 objects on a map in structure like <div><a><img>.
But if I place only 2,000 objects as overlay my map crashes.
What can I do?
var srcImage = 'img/catalog-6.png';
var b = 1;
var a = 1;
var bounds = [10000];
var overlay = [10000]
var good;
for(i = 1; i < 1000; i++) {
bounds[i] = new google.maps.LatLngBounds(
new google.maps.LatLng(b, b),
new google.maps.LatLng(a, a));
b = 1;
a = 1;
overlay = new firstpixel(bounds[i], srcImage, map);
good++;
console.log(i);
}
Related
So I used the solution from this thread How to draw a polygon around a polyline in JavaScript? to solve my problem that I needed to have a radius drawn along a path. However it looks lopsided, like an oval when I use this method, even though on the thread the result doesn't look like this. I'm not using directions to generate my points, I already have an array of points that I'm passing to the function
here is what it currently looks like
function drawRadius(map, path, radius, factor)
{
let radial = [];
overviewPathGeo = [];
for (var i = 0; i < path.length; i++) {
overviewPathGeo.push(
[path[i].lng, path[i].lat]
);
}
var distance = (radius/1000.0) / 111.12, // Roughly 10km
geoInput = {
type: "LineString",
coordinates: overviewPathGeo
};
var geoReader = new jsts.io.GeoJSONReader(),
geoWriter = new jsts.io.GeoJSONWriter();
var geometry = geoReader.read(geoInput).buffer(distance);
var polygon = geoWriter.write(geometry);
var oLanLng = [];
var oCoordinates;
oCoordinates = polygon.coordinates[0];
for (i = 0; i < oCoordinates.length; i++) {
var oItem;
oItem = oCoordinates[i];
oLanLng.push(new google.maps.LatLng(oItem[1], oItem[0]));
}
var polygone = new google.maps.Polygon({
paths: oLanLng,
map:map
});
radial.push(polygone);
distance = ((radius*factor)/1000.0) / 111.12, // Roughly 10km
geoInput = {
type: "LineString",
coordinates: overviewPathGeo
};
geoReader = new jsts.io.GeoJSONReader(),
geoWriter = new jsts.io.GeoJSONWriter();
geometry = geoReader.read(geoInput).buffer(distance);
polygon = geoWriter.write(geometry);
oLanLng = [];
oCoordinates;
oCoordinates = polygon.coordinates[0];
for (i = 0; i < oCoordinates.length; i++) {
var oItem;
oItem = oCoordinates[i];
oLanLng.push(new google.maps.LatLng(oItem[1], oItem[0]));
}
polygone = new google.maps.Polygon({
paths: oLanLng,
map:map
});
radial.push(polygone);
return radial;
}
Good day!
Have issue with memory handling. I read lots of forums but still can't find whats wrong with my code.
I'm working on project where I combine d3.js with three.js to visualize nodes like planets on orbits in space.
I have a lot of data - like 8K planets in 8+ orbits. But when I try to load new data - I can't destroy current tree without memory leak.
I would be grateful for any help! Here is part of code where I create planets and where I try to destroy them:
function initTree(root) {
var start, end;
var nodes = tree.nodes(root); //this is d3.js tree init
var depth = getDepth(root);
var first_x_offset = nodes[0].x;
if (isNaN(first_x_offset)) {first_x_offset = 0}
//create orbits
var orbitTexture = new THREE.ImageUtils.loadTexture('img/orbit_texture.png');
var orbitMaterial = new THREE.MeshBasicMaterial({map: orbitTexture, transparent:true, side: THREE.DoubleSide, alphaTest: 0.05, opacity:0.3});
var sphereGeometry = new THREE.SphereGeometry(1, 6, 6);
var orbitSize = 30;
for (var k=1; k<depth; k++) {
var orbit = new THREE.Mesh(new THREE.CircleGeometry(orbitSize*k, 64), orbitMaterial);
orbit.rotation.x = -90*Math.PI/180;
orbit.name = 'orbit';
scene.add(orbit);
}
//end orbits
//camera position
camera.position.x = 0;
camera.position.y = 70;
camera.position.z = -orbitSize*depth-100;
controls.target.x = 0;
controls.target.y = 0;
controls.target.z = 0;
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
//this is parent object to place in center
var parent = new THREE.Object3D();
parent.name = 'parent';
scene.add(parent);
y=0;
spheres = {};
objects = [];
nodes.forEach(function(d) {
if (d.type == 'BLANK') {return}
d.x = d.x - first_x_offset;
if (isNaN(d.x)) {d.x = 0}
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xdddddd, wireframe: false, opacity: 0.7, transparent: true});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial );
sphere.material.color.setHex(color_type[d.type]);
sphere.castShadow = false; //maybe change to true
sphere.id2 = y;
d.id2 = y;
sphere.d = d;
sphere.scale.x = radius_type[d.type];
sphere.scale.y = radius_type[d.type];
sphere.scale.z = radius_type[d.type];
sphere.name = 'sphere';
spheres[y] = sphere;
//count items of each type
count_type[d.type]++;
//how many nodes in tree
y++;
//create pivot
var pivot = new THREE.Object3D;
//rotate it
pivot.rotation.y = d.x*Math.PI/180-90;
//append to parent
pivot.name = 'pivot';
parent.add(pivot);
//add mesh to pivot
var default_distance = size/(depth-1);
if (d.y > 0) {
d.y = (Math.round(d.y/default_distance)) * (orbitSize-8.8);
}
sphere.position.x = d.y;
sphere.position.y = 0; //should be 0!
sphere.position.z = d.y;
objects.push(sphere);
pivot.add(sphere);
});
nodesLength = y;
render();
$('.loading').fadeOut(500);
if (!animationId) {
animate();
}
temp = null;
nodes = null;
}
So I'm adding spheres to parent Object3D and then add it to scene.
And here is destroy function:
function destroyTree() {
//spheres
//console.log(renderer.info);
var to_delete = [];
for (var i=0; i<spheres.length; i++) {
scene.remove(spheres[i]);
spheres[i].material.dispose();
spheres[i].geometry.dispose();
}
for (var i=0; i<spheres.length; i++) {
spheres[i] = undefined;
}
spheres = {};
for (var i=0; i<objects.length; i++) {
scene.remove(objects[i]);
}
for (var i=0; i<objects.length; i++) {
objects[i] = undefined;
}
objects = [];
var parent = scene.getObjectByName('parent');
scene.remove(parent);
if (links.length) {
for (var i=0; i<links.length; i++) {
scene.remove(links[i]);
}
}
links = [];
scene.traverse(function (child) {
if (child instanceof THREE.Mesh) {
if (child.name.length) {
to_delete.push(child);
}
}
});
for (var i=0; i<to_delete.length; i++) {
scene.remove(to_delete[i]);
to_delete[i].geometry.dispose();
to_delete[i].material.dispose();
to_delete[i] = undefined;
}
to_delete = [];
}
Wouldn't traversing the scene find the spheres too? And in that loop you could dispose directly without need for the to_delete array. If all speres are not children of the scene then maybe reconsider when to create them? These would just be optimizations and probably do little other then clarify where it might be leaking.
Then again maybe try holding an array of textures and releasing those directly?
Wait here it is, this link says to remove the objects and textures from the renderer as well.
Memory leak in Three.js
renderer.deallocateObject
renderer.deallocateTexture
I'm using the Google Maps API to embed a map in a web page. The map fills the entire screen, but there's ~400px worth of content on the left side of the screen that mostly covers the map. When I want to pan the map, that area to the left should be treated as though it isn't visible.
I came up with the following code to calculate the "usable part" of the map, which I'd like to be 50px in from the map's edge, and should also avoid the 400px area to the left side of the map:
panIfNotClose = function(latLngs){
if(latLngs.length === 0)
return;
// Get some important values that may not be available yet
// http://stackoverflow.com/a/2833015/802335
var bounds = map.getBounds();
if(!bounds)
return setTimeout(panIfNotClose.bind(this, latLngs), 10);
var overlay = new google.maps.OverlayView();
overlay.draw = function(){};
overlay.setMap(map);
var proj = overlay.getProjection();
if(!proj)
return setTimeout(panIfNotClose.bind(this, latLngs), 10);
// Calculate the "usable part" of the map
var center = bounds.getCenter();
var northEast = bounds.getNorthEast();
var southWest = bounds.getSouthWest();
var northEastPx = proj.fromLatLngToContainerPixel(northEast);
var southWestPx = proj.fromLatLngToContainerPixel(southWest);
var menuPadding = 400;
var newNorthEastPx = new google.maps.Point(northEastPx.x + 50, northEastPx.y + 50);
var newSouthWestPx = new google.maps.Point(southWestPx.x - (50 + menuPadding), southWestPx.y - 50);
var newNorthEast = proj.fromContainerPixelToLatLng(newNorthEastPx);
var newSouthWest = proj.fromContainerPixelToLatLng(newSouthWestPx);
var centerBounds = new google.maps.LatLngBounds(newSouthWest, newSouthWest);
// Decide if any of the new LatLngs are far enough away that the map should move
var shouldMove = false;
var targetBounds = new google.maps.LatLngBounds();
for(var i = 0; i < latLngs.length; i++){
targetBounds.extend(latLngs[i]);
if(!centerBounds.contains(latLngs[i]))
shouldMove = true;
}
// If the LatLngs aren't all near the center of the map, pan to it
if(latLngs.length === 1){
if(shouldMove || map.getZoom() !== 18)
map.panTo(latLngs[0]);
map.setZoom(18);
}else{
var targetZoom = Math.min(getBoundsZoomLevel(targetBounds), 18);
if(shouldMove || map.getZoom() !== targetZoom)
map.panTo(targetBounds.getCenter());
map.setZoom(targetZoom);
}
}
This code should test the "valid" area to make sure all the given LatLngs fit inside, but it doesn't yet make any changes to panTo to "move" the center 200px to the right to account for the 400px worth of content on the left.
The code doesn't work as I intended, but I'm not sure why. I suspect I'm probably doing something wrong when converting from a LatLng to a Point or vice-versa. I may also be doing far more work than is necessary, although I can't think of a way to simplify it.
This turned out to be a pretty simple mistake. In the line var centerBounds = new google.maps.LatLngBounds(newSouthWest, newSouthWest);, I accidentally used the same LatLng twice, rather than the northeast and southwest corners. I also had a couple simple arithmetic issues when calculating newNorthEastPx and newSouthWestPx. Drawing a google.maps.Rectangle using centerBounds helped work that out quickly and easily. For anyone interested, here's the end result:
function panIfNotClose(latLngs, zoomOnly){
if(latLngs.length === 0)
return;
if(typeof latLngs !== "object")
latLngs = [latLngs];
// Calculate the "middle half" of the map
var bounds = map.getBounds();
if(!bounds) // http://stackoverflow.com/a/2833015/802335
return setTimeout(panIfNotClose.bind(this, latLngs, zoomOnly), 10);
var overlay = new google.maps.OverlayView();
overlay.draw = function(){};
overlay.setMap(map);
var proj = overlay.getProjection();
if(!proj)
return setTimeout(panIfNotClose.bind(this, latLngs, zoomOnly), 10);
var center = bounds.getCenter();
var northEast = bounds.getNorthEast();
var southWest = bounds.getSouthWest();
var northEastPx = proj.fromLatLngToContainerPixel(northEast);
var southWestPx = proj.fromLatLngToContainerPixel(southWest);
var menuPadding = 0;
if($navBar.css("display") !== "none")
menuPadding = 400;
var newNorthEastPx = new google.maps.Point(northEastPx.x - 100, northEastPx.y + 100);
var newSouthWestPx = new google.maps.Point(southWestPx.x + (100 + menuPadding), southWestPx.y - 100);
var newNorthEast = proj.fromContainerPixelToLatLng(newNorthEastPx);
var newSouthWest = proj.fromContainerPixelToLatLng(newSouthWestPx);
centerBounds = new google.maps.LatLngBounds(newSouthWest, newNorthEast);
var shouldMove = false;
var targetBounds = new google.maps.LatLngBounds();
for(var i = 0; i < latLngs.length; i++){
targetBounds.extend(latLngs[i]);
if(!centerBounds.contains(latLngs[i]))
shouldMove = true;
}
// If the marker isn't near the center of the map, pan to it
if(latLngs.length === 1){
if(!zoomOnly && (shouldMove || map.getZoom() !== 18))
map.panTo(correctCenter(latLngs[0], proj));
map.setZoom(18);
}else{
var targetZoom = Math.min(getBoundsZoomLevel(targetBounds), 18);
if(!zoomOnly && (shouldMove || map.getZoom() !== targetZoom))
map.panTo(correctCenter(targetBounds.getCenter(), proj));
map.setZoom(targetZoom);
}
}
function correctCenter(latLng, proj){
// $navBar references a jQuery pointer to a DOM element
if($navBar.css("display") === "none")
return latLng;
var latLngPx = proj.fromLatLngToContainerPixel(latLng);
var newLatLngPx = new google.maps.Point(latLngPx.x - 200, latLngPx.y)
return proj.fromContainerPixelToLatLng(newLatLngPx);
}
// Adapted from http://stackoverflow.com/a/13274361/802335
function getBoundsZoomLevel(bounds){
// $mapCanvas is a jQuery reference to the div containing the Google Map
var mapDim = {
width: $mapCanvas.width() * .6,
height: $mapCanvas.height() * .6
};
var ZOOM_MAX = 18;
function latRad(lat){
var sin = Math.sin(lat * Math.PI / 180);
var radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
function zoom(mapPx, fraction){
return Math.floor(Math.log(mapPx / 256 / fraction) / Math.LN2);
}
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
var latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;
var lngDiff = ne.lng() - sw.lng();
var lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360;
var latZoom = zoom(mapDim.height, latFraction);
var lngZoom = zoom(mapDim.width, lngFraction);
return Math.min(latZoom, lngZoom, ZOOM_MAX);
}
I extend a polygon shape on the client. Please see my question (How to evenly adjust some area to polygon (extend a polygon)?) to understand what I exactly mean. I do all the calculations in browser and then send a result to server and store it in DB. I use this function (from here):
this.extendPolygon = function(polyline, offset) {
var distance = Number(offset) * 1000;
var numPts = polyline.getPath().getLength();
var bounds = new google.maps.LatLngBounds();
for (var i=0; i< numPts; i++) {
bounds.extend(polyline.getPath().getAt(i));
}
var center = bounds.getCenter();
var extendedPolyPts = [];
for (var i=0; i< numPts; i++) {
var heading = google.maps.geometry.spherical.computeHeading(center,polyline.getPath().getAt(i));
var initialDist = google.maps.geometry.spherical.computeDistanceBetween(center,polyline.getPath().getAt(i));
var extendedDist = initialDist + distance;
var extendedPt = google.maps.geometry.spherical.computeOffset(center, extendedDist, heading);
extendedPolyPts.push(extendedPt);
}
extendedPoly = new google.maps.Polygon({
// map: map,
paths:extendedPolyPts,
fillColor:"#00FF00",
strokeWidth:2,
fillOpacity:0.4,
strokeColor:"#0000FF",
strokeOpacity:0.5
});
return extendedPoly;
};
But I'd like to do calculations on a server side. Is it possible to run the function on a server? It uses these functions of GM API:
google.maps.geometry.spherical.computeHeading
google.maps.LatLngBounds
polyline.getPath().getLength()
google.maps.geometry.spherical.computeDistanceBetween
google.maps.geometry.spherical.computeOffset
google.maps.Polygon
I've made the code so that I get yellow points on my map, the coords and some other facts is loaded from a external file.
Here's the resource file
var sites = [{id:1269209,geometry:{ type:"Point",lat:1,lon: 1},properties:{siteName:"Yttern",parentId:1269209,siteType:2}}];
And here's the script for viewing them
var vectorLayer = new OpenLayers.Layer.Vector("Overlay");
$.getScript('test.js',function(){
for(var i = 0; i < sites.length; i++)
{
var site = sites[i];
var feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(site.geometry.lon,site.geometry.lat));
vectorLayer.addFeatures(feature);
}
map.addLayer(vectorLayer);
});
The thing I woundering about is how do I do to make a hoverable popup for each marker, with the content from the JSON file?
Is it also possible to make the request only when the user have passed zoom level 14?
Now, I've fixed the function that starts when zoom passed 10
map.events.register("moveend", null, function(){
if(map.zoom >= 10)
{
var bounds = map.getExtent();
var ne = new OpenLayers.LonLat(bounds.right,bounds.top).transform(map.getProjectionObject(),new OpenLayers.Projection("EPSG:4326"));
var sw = new OpenLayers.LonLat(bounds.left,bounds.bottom).transform(map.getProjectionObject(),new OpenLayers.Projection("EPSG:4326"));
var vectorLayer = new OpenLayers.Layer.Vector("Layer");
$.getScript('ajax.php?a=markers&type=javascript&sw=('+sw.lon+','+sw.lat+')&ne=('+ne.lon+','+ne.lat+')',function(){
//$.getScript('test.js',function(){
for(var i = 0; i < sites.length; i++)
{
var site = sites[i];
var latlon = new OpenLayers.LonLat(site.geo.lon,site.geo.lat);
var feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(latlon)
);
vectorLayer.addFeatures(feature);
}
map.addLayer(vectorLayer);
});
}
});
but still I dont get the markers on the map, is something wrong?
One result from markers.php aka ajax.php?a=markers....
var sites = [{siteId:'9',siteName:'HĂ„rleby',geo:{lon:11.641452694427471,lat:58.15782686109065},fact:{parentSiteId:0,county:'Orust'}}];
is it the projection on the result maybe? Please help.