diff --git a/README.md b/README.md index 0186a33..943f5f2 100755 --- a/README.md +++ b/README.md @@ -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 diff --git a/controllers/IndexController.php b/controllers/IndexController.php index 61dc0b9..9a68ba6 100755 --- a/controllers/IndexController.php +++ b/controllers/IndexController.php @@ -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') diff --git a/views/public/javascripts/leaflet-iiif.js b/views/public/javascripts/leaflet-iiif.js new file mode 100644 index 0000000..ee5ae09 --- /dev/null +++ b/views/public/javascripts/leaflet-iiif.js @@ -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); +}; diff --git a/views/public/javascripts/walking-tour.js b/views/public/javascripts/walking-tour.js index 25a7bb9..aeb9602 100755 --- a/views/public/javascripts/walking-tour.js +++ b/views/public/javascripts/walking-tour.js @@ -1,8 +1,278 @@ -$(document).ready(function () { - walkingTourJs() -}); +console.log("start") +/* + * Leaflet-IIIF 1.1.1 + * IIIF Viewer for Leaflet + * by Jack Reed, @mejackreed + */ + +const 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; + }, + _getImageSize: function() { + return this._imageSizes; + } + }); + +const tiff = function(url, options) { +return new Iiif(url, options); +}; + +const getPackages = async function() { + const allmapsAnnotation = await import("https://unpkg.com/@allmaps/annotation?module") + const allmapsTransform = await import("https://unpkg.com/@allmaps/transform@1.0.0-beta.37/dist/bundled/index.es.js?module") + + return [allmapsAnnotation, allmapsTransform] +} -function walkingTourJs() { +console.log(tiff) +async function main() { + let packages = await getPackages(); + console.log(packages); + console.log(tiff) + walkingTourJs(packages[0], packages[1], tiff) + } + +main() + +// .then(([allmapsAnnotation, allmapsTransform]) => { +// // Both modules loaded successfully +// // Use the imported modules +// console.log(L.tileLayer) +// walkingTourJs(allmapsAnnotation, allmapsTransform, L.tileLayer.iiif) +// }) +// .catch((error) => { +// // An error occurred while loading one of the modules +// console.error('Error loading modules:', error); +// }); + + +function walkingTourJs(allmapsAnnotation, allmapsTransform, iiif) { var imported = document.createElement("script"); document.head.appendChild(imported); // Set map height to be window height minus header height. @@ -10,6 +280,8 @@ function walkingTourJs() { $('#map').css('height', windowheight - 54); var MAP_URL_TEMPLATE = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}'; + const annotationUrl = 'https://annotations.allmaps.org/manifests/47574ee029cca631' + // const annotationUrl = "https://annotations.allmaps.org/manifests/c047e9dd35f2d377" var MAP_CENTER; var MAP_ZOOM; // MAP_ZOOM controls the default zoom of the map @@ -29,6 +301,17 @@ function walkingTourJs() { var allItems = {}; var allMarkers = {}; + var imageZoom; + + var yx = L.latLng; + + var xy = function(x, y) { + if (Array.isArray(x)) { // When doing xy([x, y]); + return yx(x[1], x[0]); + } + return yx(y, x); // When doing xy(x, y); + }; + /* @@ -242,12 +525,53 @@ function walkingTourJs() { * Query backend */ - window.onload = function () { - jqXhr = $.post('walking-tour/index/map-config', function (response) { - mapSetUp(response); - doQuery(); + // window.onload = function () { + // jqXhr = $.post('walking-tour/index/map-config', function (response) { + // const mapConfig = response + // mapSetUp(mapConfig, "https://iiif.digitalcommonwealth.org/iiif/2/commonwealth:ht250943q") + // fetch(annotationUrl) + // .then(response => { + // // Check if the request was successful + // if (!response.ok) { + // throw new Error('Network response was not ok'); + // } + // // Parse the response as JSON + // return response.json(); + // }) + // .then(data => { + // const maps = allmapsAnnotation.parseAnnotation(data) + // const transformer = new allmapsTransform.GcpTransformer(maps[0].gcps); + // console.log(maps) + // doQuery(transformer, maps); + // }) + // .catch(error => { + // // Handle any errors that occurred during the fetch + // console.error('Fetch error:', error); + // }); + // }) + // }; + + fetch(annotationUrl) + .then(response => { + // Check if the request was successful + if (!response.ok) { + throw new Error('Network response was not ok'); + } + // Parse the response as JSON + return response.json(); }) - }; + .then(data => { + const maps = allmapsAnnotation.parseAnnotation(data) + const transformer = new allmapsTransform.GcpTransformer(maps[0].gcps); + console.log(maps) + imageZoom = maps[0].resource.height / $('#map').height() + mapSetUp(maps[0]) + doQuery(transformer, maps); + }) + .catch(error => { + // Handle any errors that occurred during the fetch + console.error('Fetch error:', error); + }); // Retain previous form state, if needed. retainFormState(); @@ -257,96 +581,136 @@ function walkingTourJs() { * * Call only once during set up */ - function mapSetUp(response) { - EXHIBIT_BUTTON_TEXT = response['walking_tour_exhibit_button'] - DETAIL_BUTTON_TEXT = response['walking_tour_detail_button'] - MAP_MAX_ZOOM = parseInt(response['walking_tour_max_zoom']) - MAP_MIN_ZOOM = parseInt(response['walking_tour_min_zoom']) - MAP_CENTER = parse1DArrayPoint(response['walking_tour_center']) - MAP_ZOOM = parseInt(response["walking_tour_default_zoom"]) - MAP_MAX_BOUNDS = parse2DArrayPoint(response["walking_tour_max_bounds"]) - // Set the base map layer. + function mapSetUp(maps) { + var mapHeight = maps.resource.height / imageZoom + var mapWidth = maps.resource.width / imageZoom + var bounds = [[0,0], [mapHeight, mapWidth]]; + var center = [(bounds[1][0] - bounds[0][0])/ 2, (bounds[1][1] - bounds[0][1])/ 2] map = L.map('map', { - center: MAP_CENTER, - zoom: MAP_MIN_ZOOM, - minZoom: MAP_MIN_ZOOM, - maxZoom: MAP_MAX_ZOOM, - // maxBounds: MAP_MAX_BOUNDS, - zoomControl: false + center: center, + crs: L.CRS.Simple, + zoom: -1, + maxBounds: bounds + }); + + // const iiif_layer = iiif(maps.resource.id+'/info.json', { + // fitBounds: true, + // setMaxBounds: true, + // }).addTo(map) + console.log(maps.resource.id +'/full/'+ maps.resource.width +',/0/default.jpg') + var image = L.imageOverlay(maps.resource.id +'/full/'+ $('#map').width() +',/0/default.jpg', bounds).addTo(map); + console.log(image) + // console.log(iiif_layer) + // console.log(iiif_layer._getImageSize()) + // const imageSize = iiif_layer._imageSizes.map(ele => { + // return xy(ele[0], ele[1]) + // }) + + map.on('zoomend', function() { + console.log(map.getZoom()) }); - LOCATE_BOUNDS = map.getBounds(); - map.setZoom(MAP_ZOOM); - - map.addLayer(L.tileLayer(MAP_URL_TEMPLATE)); - map.addControl(L.control.zoom({ position: 'topleft' })); - var extentControl = L.Control.extend({ - options: { - position: 'topleft' - }, - onAdd: function (map) { - var container = L.DomUtil.create('div', 'extentControl'); - $(container).attr('id', 'extent-control'); - $(container).css('width', '26px').css('height', '26px').css('outline', '1px black'); - $(container).addClass('extentControl-disabled') - $(container).addClass('leaflet-bar') - $(container).on('click', function () { - map.flyTo(MAP_CENTER, MAP_ZOOM); - }); - return container; - } - }) - map.addControl(new extentControl()); - map.attributionControl.setPrefix('Tiles © Esri'); + // map.setZoom(zoom) + // var bounds = L.bounds(L.point(maps.resourceMask[0][0], maps.resourceMask[0][1]), L.point(maps.resourceMask[2][0], maps.resourceMask[2][1])); + + // console.log(bounds) + // map.fitBounds(bounds) + // console.log(map.getBounds(), map.getZoom()) + // var rect = L.rectangle(imageSize, {color: 'blue', weight: 1}).on('click', function (e) { + // // There event is event object + // // there e.type === 'click' + // // there e.lanlng === L.LatLng on map + // // there e.target.getLatLngs() - your rectangle coordinates + // // but e.target !== rect + // console.info(e); + // }).addTo(map); + + // EXHIBIT_BUTTON_TEXT = response['walking_tour_exhibit_button'] + // DETAIL_BUTTON_TEXT = response['walking_tour_detail_button'] + // MAP_MAX_ZOOM = parseInt(response['walking_tour_max_zoom']) + // MAP_MIN_ZOOM = parseInt(response['walking_tour_min_zoom']) + // MAP_CENTER = parse1DArrayPoint(response['walking_tour_center']) + // MAP_ZOOM = parseInt(response["walking_tour_default_zoom"]) + // MAP_MAX_BOUNDS = parse2DArrayPoint(response["walking_tour_max_bounds"]) + // // Set the base map layer. + // map = L.map('map', { + // center: MAP_CENTER, + // zoom: MAP_MIN_ZOOM, + // minZoom: MAP_MIN_ZOOM, + // maxZoom: MAP_MAX_ZOOM, + // zoomControl: false + // }); + // LOCATE_BOUNDS = map.getBounds(); + // map.setZoom(MAP_ZOOM); + + // map.addLayer(L.tileLayer(MAP_URL_TEMPLATE)); + // map.addControl(L.control.zoom({ position: 'topleft' })); + // var extentControl = L.Control.extend({ + // options: { + // position: 'topleft' + // }, + // onAdd: function (map) { + // var container = L.DomUtil.create('div', 'extentControl'); + // $(container).attr('id', 'extent-control'); + // $(container).css('width', '26px').css('height', '26px').css('outline', '1px black'); + // $(container).addClass('extentControl-disabled') + // $(container).addClass('leaflet-bar') + // $(container).on('click', function () { + // map.flyTo(MAP_CENTER, MAP_ZOOM); + // }); + // return container; + // } + // }) + // map.addControl(new extentControl()); + // map.attributionControl.setPrefix('Tiles © Esri'); - // const annotationUrl = 'https://annotations.allmaps.org/manifests/47574ee029cca631' // const warpedMapLayer = new Allmaps.WarpedMapLayer(annotationUrl) // map.addLayer(warpedMapLayer); - map.on('zoomend', function () { - if (map.getZoom() == MAP_MIN_ZOOM) { - $('#extent-control').addClass('extentControl-disabled') - } else { - $('#extent-control').removeClass('extentControl-disabled') - } - }) + // map.on('zoomend', function () { + // if (map.getZoom() == MAP_MIN_ZOOM) { + // $('#extent-control').addClass('extentControl-disabled') + // } else { + // $('#extent-control').removeClass('extentControl-disabled') + // } + // }) // Handle location found. - map.on('locationfound', function (e) { - if (!locationMarker) { - $("#locate-button").toggleClass('loading'); - } - // User within location bounds. Set the location marker. - if (L.latLngBounds(LOCATE_BOUNDS).contains(e.latlng)) { - if (locationMarker) { - // Remove the existing location marker before adding to map. - map.removeLayer(locationMarker); - } else { - // Pan to location only on first locate. - map.panTo(e.latlng); - } - locationMarker = L.marker(e.latlng, { - icon: L.icon({ - iconUrl: 'plugins/WalkingTour/views/public/images/location.png', - iconSize: [25, 25] - }) - }); - locationMarker.addTo(map).bindPopup("You are within " + e.accuracy / 2 + " meters from this point"); - // User outside location bounds. - } else { - var locateMeters = e.latlng.distanceTo(map.options.center); - var locateMiles = Math.ceil((locateMeters * 0.000621371) * 100) / 100; - alert('Cannot locate your location. You are ' + locateMiles + ' miles from the map bounds.'); - map.stopLocate(); - } - }); - - // Handle location error. - map.on('locationerror', function () { - $("#locate-button").toggleClass('loading'); - map.stopLocate(); - alert('Location Error, Please try again.'); - console.log('location error') - }); + // map.on('locationfound', function (e) { + // if (!locationMarker) { + // $("#locate-button").toggleClass('loading'); + // } + // // User within location bounds. Set the location marker. + // if (L.latLngBounds(LOCATE_BOUNDS).contains(e.latlng)) { + // if (locationMarker) { + // // Remove the existing location marker before adding to map. + // map.removeLayer(locationMarker); + // } else { + // // Pan to location only on first locate. + // map.panTo(e.latlng); + // } + // locationMarker = L.marker(e.latlng, { + // icon: L.icon({ + // iconUrl: 'plugins/WalkingTour/views/public/images/location.png', + // iconSize: [25, 25] + // }) + // }); + // locationMarker.addTo(map).bindPopup("You are within " + e.accuracy / 2 + " meters from this point"); + // // User outside location bounds. + // } else { + // var locateMeters = e.latlng.distanceTo(map.options.center); + // var locateMiles = Math.ceil((locateMeters * 0.000621371) * 100) / 100; + // alert('Cannot locate your location. You are ' + locateMiles + ' miles from the map bounds.'); + // map.stopLocate(); + // } + // }); + + // // Handle location error. + // map.on('locationerror', function () { + // $("#locate-button").toggleClass('loading'); + // map.stopLocate(); + // alert('Location Error, Please try again.'); + // console.log('location error') + // }); } /* @@ -354,7 +718,7 @@ function walkingTourJs() { * * Call only once during set up */ - function doQuery() { + function doQuery(transformer) { const markerFontHtmlStyles = ` transform: rotate(-45deg); color:white; @@ -362,7 +726,6 @@ function walkingTourJs() { padding: 0.2rem 0 0.18rem 0; font-size: 15px; ` - // correctly formats coordinates as [lat, long] (API returns [long, lat]) function orderCoords(path) { var directions = []; @@ -395,6 +758,15 @@ function walkingTourJs() { var url; var itemArray = [] var tourToItem = {} + + var yx = L.latLng; + + var xy = function(x, y) { + if (Array.isArray(x)) { // When doing xy([x, y]); + return yx(x[1], x[0]); + } + return yx(y, x); // When doing xy(x, y); + }; jqXhr = $.post('walking-tour/index/query', function (response) { markerData = response; dataArray = Object.entries(markerData) @@ -406,82 +778,152 @@ function walkingTourJs() { var numMarker = 1; var response = value["Data"]; var itemIDList = []; + // console.log(transformer) + // console.log(response.features) + + newList = [] - response.features.forEach(ele => { + response.features = response.features.map(ele => { + var test = transformer.transformBackward( + ele.geometry + ) + test = test.map(ele => {return ele/imageZoom}) + // console.log(test) itemIDList.push(ele.properties.id) + return({ + ...ele, + geometry: test + }) }) + console.log(response.features) tourToItem[tourId] = itemIDList; markerList = [] - var geoJsonLayer = L.geoJson(response.features, { - // adds the correct number to each marker based on order of tour - pointToLayer: function (feature, latlng) { - var numberIcon = L.divIcon({ - className: "my-custom-pin", - iconSize: [25, 41], - iconAnchor: [12, 40], - popupAnchor: [0, -5], - html: `

