From CruisersWiki
//
/*
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 || this.params.displayPOIs)
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.trackHash()
this.addGraticule();
this.params.page && this.loadPOIs(this.params.page);
} else if (this.params.displayPOIs) {
this.loadPOIs();
}
};
// 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.loadPOIs = function (page) {
var addPOIs = this.addPOIs.bind(this);
var initPopups = this.initPopups.bind(this);
loadWikiScript('CruisersWiki:GetKml.js', function () {
getKml(
{
page: page,
decorated: true
},
addPOIs
);
});
loadWikiCss('CruisersWiki:Ol3-popup.css');
loadWikiScript("CruisersWiki:Ol3-popup.js", initPopups);
};
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;
} else if (key == 'displaypois') {
out.displayPOIs = val;
}
}
return out;
}
function round(val) {
var fact = 100000;
return Math.round(val * fact) / fact;
}
function chartletStart(secondCall) {
var $chartlets = $('.chartlet-test');
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";
};
}
$chartlets.each( function () {
new ol3Chartlet(this);
});
}
};
addOnloadHook(chartletStart);
})();
//