2D Array Not Translating to D3 Map Coordinates - javascript

The 2D array I created is not accepted by D3.js as coordinates (The map example I'm using is at http://bl.ocks.org/phil-pedruco/6522279.)
Here are the facts:
1.) The JSON input I am supplied with is a string of latitude and longitude (e.g. "37.3879 -134.96376").
2.) The output required is a 2D array that must be in this form [[lat,long],[lat,long],...].
3.) console.log(typeof(lat)); returns that the lat and long values are indeed numbers (not strings)
4.) console.log("Coordinates: " + JSON.stringify(points)); returns [[37.3879,-134.96376],[13.5,-45],...] - which appears to be in the correct form, yet no points are displayed on the map
5.) If I hardcode the values in the array the points are displayed.
var points = [];
//var dotSpot = [[1.4440, 32.442], [12.222, 4.893]];
window.onload = function () {
getJSON();
}
function getJSON(supplierID) {
//retrieves JSON perfectly
//calls make() with Supplier data
}
function make(jdata) {
for (var i = 0; i < jdata.length; i++) {
//Splits string by space
var temp = jdata[i].latLong.split(/[ ,]+/)
//Converts lat and long strings to floats
var lat = parseFloat(temp[0]);
var long = parseFloat(temp[1]);
console.log(typeof(lat));
//Add "curr" coordinates array to "points" array
var curr = new Array(lat, long);
points.push(curr);
}
console.log("Coordinates: " + JSON.stringify(points));
}

You have specified your coordinates to be [latitude, longitude]. However, unlike many other applications D3 uses coordinates with longitude as the first value followed by latitude. From the docs:
The point must be specified as a two-element array [longitude, latitude] in degrees.
Changing you data accordingly should yield the desired rendering:
var curr = new Array(long, lat); // instead of new Array(lat, long)
points.push(curr);

Related

Project lat/long to pixels

I´m making an app for smartwatches, where I need to draw the track user is currently using. The track consists of lat/long pairs.
So far I´ve tried many functions, but with this one below I got most consistent results yet there are tracks, that got deformed, like squashed or the route was shifted.
function transformToPixels(lat, lon){
var westLongitude = boundingBox[1].toDegrees()[1];
var eastLongitude = boundingBox[0].toDegrees()[1];
var northLatitude = boundingBox[1].toDegrees()[0];
var southLatitude = boundingBox[0].toDegrees()[0];
var longitudeDiff = eastLongitude - westLongitude;
var latitudeDiff = northLatitude - southLatitude;
var xPixel = (((eastLongitude - lon) / (longitudeDiff).toDouble()) * DISPLAY_WIDTH).toNumber();
var yPixel = (((northLatitude - lat) / (latitudeDiff).toDouble()) * DISPLAY_HEIGHT).toNumber();
var result = new [2];
result[1] = xPixel - 3; //had to try/error these numbers to fit the line on the display
result[0] = yPixel + 25; //had to try/error these numbers to fit the line on the display
return result;
}
Here is the route drawn on phone from lat/long pairs:
And here is drawn on the smartwatch by projecting the same lat/long to X,Y pixels:
Then there is another route:
And here is drawn on the smartwatch by projecting the same lat/long to X,Y pixels:
Here are the GeoJsons from which I get the lat/long pairs.
This one is working fine: https://pastebin.com/1vx8S98V
This one gets deformed: https://pastebin.com/4Mt4MpEq
I don´t need meter-perfect conversion, but the shape of the route shouldn´t be changed.

How to get map.getBounds() as a list of 4 floats?

I'd like to get the coordinates of map bounds as a list of 4 floats (i.e. two points in latitude/longitude coordinates).
This (Google maps undocumented feature) used to work until a few days ago:
var b = map.getBounds();
var bounds = [b.H.H, b.H.j, b.j.j, b.j.H];
It doesn't work anymore. How to get these 4 floats ?
function getRectFromBounds(bounds) {
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
return [ne.lat(), ne.lng(), sw.lat(), sw.lng()];
};
var rect = getRectFromBounds(map.getBounds());
you can extend LatLngBounds and create a utility function to return this array, something like map.getBounds().toRect()

How do I enlarge LatLngBounds box using LatLng data

I get the current bounds of a google map by calling:
map.getBounds()
This will return LatLngBounds. For example:
((-26.574013562724005, -1.5375947819336488), (-25.230016040794602, 3.735842718066351))
Is it possible to get the the new LatLng points if I want to increase the map bounds by a percentage (e.g. 1%) around the centre of the map.
I have tried multiplying every coordinate by 1.01 but this shifts the map and does not increase the bounds.
I want to use the increased box size to start caching markers, in order to save calls to the server when the user pans or zooms out.
The image below will explain better what needs to happen:
Based on markerclusterer getExtendedBounds function you could use this one:
function getExtendedBounds(map, overlay) {
//With _mapBoundsEnlargePixels we add some extra space surrounding the map
//change this value until you get the desired size
var _mapBoundsEnlargePixels = 500;
var projection = overlay.getProjection();
var bounds = angular.copy(map.getBounds());
// Turn the bounds into latlng.
var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
bounds.getNorthEast().lng());
var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
bounds.getSouthWest().lng());
// Convert the points to pixels and extend out
var trPix = projection.fromLatLngToDivPixel(tr);
trPix.x = trPix.x + _mapBoundsEnlargePixels;
trPix.y = trPix.y - _mapBoundsEnlargePixels;
var blPix = projection.fromLatLngToDivPixel(bl);
blPix.x = blPix.x - _mapBoundsEnlargePixels;
blPix.y = blPix.y + _mapBoundsEnlargePixels;
// Convert the pixel points back to LatLng
var ne = projection.fromDivPixelToLatLng(trPix);
var sw = projection.fromDivPixelToLatLng(blPix);
// Extend the bounds to contain the new bounds.
bounds.extend(ne);
bounds.extend(sw);
return bounds;
}

