Skip to content

Allmaps historical maps #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,9 @@ One annoying issue we found is that there is some coupling between the MallMap t
- [x] Representation for no exhibit for tour item
- [ ] Padding on the dropdown menu
- [ ] Historical Map

### Allmaps References

Leaflet without geographic coordinates: https://leafletjs.com/examples/crs-simple/crs-simple.html
https://observablehq.com/d/7db1214479eeeee0
https://observablehq.com/@allmaps/using-allmaps-to-draw-geojson-on-a-iiif-image
1 change: 1 addition & 0 deletions controllers/IndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function indexAction()
->appendFile(src('modernizr.custom.63332', 'javascripts', 'js'))
->appendFile(src('Polyline.encoded', 'javascripts', 'js'))
->appendFile('//cdn.jsdelivr.net/npm/@allmaps/leaflet/dist/bundled/allmaps-leaflet-1.9.umd.js')
->appendFile(src('leaflet-iiif', 'javascripts', 'js'))
->appendFile(src('walking-tour', 'javascripts', 'js'));
$this->view->headLink()
->appendStylesheet('//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css', 'all')
Expand Down
241 changes: 241 additions & 0 deletions views/public/javascripts/leaflet-iiif.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* Leaflet-IIIF 1.1.1
* IIIF Viewer for Leaflet
* by Jack Reed, @mejackreed
*/

