CruisersWiki:Ol3chartlet.js

From CruisersWiki

Revision as of 08:35, 1 March 2016 by Vadim (Talk | contribs)
Jump to: navigation, search

/*

  ol3Chartlet.js
  Copyright (c) 2016 Vadim Shlyakhov
  Licensed MIT
  • /

addOnloadHook(function() {

   var $chartlets = $('.ol3-chartlet');
   if ($chartlets.length === 0) {
       return;
   }
   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: '© Navionics <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 = $('#ol3-chartlet-standalone')[0];
       var standalone = !! standalone_div;
       if (standalone && location.hash) {
           $('body').empty().append(standalone_div);
           $('body').addClass('cw-chartlet-extend');
       }
       this.params = parseParams(standalone && location.hash ? 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',
           source: nx.new_source({
               transparency:true
           })
       });
       var overlaidLayers = [
           openseamap,
           nx_layer_ovl,
           // testLayer,
       ];
       var watercolor = new ol.layer.Tile({
               title: 'Water color',
               source: new ol.source.Stamen({
                   layer: 'watercolor'
               });
       watercolor.on('tileloaderror', function (evnt) {
           console.log(evnt);
       });
       var baseLayers =  [
           new ol.layer.Tile({
               title: 'OpenStreetMap',
               source: new ol.source.OSM()
           }),
           //~ new ol.layer.Tile({
               //~ title: 'OSM no labels',
               //~ source: new ol.source.OSM({
                   //~ crossOrigin: null,
                   //~ url: 'http://{a-c}.tiles.wmflabs.org/osm-no-labels/{z}/{x}/{y}.png'
               //~ })
           //~ }),
           new ol.layer.Tile({
               title: 'ESRI World Imagery',
               source: esri.new_source('satellite')
           }),
           new ol.layer.Tile({
               title: 'ESRI World Street Map',
               source: esri.new_source('street')
           }),
           watercolor,
           //~ new ol.layer.Vector({
               //~ title: 'None',
               //~ source: new ol.source.Vector({
               //~ })
           //~ }),
       ];
       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 map = this.map = new ol.Map({
           target: chartlet_div,
           layers: [
               new ol.layer.Group({
                   'title': 'Base',
                   layers: baseLayers
               }),
               new ol.layer.Group({
                   title: 'Layers',
                   layers: overlaidLayers
               })
           ],
           view: new ol.View({
               center: ol.proj.transform([this.params.lon, this.params.lat], 'EPSG:4326', 'EPSG:3857'),
               zoom: this.params.zoom
           }),
           controls: ol.control.defaults({
               attributionOptions: /** @type {olx.control.AttributionOptions} */ ({
                   collapsible: false
               })
           })
       });
       map.addControl(new ol.control.ScaleLine({
           units: 'nautical'
       }));
       loadWikiCss('MediaWiki:Ol3-layerswitcher.css');
       loadWikiScript("MediaWiki: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.addCoordinateGrid();
       var page = this.params.page;
       var _this = this;
       if (page) {
           loadWikiScript('MediaWiki:GetKml.js', function () {
               getKml(
                   {
                       page: page,
                       decorated: true
                   },
                   _this.addPOIs.bind(_this)
               );
           });
           loadWikiCss('MediaWiki:Ol3-popup.css');
           loadWikiScript("MediaWiki: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.addCoordinateGrid = 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 coord_grid = new ol.layer.Vector({
           title: 'Coordinate grid',
           visible: false,
           source: new ol.source.Vector({
               loader: loader,
               strategy: ol.loadingstrategy.bbox
           })
       });
       coord_grid.set('noclickable', true);
       // add to the proper layer group
       this.addNonBaseLayer(coord_grid);
       var onChangeCenterZoom = function () {
           coord_grid.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,
'
' + feature.get("name") + '
' + '
' + feature.get("styleUrl").split('#')[1] + '
' + '
' + feature.get("description") + '
'
               );
           } 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;
   }
   loadWikiCss('CruisersWiki:Ol3chartlet.css');
   loadCss("http://cdnjs.cloudflare.com/ajax/libs/ol3/3.13.1/ol.css");
   // use debug version, to allow patch below
   loadScript("http://cdnjs.cloudflare.com/ajax/libs/ol3/3.13.1/ol-debug.js", function () {
       if (typeof ol === 'undefined') {
           return;
       }
       // patch ol.xml as /extensions/TreeAndMenu/dtree.js overwrites Node
       ol.xml.isNode = goog.userAgent.IE ? ol.xml.isNodeIE_ : function(value) {
           //   return value instanceof Node;
           return typeof value.nodeName === "string";
       };
       $chartlets.each( function () {
           new ol3Chartlet(this);
       });
   });
});
Personal tools
advertisement
Friends of Cruisers Wiki