JavaScript fixed array or object length?

I need a way to store two values only within an array or object and limit its length to two values. The reason is that I am using a jQuery Vectormap to calculate the distance and a draw line between two coordinates x1/y1 & x2/y2.
Whenever a region/country is clicked, corresponding markers are loaded and added to the map
map.addMarker(id ,{latLng: [val.lat, val.long], name:val.name}) ; ect///
Now, whenever a marker is clicked I should be able to track count of two markers's selection and store their coordinates in an array then do the calculations..
onMarkerClick:function(e, code){
var coordinates = map.markers[code].config.latLng;
// latitude = coordinates[0]
// longitude = coordinates[1]
}
So if I were to use myArray.push([coordinates[0],coordinates[1]]) for each marker clicked then I end up with countless number of coordinates and thus making it impossible to draw my line.. Is there a way to set myArray length to 2 then when I push more values overwrite the existing one?
Thanks
If you want to be fancy about it, you can create your custom class that does this...
function CappedArray(Size)
{
this.push = function(Value) {
if(this.length==Size)
{
this.shift();
}
CappedArray.prototype.push.call(this, Value);
}
}
CappedArray.prototype = new Array();
//How you use it
var SomeArray = new CappedArray(2);
SomeArray.push([coordinates[0],coordinates[1]]);
...
Alternatively, if you want to force the fact that points should only be associated in successive pairs of insertions:
function PairArray()
{
this.push = function(Value) {
if(this.length==2)
{
this.splice(0, 2);
}
PairArray.prototype.push.call(this, Value);
}
}
PairArray.prototype = new Array();
//How you use it
var SomeArray = new PairArray();
SomeArray.push([coordinates[0],coordinates[1]]);
You could use an object like this:
var coords =
{
"c1": [x1,y1],
"c2": [x2,y2]
}
then when adding coordinates you could:
coords.c1 = coordinates[0];
coords.c2 = coordinates[1];

How do I force jsonStringify to output an array without quotes?

I am using a Google Apps script to format data from a Google spreadsheet into geoJSON by calling jsonStringify. My code is modified from this original example. Each row in the spreadsheet represents a country, with a single cell containing the relevant geoJSON polygon data:
[[[74.92,37.24],[74.57,37.03],...[73.31,37.46],[74.92,37.24]]]
But since that cell doesn't contain a number, jsonStringify is parsing it as a string, returning this:
"coordinates":["[[[74.92,37.24],[74.57,37.03],...[73.31,37.46],[74.92,37.24]]]"]
...which I can't use, since the quotes make it non-valid geoJSON. When I enter a single number, jsonStringify returns it without the quotes, I assume because it recognizes that it's a number. Is there some way I can force it to interpret the polygon data as a number or otherwise escape the quotes? Here is the relevant section of my code:
function getObjects(data, keys) {
var objects = [];
var headers = getHeaders(sheet, activeRange, 1);
var zip = function(keys, data) {
var obj = {};
for (var i = 0; i < keys.length; i++) {
obj[keys[i]] = data[i];
}
return obj;
};
for (var i = 0; i < data.length; i++) {
var obj = zip(headers, data[i]);
//this is the polygon data
var poly = obj[settings.poly];
var coordinates = [poly];
// If we have an id and polygon data
if (obj[settings.id] && poly) {
// Define a new GeoJSON feature object
var feature = {
type: 'Feature',
// Get ID from UI
id: obj[settings.id],
geometry: {
type: 'MultiPolygon',
// Get coordinates from UIr
coordinates: coordinates
},
// Place holder for properties object
properties: obj
};
objects.push(feature);
}
}
return objects;
}
Instead of passing a string to jsonStringify as the "coordinates", pass an actual array. That is, use jsonParse first on the original text (as required) to obtain the relevant object.
An example conversion (with guard that may or may not be appropriate) might look like:
function restoreCoordinatesFromText(source) {
var geo = Utilities.jsonParse(source);
return (geo && (geo instanceof Array)
? geo // looks like we got our [array of stuff]
: theSourceData); // dunno, let's act like we never saw it
}
Then later on the actual coordinate array can be encoded correctly in JSON while the string exhibits the initial undesired behavior.
var coords = "[1,2,3,4]"; /* just a string */
var json = Utilities.jsonStringify({
/* array, good! */
goodCoordinates: restoreCoordinatesFromText(coords),
/* string, bad! */
badCoordinates: coords
});
Here is the corresponding fiddle (it utilizes ES5 JSON support).

Categories