L.TileLayer.Iiif = L.TileLayer.extend({
options: {
continuousWorld: true,
tileSize: 256,
updateWhenIdle: true,
tileFormat: 'jpg',
fitBounds: true
},

initialize: function(url, options) {
options = typeof options !== 'undefined' ? options : {};

if (options.maxZoom) {
this._customMaxZoom = true;
}

// Check for explicit tileSize set
if (options.tileSize) {
this._explicitTileSize = true;
}

// Check for an explicit quality
if (options.quality) {
this._explicitQuality = true;
}

options = L.setOptions(this, options);
this._infoDeferred = new $.Deferred();
this._infoUrl = url;
this._baseUrl = this._templateUrl();
this._getInfo();
},
getTileUrl: function(coords) {
var _this = this,
x = coords.x,
y = (coords.y),
zoom = _this._getZoomForUrl(),
scale = Math.pow(2, _this.maxNativeZoom - zoom),
tileBaseSize = _this.options.tileSize * scale,
minx = (x * tileBaseSize),
miny = (y * tileBaseSize),
maxx = Math.min(minx + tileBaseSize, _this.x),
maxy = Math.min(miny + tileBaseSize, _this.y);

var xDiff = (maxx - minx);
var yDiff = (maxy - miny);

return L.Util.template(this._baseUrl, L.extend({
format: _this.options.tileFormat,
quality: _this.quality,
region: [minx, miny, xDiff, yDiff].join(','),
rotation: 0,
size: Math.ceil(xDiff / scale) + ','
}, this.options));
},
onAdd: function(map) {
var _this = this;

// Wait for deferred to complete
$.when(_this._infoDeferred).done(function() {

// Set maxZoom for map
map._layersMaxZoom = _this.maxZoom;

// Call add TileLayer
L.TileLayer.prototype.onAdd.call(_this, map);

if (_this.options.fitBounds) {
_this._fitBounds();
}

// Reset tile sizes to handle non 256x256 IIIF tiles
_this.on('tileload', function(tile, url) {

var height = tile.tile.naturalHeight,
width = tile.tile.naturalWidth;

// No need to resize if tile is 256 x 256
if (height === 256 && width === 256) return;

tile.tile.style.width = width + 'px';
tile.tile.style.height = height + 'px';

});
});
},
_fitBounds: function() {
var _this = this;

// Find best zoom level and center map
var initialZoom = _this._getInitialZoom(_this._map.getSize());
var imageSize = _this._imageSizes[initialZoom];
var sw = _this._map.options.crs.pointToLatLng(L.point(0, imageSize.y), initialZoom);
var ne = _this._map.options.crs.pointToLatLng(L.point(imageSize.x, 0), initialZoom);
var bounds = L.latLngBounds(sw, ne);

_this._map.fitBounds(bounds, true);
},
_getInfo: function() {
var _this = this;

// Look for a way to do this without jQuery
$.getJSON(_this._infoUrl)
.done(function(data) {
_this.y = data.height;
_this.x = data.width;

var tierSizes = [],
imageSizes = [],
scale,
width_,
height_,
tilesX_,
tilesY_;

// Set quality based off of IIIF version
if (data.profile instanceof Array) {
_this.profile = data.profile[0];
}else {
_this.profile = data.profile;
}

_this._setQuality();

// Unless an explicit tileSize is set, use a preferred tileSize
if (!_this._explicitTileSize) {
// Set the default first
_this.options.tileSize = 256;
if (data.tiles) {
// Image API 2.0 Case
_this.options.tileSize = data.tiles[0].width;
} else if (data.tile_width){
// Image API 1.1 Case
_this.options.tileSize = data.tile_width;
}
}

function ceilLog2(x) {
return Math.ceil(Math.log(x) / Math.LN2);
};

// Calculates maximum native zoom for the layer
_this.maxNativeZoom = Math.max(ceilLog2(_this.x / _this.options.tileSize),
ceilLog2(_this.y / _this.options.tileSize));

// Enable zooming further than native if maxZoom option supplied
if (_this._customMaxZoom && _this.options.maxZoom > _this.maxNativeZoom) {
_this.maxZoom = _this.options.maxZoom;
}
else {
_this.maxZoom = _this.maxNativeZoom;
}

for (var i = 0; i <= _this.maxZoom; i++) {
scale = Math.pow(2, _this.maxNativeZoom - i);
width_ = Math.ceil(_this.x / scale);
height_ = Math.ceil(_this.y / scale);
tilesX_ = Math.ceil(width_ / _this.options.tileSize);
tilesY_ = Math.ceil(height_ / _this.options.tileSize);
tierSizes.push([tilesX_, tilesY_]);
imageSizes.push(L.point(width_,height_));
}

_this._tierSizes = tierSizes;
_this._imageSizes = imageSizes;

// Resolved Deferred to initiate tilelayer load
_this._infoDeferred.resolve();
});
},

_setQuality: function() {
var _this = this;
var profileToCheck = _this.profile;

if (_this._explicitQuality) {
return;
}

// If profile is an object
if (typeof(profileToCheck) === 'object') {
profileToCheck = profileToCheck['@id'];
}

// Set the quality based on the IIIF compliance level
switch (true) {
case /^http:\/\/library.stanford.edu\/iiif\/image-api\/1.1\/compliance.html.*$/.test(profileToCheck):
_this.options.quality = 'native';
break;
// Assume later profiles and set to default
default:
_this.options.quality = 'default';
break;
}
},

_infoToBaseUrl: function() {
return this._infoUrl.replace('info.json', '');
},
_templateUrl: function() {
return this._infoToBaseUrl() + '{region}/{size}/{rotation}/{quality}.{format}';
},
_isValidTile: function(coords) {
var _this = this,
zoom = _this._getZoomForUrl(),
sizes = _this._tierSizes[zoom],
x = coords.x,
y = (coords.y);

if (!sizes) return false;
if (x < 0 || sizes[0] <= x || y < 0 || sizes[1] <= y) {
return false;
}else {
return true;
}
},
_getInitialZoom: function (mapSize) {
var _this = this,
tolerance = 0.8,
imageSize;

for (var i = _this.maxNativeZoom; i >= 0; i--) {
imageSize = this._imageSizes[i];
if (imageSize.x * tolerance < mapSize.x && imageSize.y * tolerance < mapSize.y) {
return i;
}
}
// return a default zoom
return 2;
}
});

L.tileLayer.iiif = function(url, options) {
return new L.TileLayer.Iiif(url, options);
};
Loading