Skip to content

Commit

Permalink
Add ne and sw to bounds object (#287)
Browse files Browse the repository at this point in the history
* Add ne and sw to bounds object

* Add ability to use ne and sw in fitBounds

* Return all corners from fitBounds

* Remove exports object in favour export
  • Loading branch information
sleekybadger authored and istarkov committed Nov 30, 2016
1 parent 409db3f commit 7a9a8d3
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 111 deletions.
21 changes: 17 additions & 4 deletions README.md
Expand Up @@ -50,7 +50,7 @@ UMD AMD and other build are available under dist folder after `npm install`

## What's it Look Like?

In the simple case you just need to add `lat` `lng` props to any child of `GoogleMap` component.
In the simple case you just need to add `lat` `lng` props to any child of `GoogleMap` component.
[simple example in action](http://istarkov.github.io/google-map-react/map/simple)

```javascript
Expand Down Expand Up @@ -318,6 +318,19 @@ const bounds = {
}
};

// Or

const bounds = {
ne: {
lat: 50.01038826014866,
lng: -118.6525866875
},
sw: {
lat: 32.698335045970396,
lng: -92.0217273125
}
};

const size = {
width: 640, // Map width in pixels
height: 380, // Map height in pixels
Expand Down Expand Up @@ -430,10 +443,10 @@ function createMapOptions() {

---

(*Really big thanks to [April Arcus](https://github.com/AprilArcus) for documentation fixes*)
(*thank you [Dan Abramov](http://gaearon.github.io/react-dnd/) for titles structure*)
(*Really big thanks to [April Arcus](https://github.com/AprilArcus) for documentation fixes*)
(*thank you [Dan Abramov](http://gaearon.github.io/react-dnd/) for titles structure*)
(*great thanks to [Vladimir Akimov](https://github.com/b2whats) he knows why*)

## License

MIT (http://www.opensource.org/licenses/mit-license.php)
MIT (http://www.opensource.org/licenses/mit-license.php)
16 changes: 16 additions & 0 deletions src/google_map.js
Expand Up @@ -899,6 +899,14 @@ export default class GoogleMap extends Component {
lat: bounds[2],
lng: bounds[3],
},
sw: {
lat: bounds[4],
lng: bounds[5],
},
ne: {
lat: bounds[6],
lng: bounds[7],
},
},
marginBounds: {
nw: {
Expand All @@ -909,6 +917,14 @@ export default class GoogleMap extends Component {
lat: marginBounds[2],
lng: marginBounds[3],
},
sw: {
lat: marginBounds[4],
lng: marginBounds[5],
},
ne: {
lat: marginBounds[6],
lng: marginBounds[7],
},
},

size: this.geoService_.hasSize()
Expand Down
6 changes: 4 additions & 2 deletions src/utils/geo.js
Expand Up @@ -97,8 +97,10 @@ export default class Geo {
});

let res = [
topLeftCorner.lat, topLeftCorner.lng,
bottomRightCorner.lat, bottomRightCorner.lng,
topLeftCorner.lat, topLeftCorner.lng, // NW
bottomRightCorner.lat, bottomRightCorner.lng, // SE
bottomRightCorner.lat, topLeftCorner.lng, // SW
topLeftCorner.lat, bottomRightCorner.lng, // NE
];

if (roundFactor) {
Expand Down
246 changes: 141 additions & 105 deletions src/utils/utils.js
Expand Up @@ -63,111 +63,147 @@ function meters2WorldSize(meters, { lat, lng }) {
return { w, h };
}

const exports = {
fitBounds({ nw, se }, { width, height }) {
const EPS = 0.000000001;
const nwWorld = latLng2World(nw);
const seWorld = latLng2World(se);
const dx = nwWorld.x < seWorld.x
? seWorld.x - nwWorld.x
: (1 - nwWorld.x) + seWorld.x;
const dy = seWorld.y - nwWorld.y;

if (dx <= 0 && dy <= 0) {
return null;
}
function fitNwSe(nw, se, width, height) {
const EPS = 0.000000001;
const nwWorld = latLng2World(nw);
const seWorld = latLng2World(se);
const dx = nwWorld.x < seWorld.x
? seWorld.x - nwWorld.x
: (1 - nwWorld.x) + seWorld.x;
const dy = seWorld.y - nwWorld.y;

if (dx <= 0 && dy <= 0) {
return null;
}

const zoomX = log2(width / GOOGLE_TILE_SIZE / dx);
const zoomY = log2(height / GOOGLE_TILE_SIZE / dy);
const zoom = Math.floor(EPS + Math.min(zoomX, zoomY));

// TODO find center just unproject middle world point
const middle = {
x: nwWorld.x < seWorld.x // eslint-disable-line
? 0.5 * (nwWorld.x + seWorld.x)
: nwWorld.x + seWorld.x - 1 > 0
? 0.5 * (nwWorld.x + seWorld.x - 1)
: 0.5 * (1 + nwWorld.x + seWorld.x),
y: 0.5 * (nwWorld.y + seWorld.y),
};

const zoomX = log2(width / GOOGLE_TILE_SIZE / dx);
const zoomY = log2(height / GOOGLE_TILE_SIZE / dy);
const zoom = Math.floor(EPS + Math.min(zoomX, zoomY));

// TODO find center just unproject middle world point
const middle = {
x: nwWorld.x < seWorld.x // eslint-disable-line
? 0.5 * (nwWorld.x + seWorld.x)
: nwWorld.x + seWorld.x - 1 > 0
? 0.5 * (nwWorld.x + seWorld.x - 1)
: 0.5 * (1 + nwWorld.x + seWorld.x),
y: 0.5 * (nwWorld.y + seWorld.y),
};

const scale = Math.pow(2, zoom);
const halfW = width / scale / GOOGLE_TILE_SIZE / 2;
const halfH = height / scale / GOOGLE_TILE_SIZE / 2;

const newNW = world2LatLng({
x: middle.x - halfW,
y: middle.y - halfH,
});

const newSE = world2LatLng({
x: middle.x + halfW,
y: middle.y + halfH,
});

return {
center: world2LatLng(middle),
zoom,
newBounds: {
nw: newNW,
se: newSE,
},
};
},

// -------------------------------------------------------------------
// Helpers to calc some markers size

meters2ScreenPixels(meters, { lat, lng }, zoom) {
const { w, h } = meters2WorldSize(meters, { lat, lng });
const scale = Math.pow(2, zoom);
const wScreen = w * scale * GOOGLE_TILE_SIZE;
const hScreen = h * scale * GOOGLE_TILE_SIZE;
return {
w: wScreen,
h: hScreen,
};
},

// --------------------------------------------------
// Helper functions for working with svg tiles, (examples coming soon)

tile2LatLng({ x, y }, zoom) {
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, zoom);

return ({
lat: (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))),
lng: (x / Math.pow(2, zoom) * 360 - 180),
});
},

latLng2Tile({ lat, lng }, zoom) {
const worldCoords = latLng2World({ lat, lng });
const scale = Math.pow(2, zoom);

return {
x: Math.floor(worldCoords.x * scale),
y: Math.floor(worldCoords.y * scale),
};
},

getTilesIds({ from, to }, zoom) {
const scale = Math.pow(2, zoom);

const ids = [];
for (let x = from.x; x !== (to.x + 1) % scale; x = (x + 1) % scale) {
for (let y = from.y; y !== (to.y + 1) % scale; y = (y + 1) % scale) {
ids.push([zoom, x, y]);
}
}
const scale = Math.pow(2, zoom);
const halfW = width / scale / GOOGLE_TILE_SIZE / 2;
const halfH = height / scale / GOOGLE_TILE_SIZE / 2;

const newNW = world2LatLng({
x: middle.x - halfW,
y: middle.y - halfH,
});

const newSE = world2LatLng({
x: middle.x + halfW,
y: middle.y + halfH,
});

return {
center: world2LatLng(middle),
zoom,
newBounds: {
nw: newNW,
se: newSE,
},
};
}

export function convertNeSwToNwSe({ ne, sw }) {
return {
nw: {
lat: ne.lat,
lng: sw.lng,
},
se: {
lat: sw.lat,
lng: ne.lng,
},
};
}

export function convertNwSeToNeSw({ nw, se }) {
return {
ne: {
lat: nw.lat,
lng: se.lng,
},
sw: {
lat: se.lat,
lng: nw.lng,
},
};
}

return ids;
},
};
export function fitBounds({ nw, se, ne, sw }, { width, height }) {
let fittedData;

export const fitBounds = exports.fitBounds;
export const meters2ScreenPixels = exports.meters2ScreenPixels;
export const tile2LatLng = exports.tile2LatLng;
export const latLng2Tile = exports.latLng2Tile;
export const getTilesIds = exports.getTilesIds;
// export default exports;
if (nw && se) {
fittedData = fitNwSe(nw, se, width, height);
} else {
const calculatedNwSe = convertNeSwToNwSe({ ne, sw });
fittedData = fitNwSe(calculatedNwSe.nw, calculatedNwSe.se, width, height);
}

return {
...fittedData,
newBounds: {
...fittedData.newBounds,
...convertNwSeToNeSw(fittedData.newBounds),
},
};
}

// -------------------------------------------------------------------
// Helpers to calc some markers size

export function meters2ScreenPixels(meters, { lat, lng }, zoom) {
const { w, h } = meters2WorldSize(meters, { lat, lng });
const scale = Math.pow(2, zoom);
const wScreen = w * scale * GOOGLE_TILE_SIZE;
const hScreen = h * scale * GOOGLE_TILE_SIZE;
return {
w: wScreen,
h: hScreen,
};
}

// --------------------------------------------------
// Helper functions for working with svg tiles, (examples coming soon)

export function tile2LatLng({ x, y }, zoom) {
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, zoom);

return ({
lat: (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))),
lng: (x / Math.pow(2, zoom) * 360 - 180),
});
}

export function latLng2Tile({ lat, lng }, zoom) {
const worldCoords = latLng2World({ lat, lng });
const scale = Math.pow(2, zoom);

return {
x: Math.floor(worldCoords.x * scale),
y: Math.floor(worldCoords.y * scale),
};
}

export function getTilesIds({ from, to }, zoom) {
const scale = Math.pow(2, zoom);

const ids = [];
for (let x = from.x; x !== (to.x + 1) % scale; x = (x + 1) % scale) {
for (let y = from.y; y !== (to.y + 1) % scale; y = (y + 1) % scale) {
ids.push([zoom, x, y]);
}
}

return ids;
}

0 comments on commit 7a9a8d3

Please sign in to comment.