${numMarker}

` - }); - numMarker++; - return L.marker(latlng, { icon: numberIcon }); - }, - onEachFeature: function (feature, layer) { - layer.on('click', function (e) { - // center click location - map.flyTo(e.latlng,MAP_MAX_ZOOM); - // Close the filtering - var filterButton = $('filter-button'); - filterButton.removeClass('on'). - find('.screen-reader-text'). - html('Filters'); - $('#filters').fadeOut(200, 'linear'); - - var marker = this; - response = allItems[`${tourId}:${feature.properties.id}`] - if (response == undefined) { - $.post('walking-tour/index/get-item', { id: feature.properties.id, tour: tourId }, function (response) { - allItems[`${tourId}:${feature.properties.id}`] = response; - featureOnclickAction(response, layer, marker, itemIDList, value, tourId); - }) - } else { - featureOnclickAction(response, layer, marker, itemIDList, value, tourId); + + response.features.forEach(feature => { + var numberIcon = L.divIcon({ + className: "my-custom-pin", + iconSize: [25, 41], + iconAnchor: [12, 40], + popupAnchor: [0, -5], + html: `

${numMarker}

` + }); + numMarker++; + + var marker = L.marker(xy(feature.geometry[0], feature.geometry[1]), { icon: numberIcon }); + marker.on('click', function (e) { + // center click location + map.flyTo(e.latlng, 4); + // Close the filtering + var filterButton = $('filter-button'); + filterButton.removeClass('on'). + find('.screen-reader-text'). + html('Filters'); + $('#filters').fadeOut(200, 'linear'); + + var marker = this; + response = allItems[`${tourId}:${feature.properties.id}`] + if (response == undefined) { + $.post('walking-tour/index/get-item', { id: feature.properties.id, tour: tourId }, function (response) { + allItems[`${tourId}:${feature.properties.id}`] = response; + + + + var popupContent = '

' + response.title + '

'; + if (response.thumbnail) { + popupContent += '' + response.thumbnail + '
'; + } + popupContent += 'View More Info'; + if (!marker.getPopup()) { + marker.bindPopup(popupContent, { maxWidth: 200, offset: L.point(0, -40) }).openPopup(); + allMarkers[response.id] = marker; + } + }) + } else { + var popupContent = '

' + response.title + '

'; + if (response.thumbnail) { + popupContent += '' + response.thumbnail + '
'; } + popupContent += 'View More Info'; + if (!marker.getPopup()) { + marker.bindPopup(popupContent, { maxWidth: 200, offset: L.point(0, -40) }).openPopup(); + allMarkers[response.id] = marker; + } + } + }) + marker.addTo(map) + }) + - }); - } - }); + // var geoJsonLayer = L.geoJson(response.features, { + // // adds the correct number to each marker based on order of tour + // pointToLayer: function (feature, latlng) { + // var numberIcon = L.divIcon({ + // className: "my-custom-pin", + // iconSize: [25, 41], + // iconAnchor: [12, 40], + // popupAnchor: [0, -5], + // html: `

${numMarker}

` + // }); + // numMarker++; + // console.log(latlng) + // return L.marker(latlng, { icon: numberIcon }); + // }, + // onEachFeature: function (feature, layer) { + // layer.on('click', function (e) { + // // center click location + // map.flyTo(e.latlng,MAP_MAX_ZOOM); + // // Close the filtering + // var filterButton = $('filter-button'); + // filterButton.removeClass('on'). + // find('.screen-reader-text'). + // html('Filters'); + // $('#filters').fadeOut(200, 'linear'); + + // var marker = this; + // response = allItems[`${tourId}:${feature.properties.id}`] + // if (response == undefined) { + // $.post('walking-tour/index/get-item', { id: feature.properties.id, tour: tourId }, function (response) { + // allItems[`${tourId}:${feature.properties.id}`] = response; + // featureOnclickAction(response, layer, marker, itemIDList, value, tourId); + // }) + // } else { + // featureOnclickAction(response, layer, marker, itemIDList, value, tourId); + // } + + // }); + + // } + // }); markerData[tourId].allMarker = markerList; - markerData[tourId].geoJson = geoJsonLayer; - var walkingPath = []; - var json_content = response.features; - var pointList = []; - for (var i = 0; i < json_content.length; i++) { - lat = json_content[i].geometry.coordinates[1]; - lng = json_content[i].geometry.coordinates[0]; - var point = new L.LatLng(lat, lng); - pointList[i] = point; - } - getOverallPath(pointList, key).then((data) => { - var path = data["features"][0]["geometry"]["coordinates"]; - path = orderCoords(path); - for (var p of path) { - walkingPath.push(p); - } - var tourPolyline = new L.Polyline(walkingPath, { - color: value["Color"], - weight: 3, - opacity: 1, - smoothFactor: 1 - }); - markerData[tourId].walkingPath = tourPolyline; - resolve() - }); + // var json_content = response.features; + // var pointList = []; + // for (var i = 0; i < json_content.length; i++) { + // lat = json_content[i].geometry.coordinates[1]; + // lng = json_content[i].geometry.coordinates[0]; + // var point = new L.LatLng(lat, lng); + // pointList[i] = point; + // } + // getOverallPath(pointList, key).then((data) => { + // var path = data["features"][0]["geometry"]["coordinates"]; + // path = orderCoords(path); + // for (var p of path) { + // walkingPath.push(p); + // } + // var tourPolyline = new L.Polyline(walkingPath, { + // color: value["Color"], + // weight: 3, + // opacity: 1, + // smoothFactor: 1 + // }); + // markerData[tourId].walkingPath = tourPolyline; + // resolve() + // }); }); }) Promise.all(requests).then(() => { createCustomCSS(); - doFilters(); + // doFilters(); }); }); }