Last active
July 12, 2024 09:44
-
-
Save twelch/d1c57227e75262b4caad556a39335702 to your computer and use it in GitHub Desktop.
Mapbox GL JS compare window circle magnifying glass
This file contains 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.46.0/mapbox-gl.js'></script> | |
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.46.0/mapbox-gl.css' rel='stylesheet' /> | |
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-compare/v0.1.0/mapbox-gl-compare.js'></script> | |
</head> | |
<body> | |
<style> | |
body { | |
overflow: hidden; | |
} | |
body * { | |
-webkit-touch-callout: none; | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
user-select: none; | |
} | |
#before { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
width: 100vw; | |
height: 100vh; | |
} | |
#after { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100vw; | |
height: 100vh; | |
margin-top: calc(-100vh / 2 + 140px); | |
margin-left: calc(-100vw / 2 + 140px) | |
/*clip-path: circle(140px at center); | |
-webkit-clip-path: circle(140px at center); | |
*/ | |
} | |
.container { | |
margin: auto; | |
position: absolute; | |
top: 0; left: 0; bottom: 0; right: 0; | |
width: 280px; | |
height: 280px; | |
border-radius: 100%; | |
overflow: hidden; | |
/* Safari overflow hidden + border-radius bug https://hk.saowen.com/a/fd38838b1554e3bc311ebabb7c4cc3d7e44d62a45ba44bc2792172c6cd76c10a */ | |
-webkit-transform: translateZ(0); | |
transform: translateZ(0); | |
} | |
.shadow { | |
margin: auto; | |
position: absolute; | |
top: 0; left: 0; bottom: 0; right: 0; | |
width: 280px; | |
height: 280px; | |
border-radius: 999px; | |
box-shadow: inset 10px 10px 19px -4px rgba(0,0,0,0.65); | |
border: 1px solid #777; | |
pointer-events: none; | |
} | |
</style> | |
<div id='before' class='map'></div> | |
<div class='container'> | |
<div id='after' class='map'></div> | |
</div> | |
<div class='shadow'></div> | |
<script> | |
function moveToMapPosition (master, clones) { | |
var center = master.getCenter(); | |
var zoom = master.getZoom(); | |
var bearing = master.getBearing(); | |
var pitch = master.getPitch(); | |
clones.forEach(function (clone) { | |
clone.jumpTo({ | |
center: center, | |
zoom: zoom, | |
bearing: bearing, | |
pitch: pitch | |
}); | |
}); | |
} | |
// Sync movements of two maps. | |
// | |
// All interactions that result in movement end up firing | |
// a "move" event. The trick here, though, is to | |
// ensure that movements don't cycle from one map | |
// to the other and back again, because such a cycle | |
// - could cause an infinite loop | |
// - prematurely halts prolonged movements like | |
// double-click zooming, box-zooming, and flying | |
function syncMaps () { | |
var maps; | |
var argLen = arguments.length; | |
if (argLen === 1) { | |
maps = arguments[0]; | |
} else { | |
maps = []; | |
for (var i = 0; i < argLen; i++) { | |
maps.push(arguments[i]); | |
} | |
} | |
// Create all the movement functions, because if they're created every time | |
// they wouldn't be the same and couldn't be removed. | |
var fns = []; | |
maps.forEach(function (map, index) { | |
fns[index] = sync.bind(null, map, maps.filter(function (o, i) { return i !== index; })); | |
}); | |
function on () { | |
maps.forEach(function (map, index) { | |
map.on('move', fns[index]); | |
}); | |
} | |
function off () { | |
maps.forEach(function (map, index) { | |
map.off('move', fns[index]); | |
}); | |
} | |
// When one map moves, we turn off the movement listeners | |
// on all the maps, move it, then turn the listeners on again | |
function sync (master, clones) { | |
off(); | |
moveToMapPosition(master, clones); | |
on(); | |
} | |
on(); | |
} | |
function Compare(a, b, options) { | |
this.options = options ? options : {}; | |
this._onDown = this._onDown.bind(this); | |
this._onMove = this._onMove.bind(this); | |
this._onMouseUp = this._onMouseUp.bind(this); | |
this._onTouchEnd = this._onTouchEnd.bind(this); | |
this._swiper = document.createElement('div'); | |
this._swiper.className = 'compare-swiper'; | |
this._container = document.createElement('div'); | |
this._container.className = 'mapboxgl-compare'; | |
this._container.appendChild(this._swiper); | |
a.getContainer().appendChild(this._container); | |
this._clippedMap = b; | |
this._bounds = b.getContainer().getBoundingClientRect(); | |
// this._setPosition(this._bounds.width / 2); | |
syncMaps(a, b); | |
/* b.on('resize', function() { | |
this._bounds = b.getContainer().getBoundingClientRect(); | |
if (this._x) this._setPosition(this._x); | |
}.bind(this)); */ | |
if (this.options && this.options.mousemove) { | |
a.getContainer().addEventListener('mousemove', this._onMove); | |
b.getContainer().addEventListener('mousemove', this._onMove); | |
} | |
this._swiper.addEventListener('mousedown', this._onDown); | |
this._swiper.addEventListener('touchstart', this._onDown); | |
} | |
Compare.prototype = { | |
_setPointerEvents: function(v) { | |
this._container.style.pointerEvents = v; | |
this._swiper.style.pointerEvents = v; | |
}, | |
_onDown: function(e) { | |
if (e.touches) { | |
document.addEventListener('touchmove', this._onMove); | |
document.addEventListener('touchend', this._onTouchEnd); | |
} else { | |
document.addEventListener('mousemove', this._onMove); | |
document.addEventListener('mouseup', this._onMouseUp); | |
} | |
}, | |
_setPosition: function(x) { | |
var pos = 'translate(' + x + 'px, 0)'; | |
this._container.style.transform = pos; | |
this._container.style.WebkitTransform = pos; | |
this._clippedMap.getContainer().style.clip = 'rect(0, 999em, ' + this._bounds.height + 'px,' + x + 'px)'; | |
this._x = x; | |
}, | |
_onMove: function(e) { | |
if (this.options && this.options.mousemove) { | |
this._setPointerEvents(e.touches ? 'auto' : 'none'); | |
} | |
this._setPosition(this._getX(e)); | |
}, | |
_onMouseUp: function() { | |
document.removeEventListener('mousemove', this._onMove); | |
document.removeEventListener('mouseup', this._onMouseUp); | |
}, | |
_onTouchEnd: function() { | |
document.removeEventListener('touchmove', this._onMove); | |
document.removeEventListener('touchend', this._onTouchEnd); | |
}, | |
_getX: function(e) { | |
e = e.touches ? e.touches[0] : e; | |
var x = e.clientX - this._bounds.left; | |
if (x < 0) x = 0; | |
if (x > this._bounds.width) x = this._bounds.width; | |
return x; | |
} | |
}; | |
mapboxgl.Compare = Compare; | |
/* | |
{ | |
"version": 8, | |
"sources": { | |
"raster-tiles": { | |
"type": "raster", | |
"url": "mapbox://twelch.9a8w1imb", | |
"tileSize": 256 | |
} | |
}, | |
"layers": [{ | |
"id": "simple-tiles", | |
"type": "raster", | |
"source": "raster-tiles", | |
"minzoom": 0, | |
"maxzoom": 22 | |
}] | |
}, | |
*/ | |
mapboxgl.accessToken = 'pk.eyJ1IjoidHdlbGNoIiwiYSI6ImNqZW5vazRvcjEyczAyd25xamczMmh3OG0ifQ.vJy47O0vb1Z_F7OWIbZpyg'; | |
var beforeMap = new mapboxgl.Map({ | |
container: 'before', | |
style: 'mapbox://styles/mapbox/outdoors-v10', | |
center: [-112.018866, 33.438473], | |
minZoom: 9.5, | |
maxZoom: 13, | |
zoom: 11.5, | |
pitch: 50 | |
}); | |
var afterMap = new mapboxgl.Map({ | |
container: 'after', | |
style: 'mapbox://styles/mapbox/outdoors-v10', | |
center: [-112.018866, 33.438473], | |
minZoom: 9.5, | |
maxZoom: 13, | |
zoom: 11.5, | |
pitch: 50 | |
}); | |
afterMap.on('load', function () { | |
afterMap.addLayer({ | |
"id": "turney", | |
"type": "raster", | |
"source": { | |
"type": "raster", | |
"url": "mapbox://twelch.9a8w1imb", | |
"tileSize": 256 | |
}, | |
"minzoom": 0, | |
"maxzoom": 22 | |
}); | |
}); | |
var map = new mapboxgl.Compare(beforeMap, afterMap, { | |
// Set this to enable comparing two maps by mouse movement: | |
// mousemove: true | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment