CruisersWiki:TOl3chartlet.js

From CruisersWiki

(Difference between revisions)
Jump to: navigation, search
Line 26: Line 26:
         },
         },
-
         logoTemplate: '<div><a id="navionics-logo" href="http://www.navionics.com/" target="_blank"><span></span></a></div>',
+
         attributionTemplate: '<div><a id="navionics-logo" href="http://www.navionics.com/" target="_blank"><span></span></a></div><div id="navionics-acknowledgements"><div><a href="http://www.navionics.com/en/acknowledgements" target="_blank">Acknowledgements</a><span> | Not to be used for navigation</span></div></div>',
-
 
+
-
        acknowledgementsTemplate: '<div id="navionics-acknowledgements"><div><a href="http://www.navionics.com/en/acknowledgements" target="_blank">Acknowledgements</a><span> | Not to be used for navigation</span></div></div>',
+
     }
     }
Line 106: Line 104:
     }
     }
-
     Navionics.setAttributionControl = function ( map, template ) {
+
     Navionics.setAttribution = function ( map ) {
-
         var control = new ol.control.Control({ element: $( template ).get( 0 ) })
+
         var control = new ol.control.Control({ element: $( Navionics.attributionTemplate ).get( 0 ) })
         map.addControl( control )
         map.addControl( control )
-
    }
 
-
 
-
    Navionics.setAttribution = function ( map ) {
 
-
        Navionics.setAttributionControl( map, Navionics.logoTemplate )
 
-
        Navionics.setAttributionControl( map, Navionics.acknowledgementsTemplate )
 
     }
     }

Revision as of 12:55, 25 June 2017

//
/*
   ol3Chartlet.js

   Copyright (c) 2016 Vadim Shlyakhov
   Licensed MIT
*/

(function () {

    var Navionics = {
        token: null,
        KEY: 'Navionics_webapi_00572',
        DOMAIN: 'www.cruiserswiki.org',
        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',
        depthUnits: {
            'm': 1, 'metre': 1, 'meter': 1,
            'ft': 2, 'feet': 2,
            'fathom': 3,
        },

        attributionTemplate: '<div><a id="navionics-logo" href="http://www.navionics.com/" target="_blank"><span></span></a></div><div id="navionics-acknowledgements"><div><a href="http://www.navionics.com/en/acknowledgements" target="_blank">Acknowledgements</a><span> | Not to be used for navigation</span></div></div>',
    }

    Navionics.getToken = function () {
        if ( Navionics.token != null )
            return Navionics.token
        var url = Navionics.BASE_TILE_SERVER + Navionics.KEY_REQ_SUFFIX  + '/' + Navionics.KEY + '/' + Navionics.DOMAIN
        return Navionics.token = Promise.resolve( $.ajax({
                url: url,
                crossDomain: true,
                dataType: 'text',
                //cache: false,
            })
        )
        .catch( function( err ) {
          return console.log( 'Navionics.getToken', err )
        })
    }

    Navionics.layer = function ( options ) {
        options = options || {}
        var layerOptions = {
            title: options.title,
            source: new Navionics.source( options )
        }

        ol.layer.Tile.call( this, layerOptions )
        this.on( 'change:visible', this.onChange.bind( this ))
    }

    ol.inherits( Navionics.layer, ol.layer.Tile )

    Navionics.layer.prototype.onChange = function ( evt ) {
        console.log( evt )
    }
        
    Navionics.source = function ( options ) {
        var sourceOptions = {
            crossOrigin: 'anonymous',
/*            
            attributions: [
                new ol.Attribution({
                    html: Navionics.disclaimer_msg
                })
            ],
*/            
            maxResolution: Navionics.MAX_RESOLUTION,
            minResolution: Navionics.MIN_RESOLUTION
        }
        ol.source.XYZ.call( this, sourceOptions )

        var self = this
        Navionics.getToken()
        .then( function ( token ) {
            var url = Navionics.createUrl( token, options )
            self.setUrl( url )
        })
    }

    ol.inherits( Navionics.source, ol.source.XYZ )

    Navionics.createUrl = function ( token, options ) { // sonar, overlay, depthUnit, safeDepth, showUGC
        options = options || {}
        var layerConfig = [
            'config',
            Navionics.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: token
        });
        return Navionics.BASE_TILE_SERVER + Navionics.TILE_SUFFIX + '?' + params
    }

    Navionics.setAttribution = function ( map ) {
        var control = new ol.control.Control({ element: $( Navionics.attributionTemplate ).get( 0 ) })
        map.addControl( control )
    }

    var Esri = {
        uri_map: {
            '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.source = function ( id ) {
        ol.source.TileArcGISRest.call( this, {
            url: Esri.uri_map[ id ],
            params: {
                FORMAT: 'JPG',
                TRANSPARENT: false,
            },
            attributions: [
                new ol.Attribution({
                    html: 'Tiles by ESRI <a href="' + Esri.uri_map[ id ] + '">Acknowledgements</a>'
                })
            ]
        })
    };

    ol.inherits( Esri.source, ol.source.TileArcGISRest )
*/
    Esri.source = function ( id ) {
        ol.source.XYZ.call( this, {
            url: Esri.uri_map[ id ] + '/tile/{z}/{y}/{x}',
            crossOrigin: null,
            attributions: [
                new ol.Attribution({
                    html: 'Tiles by ESRI <a href="' + Esri.uri_map[ id ] + '">Acknowledgements</a>'
                })
            ],
        })
    };

    ol.inherits( Esri.source, ol.source.XYZ )

    var baselayersGroupName = 'Base';
    var overlaysGroupName = 'Overlays';

    function ol3Chartlet(chartlet_div, standalone) {
        this.styleLoadHooks = [];

        console.log('ol3Chartlet');

        this.params = parseParams(standalone && location.hash ? decodeURI(location.hash.slice(1)) : $(chartlet_div).text());
        this.params.standalone = standalone;

        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 Navionics.layer({ title: 'Navionics' })
        var nx_layer_ovl = new Navionics.layer({ 
            title: 'Navionics Boating',
            transparency: true,
            })

        var overlays = [
            //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: new Esri.source( 'satellite' )
        });
        var esri_street = new ol.layer.Tile({
            title: 'ESRI World Street Map',
            source: new Esri.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 = [
            // osm,
            // esri_world,
            // esri_street,
            // osm_base,
            // no_background,
            watercolor,
            // 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: baselayersGroupName,
                layers: baseLayers
            }),
            new ol.layer.Group({
                    title: overlaysGroupName,
                    layers: overlays
            })
        ];

        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
                }
            }).extend([
                new ol.control.FullScreen(),
                new ol.control.ScaleLine({
                    units: 'nautical'
                })
            ])
        });

        Navionics.setAttribution( this.map )

        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.params.page && this.addPoiLayer();
            this.trackHash();
            this.addGraticule();
        } else if (this.params.pageFeatures) {
            this.addPoiLayer();
        }
    };

    // add to a layer group
    ol3Chartlet.prototype.addNonBaseLayer = function (new_layer) {
        this.map.getLayers().forEach(
            function(layer) {
                if (layer.get('title') === overlaysGroupName) {
                    layer.getLayers().push(new_layer);
                }
            }
        );
    };

    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);
            }
        });
    };

    // Create the graticule
    ol3Chartlet.prototype.addGraticule = function () { // after http://map.openseamap.org/javascript/grid_wgs.js
        var this_ = this;
        loadWikiScript('CruisersWiki:Ol3chartlet-graticule.js', function () {
            var layer = graticuleLayer(this_.map);
            this_.addNonBaseLayer(layer);
        });
        /*
        var graticule = new ol.Graticule({
            map: this.map,
            // the style to use for the lines, optional.
            strokeStyle: new ol.style.Stroke({
                color: 'rgba(255,120,0,0.9)',
                width: 2,
                lineDash: [0.5, 4]
            })
        });
        // graticule.setMap(this.map);
        */
    };

    ol3Chartlet.prototype.addPoiLayer = function () {
        var options = $.extend({}, this.params);

        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}
            */
            options.projection = projection;
            options.addFeature = addFeature;

            loadWikiScript(
                $('.chartlet-test').length == 0 ? 'CruisersWiki:Ol3chartlet-features.js' : 'CruisersWiki:Ol3chartlet-features-test.js',
                function () {
                    loadFeatures(options);
                }
            );
        };

        var source = new ol.source.Vector({
            loader: loader,
        });

        var layer = new ol.layer.Vector({
            title: 'POI',
            visible: true,
            style: styleFunction,
            source: source,
        });

        var this_ = this;

        var defferedFeatures = [];
        function addFeature (feature) {
            if (!this_.styles) {
                defferedFeatures.push(feature);
                return;
            }
            if (defferedFeatures) {
                source.addFeatures(defferedFeatures);
                defferedFeatures = null;
            }
            if (feature) {
                source.addFeature(feature);
            }
        };

        this.styleLoadHooks.push(addFeature);

        function styleFunction (feature, resolution) {
            var category = feature.get('category') || 'other';
            var geom = feature.getGeometry();
            var style;
            if (geom.getType() == 'Point') {
                var styleOptions = {
                    //zIndex: 2
                };
                options.icons && (styleOptions.image = this_.getStyle(category, 'Icon'));
                options.captions && (styleOptions.text = this_.getTextStyle(category, feature.get('name')));
                style = new ol.style.Style(styleOptions);
            } else {
                style = new ol.style.Style({
                    fill: this_.getStyle(category, 'Fill'),
                    stroke: this_.getStyle(category, 'Stroke'),
                });
            }
            return style;
        };

        this.addNonBaseLayer(layer);

        loadWikiCss('CruisersWiki:Ol3-popup.css');
        loadWikiScript("CruisersWiki:Ol3-popup.js", this.initPopups.bind(this));
        this.trackPointer();
        this.highlightFeatures();
        this.loadStyles();
    };

    ol3Chartlet.prototype.styles = null;
    ol3Chartlet.prototype.styleLoadHooks = null;

    ol3Chartlet.prototype.loadStyles = function () {
        var this_ = this;
        loadWikiScript("CruisersWiki:Ol3chartlet-styles-test.js", function () {
            loadStyles()
            .then (function (styles) {
                this_.styles = styles;
                var hooks = this_.styleLoadHooks;
                this_.styleLoadHooks = [];
                hooks.map( function(fn) { fn() });
            });
        });
    };

    ol3Chartlet.prototype.getStyle = function (category, subType) {
        var style = this.styles[category + '.' + subType];
        return style ? style : this.styles['default'  + '.' + subType];
    }

    ol3Chartlet.prototype.getTextStyle = function (category, text) {
        var style = this.getStyle(category, 'Text').clone();
        style.setText(text);
        return style;
    }

    ol3Chartlet.prototype.isClickableLayer = function (layer) {
        return ! layer.get('noclickable');
    };

    ol3Chartlet.prototype.initPopups = function () {
        var map = this.map;
        var popup = new ol.Overlay.Popup();
        map.addOverlay(popup);

        var popTemplate =
            '<div class="cw-popup-name"><a href="{href}" target="_blank">{name}</a></div>\n' +
            '<div class="cw-popup-category">{category}</div>\n' +
            '<div class="cw-popup-content">{content}</div>';

        // display popup on click
        map.on('click', function(evt) {
            var feature = map.forEachFeatureAtPixel(
                evt.pixel,
                function(feature) {
                  return feature;
                },
                null,
                this.isClickableLayer
                );
            if (feature && ! feature.get('noclickable')) {
                var data = {
                    href: feature.get("url"),
                    name: feature.get("name"),
                    category: feature.get("category"),
                    content: feature.get("description"),
                };
                popup.show(evt.coordinate, format(popTemplate, data));
            } else {
                popup.hide();
            }
        });
    };

    ol3Chartlet.prototype.trackPointer = function () {
        // change mouse cursor when over marker
        var map = this.map;
        map.on('pointermove', function(e) {
            //~ if (e.dragging) {
              //~ $(element).popover('destroy');
              //~ return;
            //~ }
            var pixel = map.getEventPixel(e.originalEvent);
            var hit = map.hasFeatureAtPixel(pixel, this.isClickableLayer);
            map.getTarget().style.cursor = hit ? 'pointer' : '';
        });
    };

    ol3Chartlet.prototype.highlightFeatures = function () {
        var map = this.map;
        var highlightStyle;
        this.styleLoadHooks.push(function () {
            highlightStyle = new ol.style.Style({
                fill: this.getStyle('highlight', 'Fill'),
                stroke: this.getStyle('highlight', 'Stroke'),
            });
        }.bind(this));

        function styleFunction (feature, resolution) {
            var geom = feature.getGeometry();
            if (geom.getType() != 'Point') {
                return highlightStyle;
            }
        }

        var highlightOverlay = new ol.layer.Vector({
            source: new ol.source.Vector(),
            map: map,
            style: styleFunction
        });
        highlightOverlay.set('noclickable', true);

        var highlight;

        var highlightFeature = function(evt) {
            if (evt.dragging) {
                return;
            }
            var pixel = map.getEventPixel(evt.originalEvent);

            var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
                return feature;
            });

            if (feature !== highlight) {
                if (highlight) {
                    highlightOverlay.getSource().removeFeature(highlight);
                }
                if (feature) {
                    highlightOverlay.getSource().addFeature(feature);
                }
                highlight = feature;
            }
        };

        map.on('pointermove', highlightFeature);
    };

    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 = {
            icons: true,
            //recursive: 1,
            //childrenlocations: true,
            //captions: true,
        };

        var params = param_str.split('|');
        for (var i=0, li = params.length; i < li; i++) {
            var keyVal = params[i].split('=', 2);
            var key = $.trim(keyVal[0] || '').toLowerCase();
            var val = $.trim(keyVal[1] || '');
            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;
            } else if (key == 'pagefeatures') {
                out.pageFeatures = !!val;
            } else if (key == 'captions') {
                out.captions = !!val;
            } else if (key == 'childrenlocations') {
                out.childrenlocations = true;
                out.recursive = 1;
            } else if (key == 'recursive') {
                out.recursive = val;
            } else if (key == 'icons') {
                out.icons = !!val;
            } else if (key == 'nopagelocation') {
                out.nopagelocation = !!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-debug.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";
                };
            }

            var standalone_div = $('#chartlet-standalone')[0];

            // 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_div && location.hash) {
                var body = document.body;
                $('body').addClass('chartlet-extend');
                while (body.firstChild) {
                    body.removeChild(body.firstChild);
                }
                body.appendChild(standalone_div);

                setImmediate(function() {
                    new ol3Chartlet(standalone_div, !! standalone_div);
                });
            } else {
                $chartlets.each( function () {
                    new ol3Chartlet(this);
                });
            }

        }
    };

    addOnloadHook(chartletStart);

})();
// 
Personal tools
advertisement
Friends of Cruisers Wiki