Skip to content

Instantly share code, notes, and snippets.

@gregsadetsky
Created January 22, 2026 19:01
Show Gist options
  • Select an option

  • Save gregsadetsky/c4c1a87277063430c26922b1ad0b6e86 to your computer and use it in GitHub Desktop.

Select an option

Save gregsadetsky/c4c1a87277063430c26922b1ad0b6e86 to your computer and use it in GitHub Desktop.
// 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);
@gregsadetsky
Copy link
Author

minified version:

    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:{pixel:{x:45916,y:67519},geo:{lat:40.757903901085726,lng:-73.98557060196454}}};function getAffineTransform(){let{p1:e,p2:l,p3:g}=calib,o=e.geo.lat*(l.geo.lng-g.geo.lng)-l.geo.lat*(e.geo.lng-g.geo.lng)+g.geo.lat*(e.geo.lng-l.geo.lng);if(0===o)return console.error("Points are collinear, cannot solve."),null;let n=(e.pixel.x*(l.geo.lng-g.geo.lng)-l.pixel.x*(e.geo.lng-g.geo.lng)+g.pixel.x*(e.geo.lng-l.geo.lng))/o,x=(e.geo.lat*(l.pixel.x-g.pixel.x)-l.geo.lat*(e.pixel.x-g.pixel.x)+g.geo.lat*(e.pixel.x-l.pixel.x))/o,i=(e.geo.lat*(l.geo.lng*g.pixel.x-g.geo.lng*l.pixel.x)-l.geo.lat*(e.geo.lng*g.pixel.x-g.geo.lng*e.pixel.x)+g.geo.lat*(e.geo.lng*l.pixel.x-l.geo.lng*e.pixel.x))/o,t=(e.pixel.y*(l.geo.lng-g.geo.lng)-l.pixel.y*(e.geo.lng-g.geo.lng)+g.pixel.y*(e.geo.lng-l.geo.lng))/o,p=(e.geo.lat*(l.pixel.y-g.pixel.y)-l.geo.lat*(e.pixel.y-g.pixel.y)+g.geo.lat*(e.pixel.y-l.pixel.y))/o,a=(e.geo.lat*(l.geo.lng*g.pixel.y-g.geo.lng*l.pixel.y)-l.geo.lat*(e.geo.lng*g.pixel.y-g.geo.lng*e.pixel.y)+g.geo.lat*(e.geo.lng*l.pixel.y-l.geo.lng*e.pixel.y))/o;return{Ax:n,Bx:x,Cx:i,Ay:t,By:p,Cy:a}}function jumpToLatLng(e,l){let g=getAffineTransform();if(!g)return;let o=g.Ax*e+g.Bx*l+g.Cx,n=g.Ay*e+g.By*l+g.Cy,x=Math.round(o),i=Math.round(n);console.log(` Jumping to Geo: ${e}, ${l}`),console.log(` Calculated Pixel: ${x}, ${i}`),localStorage.setItem("isometric-nyc-view-state",JSON.stringify({target:[x,i,0],zoom:13.95})),window.location.reload()};
    jumpToLatLng(40.757903901085726,-73.98557060196454);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment