CruisersWiki:Ol3chartlet.js
From CruisersWiki
(Difference between revisions)
m |
|||
Line 701: | Line 701: | ||
// use debug version, to allow patch below | // use debug version, to allow patch below | ||
loadScript( | loadScript( | ||
- | "http://cdnjs.cloudflare.com/ajax/libs/ol3/3.19.1/ol.js", | + | "http://cdnjs.cloudflare.com/ajax/libs/ol3/3.19.1/ol-debig.js", |
function () { | function () { | ||
chartletStart(true); | chartletStart(true); |
Revision as of 13:43, 5 December 2016
///* ol3Chartlet.js Copyright (c) 2016 Vadim Shlyakhov Licensed MIT */ (function() { var nx = { navKey: 'Navionics_webapi_00572', domain: 'www.cruiserswiki.org', navToken: null, BASE_TILE_SERVER: '//backend.navionics.io', TILE_SUFFIX: '/tile/{z}/{x}/{y}', KEY_REQ_SUFFIX: '/tile/get_key', MAX_RESOLUTION: 20480, MIN_RESOLUTION: 0.625, disclaimer_msg: '<b>© Navionics</b> <a href="http://www.navionics.com/en/acknowledgements" target="_new" class="navionics-acknowledgements">Acknowledgements</a> | Not to be used for navigation', }; nx.init = function(callback) { // set location for Navionics images //~ $('body').attr('data-root', 'http://webapiv2.navionics.com/dist/webapi/images'); if ( nx.navToken ) { callback(); } else { // requestNavToken var targetUrl = nx.BASE_TILE_SERVER + nx.KEY_REQ_SUFFIX; $.ajax({ url: targetUrl + '/' + nx.navKey + '/' + nx.domain, async: !!callback, crossDomain: true, dataType: 'text', cache: false, error: function() { return console.log(arguments); }, success: function(data, textStatus, jqXHR) { nx.navToken = data; callback(); } }); } }; nx.depthUnits = { 'm': 1, 'metre': 1, 'meter': 1, 'ft': 2, 'feet': 2, 'fathom': 3, }; nx.formatTileUrl = function (options) { // sonar, overlay, depthUnit, safeDepth, showUGC options = options || {}; var layerConfig = [ 'config', nx.depthUnits[options.depthUnit] || 1, (options.safeDepth || 20).toFixed(2), options.sonar ? 1 : 0 ]; params = $.param({ LAYERS: layerConfig.join('_'), TRANSPARENT: !! options.transparency, UGC: !! options.showUGC, navtoken: nx.navToken }); return nx.BASE_TILE_SERVER + nx.TILE_SUFFIX + '?' + params; }; nx.getTileUrl = function (options, callback) { // sonar, overlay, depthUnit, safeDepth, showUGC nx.init(function () { callback(nx.formatTileUrl(options)) }); }; nx.new_source = function (options) { var source = new ol.source.XYZ({ crossOrigin: 'anonymous', attributions: [ new ol.Attribution({ html: nx.disclaimer_msg }) ], maxResolution: nx.MAX_RESOLUTION, minResolution: nx.MIN_RESOLUTION }); nx.getTileUrl( options, function (url) { source.setUrl(url); } ); return source; }; var esri = {}; esri.uris = { 'satellite': "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer", 'topo': "http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer", 'terrain': 'http://server.arcgisonline.com/arcgis/rest/services/World_Terrain_Base/MapServer', 'physical': 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer', 'relief': 'http://server.arcgisonline.com/arcgis/rest/services/World_Shaded_Relief/MapServer', 'light-gray': "http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Reference/MapServer", 'dark-gray': "http://services.arcgisonline.com/arcgis/rest/services/Canvas/World_Dark_Gray_Base/MapServer", 'street': "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer", 'hybrid': "http://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer", 'oceans-reference': "http://server.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Reference/MapServer", 'oceans': 'http://server.arcgisonline.com/arcgis/rest/services/Ocean_Basemap/MapServer', 'national-geographic': "http://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer", }; esri.ZZnew_source = function (src_id) { return new ol.source.TileArcGISRest({ url: esri.uris[src_id], params: { FORMAT: 'JPG', TRANSPARENT: false, }, attributions: [ new ol.Attribution({ html: 'Tiles by ESRI <a href="' + esri.uris[src_id] + '">Acknowledgements</a>' }) ] }) }; esri.new_source = function (src_id) { return new ol.source.XYZ({ url: esri.uris[src_id] + '/tile/{z}/{y}/{x}', crossOrigin: null, attributions: [ new ol.Attribution({ html: 'Tiles by ESRI <a href="' + esri.uris[src_id] + '">Acknowledgements</a>' }) ], }) }; function ol3Chartlet(chartlet_div) { console.log('ol3Chartlet'); var standalone_div = $('#chartlet-standalone')[0]; var standalone = !! standalone_div; // if (standalone && location.hash) { // $('body').empty().append(standalone_div); // $('body').addClass('cw-chartlet-extend'); // } // fill in to a full window if URL hash is set if (standalone && location.hash) { while (document.body.firstChild) { document.body.removeChild(document.body.firstChild); } document.body.appendChild(chartlet_div); $('body').addClass('cw-chartlet-extend'); } this.params = parseParams(standalone && location.hash ? decodeURI(location.hash.slice(1)) : $(chartlet_div).text()); var iconFeature = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.transform([this.params.lon, this.params.lat], 'EPSG:4326', 'EPSG:3857')), name: 'Test marker', }); iconFeature.setStyle( new ol.style.Style({ image: new ol.style.Icon({ anchor: [0, 1], anchorXUnits: 'fraction', anchorYUnits: 'fraction', // anchorYUnits: 'pixels', opacity: 1, src: '/images/e/e7/Flag_icon.png' }) }) ); var testLayer = new ol.layer.Vector({ title: 'Icon', source: new ol.source.Vector({ features: [iconFeature] }) }); var openseamap = new ol.layer.Tile({ title: 'OpenSeaMap', visible: false, source: new ol.source.XYZ({ url: 'http://t1.openseamap.org/seamark/{z}/{x}/{y}.png', crossOrigin: null, attributions: [ new ol.Attribution({ html: 'Tiles by <a href="http://www.openseamap.org">OpenSeaMap</a>' }) ], }) }); var nx_layer = new ol.layer.Tile({ title: 'Navionics', source: nx.new_source() }); var nx_layer_ovl = new ol.layer.Tile({ title: 'Navionics Boating', source: nx.new_source({ transparency:true }) }); var overLayers = standalone ? [ openseamap, nx_layer_ovl, // testLayer, ] : [ ]; var osm = new ol.layer.Tile({ title: 'OpenStreetMap', source: new ol.source.OSM() }); var esri_world = new ol.layer.Tile({ title: 'ESRI World Imagery', source: esri.new_source('satellite') }); var esri_street = new ol.layer.Tile({ title: 'ESRI World Street Map', source: esri.new_source('street') }); var watercolor = new ol.layer.Tile({ title: 'Water color', source: new ol.source.Stamen({ layer: 'watercolor', //~ url: 'http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg' url: '//stamen-tiles-{a-d}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg' }) }); var osm_base = new ol.layer.Tile({ title: 'OSM base', source: new ol.source.OSM({ crossOrigin: null, url: 'http://{a-c}.tiles.wmflabs.org/osm-no-labels/{z}/{x}/{y}.png' }) }); var no_background = new ol.layer.Vector({ title: 'Plain background', source: new ol.source.Vector({ }) }); var baseLayers = standalone ? [ osm, esri_world, // esri_street, // osm_base, // no_background, watercolor, ] : [ osm, esri_world, nx_layer, ]; for (var i = 0; i < baseLayers.length; i++) { baseLayers[i].set('type', 'base'); baseLayers[i].set('visible', false); } baseLayers[baseLayers.length-1].set('visible', true); var layers = [ new ol.layer.Group({ 'title': 'Base map', layers: baseLayers }) ]; if (overLayers.length > 0 ) layers.push(new ol.layer.Group({ title: 'Layers', layers: overLayers })); var map = this.map = new ol.Map({ target: chartlet_div, layers: layers, view: new ol.View({ center: ol.proj.transform([this.params.lon, this.params.lat], 'EPSG:4326', 'EPSG:3857'), zoom: this.params.zoom }), interactions: ol.interaction.defaults( standalone ? {} : { mouseWheelZoom:false, // doubleClickZoom :false, } ), controls: ol.control.defaults({ attributionOptions: /** @type {olx.control.AttributionOptions} */ ({ collapsible: false }) }) }); map.addControl(new ol.control.ScaleLine({ units: 'nautical' })); loadWikiCss('CruisersWiki:Ol3-layerswitcher.css'); loadWikiScript("CruisersWiki:Ol3-layerswitcher.js", function () { var layerSwitcher = new ol.control.LayerSwitcher({ // tipLabel: 'Légende' // Optional label for button }); map.addControl(layerSwitcher); }); if (standalone) { this.initStandalone(); } }; // add layer to a layer group ol3Chartlet.prototype.addNonBaseLayer = function (new_layer) { this.map.getLayers().forEach( function(layer) { if (layer.get('title') === 'Layers') { layer.getLayers().push(new_layer); } } ); } ol3Chartlet.prototype.initStandalone = function () { this.trackHash() this.addGraticule(); var page = this.params.page; var _this = this; if (page) { loadWikiScript('CruisersWiki:GetKml.js', function () { getKml( { page: page, decorated: true }, _this.addPOIs.bind(_this) ); }); loadWikiCss('CruisersWiki:Ol3-popup.css'); loadWikiScript("CruisersWiki:Ol3-popup.js", _this.initPopups.bind(_this)); } }; ol3Chartlet.prototype.trackHash = function() { var doNotTrackHash = false; var setHashTimeoutID = null; var view = this.map.getView(); var params = this.params; var onChangeCenterZoom = function () { var setHashDelay = 1000; var setHash = function () { var centre = view.getCenter(); var lonlat = ol.proj.transform(centre, view.getProjection(), 'EPSG:4326'); doNotTrackHash = true; setHashTimeoutID = null; params.lon = lonlat[0]; params.lat = lonlat[1]; params.zoom = view.getZoom(); //console.log(center, zoom); location.hash = 'lat=' + round(params.lat) + '|lon=' + round(params.lon) + '|zoom=' + params.zoom + (params.layer ? '|layer=' + params.layer : '') + (params.page ? '|page=' + params.page : ''); }; if (setHashTimeoutID) { window.clearTimeout(setHashTimeoutID); } setHashTimeoutID = window.setTimeout(setHash, setHashDelay); }; view.on('change:center', onChangeCenterZoom); view.on('change:resolution', onChangeCenterZoom); window.addEventListener('hashchange', function () { if (!location.hash || doNotTrackHash) { doNotTrackHash = false; return; } params = parseParams(location.hash.slice(1)); if (params.lat != null && params.lon != null) { var centre = [params.lon, params.lat]; view.setCenter(ol.proj.transform(centre, 'EPSG:4326', view.getProjection())) view.setZoom(params.zoom); } }); }; // add coordinate grid layer ol3Chartlet.prototype.addGraticule = function () { // after http://map.openseamap.org/javascript/grid_wgs.js var gridSteps = [ // in seconds //~ 3 / 3600, // 0.05' 6 / 3600, 12 / 3600, 30 / 3600, // 0.1' 0.2' 0.5' // in minutes 1 / 60, 2 / 60, 3 / 60, 5 / 60, 10 / 60, 20 / 60, 30 / 60, // in degrees 1, 2, 3, 4, 6, 10, 15, 30, 45]; var gridPixelStep = 100; // Find matching grid step var getGridStep = function (distance) { for (var i=0; i<gridSteps.length; i++) { if (distance < gridSteps[i]) return gridSteps[i]; } return gridSteps[i-1]; }; // Format label var zeroPad = function (x, int_places, dec, zero_pad) { var pad = ' ' // spaces there var sign = '' var places = dec > 0 ? int_places+dec+1 : int_places if (zero_pad == null || zero_pad) { var pad = '00000000000000000000' if (x < 0) { x = Math.abs(x) places-- sign = '-' } } return sign + (pad + x.toFixed(dec)).slice(-places) }; var formatDegrees = function (deg, format, isLon) { var adeg = Math.abs(deg); return '' + zeroPad(Math.floor(adeg), isLon ? 3 : 2) + "°" + (format == 'd' ? '' : zeroPad((adeg * 60) % 60, 2, format == 'dm' ? 0 : 1) + "'") + (isLon ? (deg < 0 ? 'W' : 'E') : (deg < 0 ? 'S' : 'N')); }; var map = this.map; var view = this.map.getView(); // layer loader var loader = function(extent, resolution, projection) { /** * @param {ol.Extent} extent Extent. * @param {number} resolution Resolution. * @param {ol.proj.Projection} projection Projection. * @this {ol.source.Vector|ol.VectorTile} */ var view_proj = view.getProjection(); var geo_proj = 'EPSG:4326'; var map_size = map.getSize(); var lonlat_extent = ol.proj.transformExtent(extent, view_proj, geo_proj); // clip extent to max values var x1 = Math.max (-180, lonlat_extent[0]); var x2 = Math.min ( 180, lonlat_extent[2]); var y1 = Math.max ( -85, lonlat_extent[1]); var y2 = Math.min ( 85, lonlat_extent[3]); // grid step var step = getGridStep((lonlat_extent[3] - lonlat_extent[1]) / map_size[1] * gridPixelStep); var labelFormat = step % 1 ? ((step * 60)% 1 ? 'dm.m' : 'dm') : 'd'; // round degrees number var features = []; // line style var strokeStyle = new ol.style.Stroke({ color: [102, 102, 102, 255 * 0.8], // "#666666", width: 1, //~ strokeOpacity: 0.8 }); // Vertical lines for (var x = Math.ceil(x1 / step) * step + (x1 == -180 ? step : 0); x <= x2; x += step) { var l = new ol.geom.LineString([ ol.proj.transform([x, y1], geo_proj, view_proj), ol.proj.transform([x, y2], geo_proj, view_proj) ]); var f = new ol.Feature(l); f.setStyle(new ol.style.Style({ stroke: strokeStyle, text: new ol.style.Text({ text: formatDegrees (x, labelFormat, true), textAlign: 'end', textBaseline: 'top', offsetX: 0, offsetY: - map_size[1] / 2, rotation: - Math.PI / 2, scale: 1.5, // labelAlign: "lt", }), })); features.push (f); } // Horizontal lines for (var y = Math.ceil(y1 / step) * step; y <= y2; y += step) { var l = new ol.geom.LineString([ ol.proj.transform([x1, y], geo_proj, view_proj), ol.proj.transform([x2, y], geo_proj, view_proj) ]); var f = new ol.Feature(l); f.setStyle(new ol.style.Style({ stroke: strokeStyle, text: new ol.style.Text({ text: formatDegrees (y, labelFormat, false), textAlign: 'end', textBaseline: 'top', offsetX: map_size[0] / 2, offsetY: 0, rotation: 0, scale: 1.5, //~ labelAlign: "lt", }), })); features.push (f); } this.addFeatures(features); }; var graticule = new ol.layer.Vector({ title: 'Graticule', visible: false, source: new ol.source.Vector({ loader: loader, strategy: ol.loadingstrategy.bbox }) }); graticule.set('noclickable', true); // add to the proper layer group this.addNonBaseLayer(graticule); var onChangeCenterZoom = function () { graticule.getSource().clear(); } view.on('change:center', onChangeCenterZoom); view.on('change:resolution', onChangeCenterZoom); }; // load kml ol3Chartlet.prototype.addPOIs = function(kml) { if (!kml) return; // kml_uri='http://openlayers.org/en/v3.13.1/examples/data/kml/2012-02-10.kml'; var format = new ol.format.KML({ showPointNames: false, }); var loader = function(extent, resolution, projection) { /** * @param {ol.Extent} extent Extent. * @param {number} resolution Resolution. * @param {ol.proj.Projection} projection Projection. * @this {ol.source.Vector|ol.VectorTile} */ var xml_tree = ol.xml.parse(kml); var features = format.readFeatures( xml_tree, {featureProjection: projection} ); this.addFeatures(features); }; var kml_layer = new ol.layer.Vector({ title: 'POI', visible:true, source: new ol.source.Vector({ loader: loader, }) }); // add to the proper layer group this.addNonBaseLayer(kml_layer); }; ol3Chartlet.prototype.initPopups = function () { var map = this.map; var popup = new ol.Overlay.Popup(); map.addOverlay(popup); var layerFilter = function (layer) { return ! layer.get('noclickable'); }; // display popup on click map.on('click', function(evt) { var feature = map.forEachFeatureAtPixel( evt.pixel, function(feature) { return feature; }, null, layerFilter ); if (feature && ! feature.get('noclickable')) { popup.show(evt.coordinate, '<div class="cw-popup-name">' + feature.get("name") + '</div>' + '<div class="cw-popup-category">' + feature.get("styleUrl").split('#')[1] + '</div>' + '<div class="cw-popup-content">' + feature.get("description") + '<div>' ); } else { popup.hide(); } }); // change mouse cursor when over marker map.on('pointermove', function(e) { //~ if (e.dragging) { //~ $(element).popover('destroy'); //~ return; //~ } var pixel = map.getEventPixel(e.originalEvent); var hit = map.hasFeatureAtPixel(pixel, layerFilter); map.getTarget().style.cursor = hit ? 'pointer' : ''; }); }; function dmsh2deg(dmsh) { var dmsFactors = [1, 60, 3600]; var deg = 0; if (!dmsh) return deg; var parts = dmsh.split('_'); for (var i=0, li = parts.length; i < li; i++) { var p = parts[i]; if (isNaN(+ p)) { if (p == 'S' || p == 's' || p == 'W' || p == 'w') deg = -deg; break; } else { deg += p / dmsFactors[i]; } } return deg; } var zoomDelta = 0; // -3; // adjust zoom levels function parseParams(param_str) { var out = {}; var params = param_str.split('|'); for (var i=0, li = params.length; i < li; i++) { var keyVal = params[i].split('=', 2); var key = keyVal[0].replace(/^\s+|\s+$/g, '').toLowerCase(); var val = keyVal[1].replace(/^\s+|\s+$/g, ''); if (key == 'lon') { out.lon = dmsh2deg(val); } else if (key == 'lat') { out.lat = dmsh2deg(val); } else if (key == 'zoom') { out.zoom = +(val || 12) + zoomDelta; } else if (key == 'layer') { out.layer = val || 'N'; } else if (key == 'page') { out.page = val; } } return out; } function round(val) { var fact = 100000; return Math.round(val * fact) / fact; } function chartletStart(secondCall) { var $chartlets = $('.chartlet'); if ($chartlets.length === 0) { return; } if (typeof ol === 'undefined') { if (!secondCall) { // try to load ol loadCss("http://cdnjs.cloudflare.com/ajax/libs/ol3/3.19.1/ol.css"); loadWikiCss('CruisersWiki:Ol3chartlet.css'); // use debug version, to allow patch below loadScript( "http://cdnjs.cloudflare.com/ajax/libs/ol3/3.19.1/ol-debig.js", function () { chartletStart(true); } ); } } else { // try to recover from /extensions/TreeAndMenu/dtree.js overwriting Node if (Node.ELEMENT_NODE === undefined) { if (document.firstElementChild.__proto__.ELEMENT_NODE == 1) { Node = document.firstElementChild.__proto__; } else { Node.ELEMENT_NODE = 1 } ol.xml.isNode = function(value) { // return value instanceof Node; return typeof value.nodeName === "string"; }; } $chartlets.each( function () { new ol3Chartlet(this); }); } }; addOnloadHook(chartletStart); })(); //