Created
January 22, 2026 19:01
-
-
Save gregsadetsky/c4c1a87277063430c26922b1ad0b6e86 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // use this with https://cannoneyed.com/isometric-nyc/ | |
| // paste the code below in your devtools -- the very last line is `jumpToLatLng(... | |
| // set the coordinates passed to that function to a lat lng near/in NYC | |
| // the iso map will reload at those coordinates! | |
| // ---------------- | |
| // bonus: you can also see the debug view https://cannoneyed.com/isometric-nyc/?debug=true :-) | |
| // congrats&thanks to andy coenen for the original iso map! | |
| // credit: iso javascript reverse engineered by gemini 3.5 pro :-P | |
| // --- CONFIGURATION --- | |
| // We need 3 points to solve the Isometric distortion perfectly. | |
| // I've added your Times Square values as the 3rd point (p3). | |
| const calib = { | |
| p1: { | |
| pixel: { x: 52548, y: 64928 }, | |
| geo: { lat: 40.75145020893891, lng: -73.9596826628078 } | |
| }, | |
| p2: { | |
| pixel: { x: 40262, y: 51982 }, | |
| geo: { lat: 40.685498640229675, lng: -73.98074283976926 } | |
| }, | |
| p3: { // Times Square (Used to triangulate the isometric squash) | |
| pixel: { x: 45916, y: 67519 }, | |
| geo: { lat: 40.757903901085726, lng: -73.98557060196454 } | |
| } | |
| }; | |
| // --- MATH SOLVER (Affine Transform) --- | |
| // Solves: Pixel = A * lat + B * lng + C | |
| function getAffineTransform() { | |
| const { p1, p2, p3 } = calib; | |
| // We solve for X and Y coefficients independently | |
| // System of equations for X: | |
| // x1 = A*lat1 + B*lng1 + C | |
| // x2 = A*lat2 + B*lng2 + C | |
| // x3 = A*lat3 + B*lng3 + C | |
| // Determinant of the coefficient matrix | |
| const det = p1.geo.lat * (p2.geo.lng - p3.geo.lng) - | |
| p2.geo.lat * (p1.geo.lng - p3.geo.lng) + | |
| p3.geo.lat * (p1.geo.lng - p2.geo.lng); | |
| if (det === 0) { console.error("Points are collinear, cannot solve."); return null; } | |
| // Solve for X coefficients (Ax, Bx, Cx) | |
| const Ax = ((p1.pixel.x * (p2.geo.lng - p3.geo.lng)) - | |
| (p2.pixel.x * (p1.geo.lng - p3.geo.lng)) + | |
| (p3.pixel.x * (p1.geo.lng - p2.geo.lng))) / det; | |
| const Bx = ((p1.geo.lat * (p2.pixel.x - p3.pixel.x)) - | |
| (p2.geo.lat * (p1.pixel.x - p3.pixel.x)) + | |
| (p3.geo.lat * (p1.pixel.x - p2.pixel.x))) / det; | |
| const Cx = ((p1.geo.lat * ((p2.geo.lng * p3.pixel.x) - (p3.geo.lng * p2.pixel.x))) - | |
| (p2.geo.lat * ((p1.geo.lng * p3.pixel.x) - (p3.geo.lng * p1.pixel.x))) + | |
| (p3.geo.lat * ((p1.geo.lng * p2.pixel.x) - (p2.geo.lng * p1.pixel.x)))) / det; | |
| // Solve for Y coefficients (Ay, By, Cy) | |
| const Ay = ((p1.pixel.y * (p2.geo.lng - p3.geo.lng)) - | |
| (p2.pixel.y * (p1.geo.lng - p3.geo.lng)) + | |
| (p3.pixel.y * (p1.geo.lng - p2.geo.lng))) / det; | |
| const By = ((p1.geo.lat * (p2.pixel.y - p3.pixel.y)) - | |
| (p2.geo.lat * (p1.pixel.y - p3.pixel.y)) + | |
| (p3.geo.lat * (p1.pixel.y - p2.pixel.y))) / det; | |
| const Cy = ((p1.geo.lat * ((p2.geo.lng * p3.pixel.y) - (p3.geo.lng * p2.pixel.y))) - | |
| (p2.geo.lat * ((p1.geo.lng * p3.pixel.y) - (p3.geo.lng * p1.pixel.y))) + | |
| (p3.geo.lat * ((p1.geo.lng * p2.pixel.y) - (p2.geo.lng * p1.pixel.y)))) / det; | |
| return { Ax, Bx, Cx, Ay, By, Cy }; | |
| } | |
| // --- EXECUTION FUNCTION --- | |
| function jumpToLatLng(lat, lng) { | |
| const t = getAffineTransform(); | |
| if (!t) return; | |
| // Apply the matrix | |
| const rawX = t.Ax * lat + t.Bx * lng + t.Cx; | |
| const rawY = t.Ay * lat + t.By * lng + t.Cy; | |
| // Ensure Integers (OpenSeadragon can be finicky with floats in state restoration) | |
| const finalX = Math.round(rawX); | |
| const finalY = Math.round(rawY); | |
| console.log(`📍 Jumping to Geo: ${lat}, ${lng}`); | |
| console.log(`🎯 Calculated Pixel: ${finalX}, ${finalY}`); | |
| // Create the state object expected by the React app | |
| const newState = { | |
| target: [finalX, finalY, 0], | |
| zoom: 13.96 // Locks zoom to the "sharp" level | |
| }; | |
| // Save and Reload | |
| localStorage.setItem("isometric-nyc-view-state", JSON.stringify(newState)); | |
| window.location.reload(); | |
| } | |
| // Example: Go to Times Square (Should match your 45916, 67519 values perfectly now) | |
| jumpToLatLng(40.757903901085726, -73.98557060196454); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
minified version: