Merge branch 'master' into patch-4
This commit is contained in:
@@ -106,6 +106,33 @@ function includeTypes(doclet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultExports = {};
|
||||||
|
const path = require('path');
|
||||||
|
const moduleRoot = path.join(process.cwd(), 'src');
|
||||||
|
|
||||||
|
// Tag default exported Identifiers because their name should be the same as the module name.
|
||||||
|
exports.astNodeVisitor = {
|
||||||
|
visitNode: function(node, e, parser, currentSourceName) {
|
||||||
|
if (node.type === 'Identifier' && node.parent.type === 'ExportDefaultDeclaration') {
|
||||||
|
const modulePath = path.relative(moduleRoot, currentSourceName).replace(/\.js$/, '');
|
||||||
|
defaultExports['module:' + modulePath.replace(/\\/g, '/') + '~' + node.name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function sortOtherMembers(doclet) {
|
||||||
|
if (doclet.fires) {
|
||||||
|
doclet.fires.sort(function(a, b) {
|
||||||
|
return a.split(/#?event:/)[1] < b.split(/#?event:/)[1] ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (doclet.observables) {
|
||||||
|
doclet.observables.sort(function(a, b) {
|
||||||
|
return a.name < b.name ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.handlers = {
|
exports.handlers = {
|
||||||
|
|
||||||
newDoclet: function(e) {
|
newDoclet: function(e) {
|
||||||
@@ -135,16 +162,7 @@ exports.handlers = {
|
|||||||
if (doclet.kind == 'class') {
|
if (doclet.kind == 'class') {
|
||||||
includeAugments(doclet);
|
includeAugments(doclet);
|
||||||
}
|
}
|
||||||
if (doclet.fires) {
|
sortOtherMembers(doclet);
|
||||||
doclet.fires.sort(function(a, b) {
|
|
||||||
return a.split(/#?event:/)[1] < b.split(/#?event:/)[1] ? -1 : 1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (doclet.observables) {
|
|
||||||
doclet.observables.sort(function(a, b) {
|
|
||||||
return a.name < b.name ? -1 : 1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Always document namespaces and items with stability annotation
|
// Always document namespaces and items with stability annotation
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -161,6 +179,7 @@ exports.handlers = {
|
|||||||
// constructor from the docs.
|
// constructor from the docs.
|
||||||
doclet._hideConstructor = true;
|
doclet._hideConstructor = true;
|
||||||
includeAugments(doclet);
|
includeAugments(doclet);
|
||||||
|
sortOtherMembers(doclet);
|
||||||
} else if (!doclet._hideConstructor && !(doclet.kind == 'typedef' && doclet.longname in types)) {
|
} else if (!doclet._hideConstructor && !(doclet.kind == 'typedef' && doclet.longname in types)) {
|
||||||
// Remove all other undocumented symbols
|
// Remove all other undocumented symbols
|
||||||
doclet.undocumented = true;
|
doclet.undocumented = true;
|
||||||
@@ -169,6 +188,15 @@ exports.handlers = {
|
|||||||
delete doclet.undocumented;
|
delete doclet.undocumented;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
processingComplete(e) {
|
||||||
|
const byLongname = e.doclets.index.longname;
|
||||||
|
for (const name in defaultExports) {
|
||||||
|
byLongname[name].forEach(function(doclet) {
|
||||||
|
doclet.isDefaultExport = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ const path = require('jsdoc/lib/jsdoc/path');
|
|||||||
const taffy = require('taffydb').taffy;
|
const taffy = require('taffydb').taffy;
|
||||||
const handle = require('jsdoc/lib/jsdoc/util/error').handle;
|
const handle = require('jsdoc/lib/jsdoc/util/error').handle;
|
||||||
const helper = require('jsdoc/lib/jsdoc/util/templateHelper');
|
const helper = require('jsdoc/lib/jsdoc/util/templateHelper');
|
||||||
const _ = require('underscore');
|
|
||||||
const htmlsafe = helper.htmlsafe;
|
const htmlsafe = helper.htmlsafe;
|
||||||
const linkto = helper.linkto;
|
const linkto = helper.linkto;
|
||||||
const resolveAuthorLinks = helper.resolveAuthorLinks;
|
const resolveAuthorLinks = helper.resolveAuthorLinks;
|
||||||
@@ -188,10 +187,12 @@ function attachModuleSymbols(doclets, modules) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrettyName(longname) {
|
function getPrettyName(doclet) {
|
||||||
return longname
|
const fullname = doclet.longname.replace('module:', '');
|
||||||
.split('~')[0]
|
if (doclet.isDefaultExport) {
|
||||||
.replace('module:', '');
|
return fullname.split('~')[0];
|
||||||
|
}
|
||||||
|
return fullname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,27 +210,13 @@ function getPrettyName(longname) {
|
|||||||
*/
|
*/
|
||||||
function buildNav(members) {
|
function buildNav(members) {
|
||||||
const nav = [];
|
const nav = [];
|
||||||
// merge namespaces and classes, then sort
|
members.classes.forEach(function(v) {
|
||||||
const merged = members.modules.concat(members.classes);
|
|
||||||
merged.sort(function(a, b) {
|
|
||||||
const prettyNameA = getPrettyName(a.longname).toLowerCase();
|
|
||||||
const prettyNameB = getPrettyName(b.longname).toLowerCase();
|
|
||||||
if (prettyNameA > prettyNameB) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (prettyNameA < prettyNameB) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
_.each(merged, function(v) {
|
|
||||||
// exclude interfaces from sidebar
|
// exclude interfaces from sidebar
|
||||||
if (v.interface !== true && v.kind === 'class') {
|
if (v.interface !== true) {
|
||||||
nav.push({
|
nav.push({
|
||||||
type: 'class',
|
type: 'class',
|
||||||
longname: v.longname,
|
longname: v.longname,
|
||||||
prettyname: getPrettyName(v.longname),
|
prettyname: getPrettyName(v),
|
||||||
name: v.name,
|
name: v.name,
|
||||||
module: find({
|
module: find({
|
||||||
kind: 'module',
|
kind: 'module',
|
||||||
@@ -253,44 +240,57 @@ function buildNav(members) {
|
|||||||
memberof: v.longname
|
memberof: v.longname
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else if (v.kind == 'module') {
|
|
||||||
const classes = find({
|
|
||||||
kind: 'class',
|
|
||||||
memberof: v.longname
|
|
||||||
});
|
|
||||||
const members = find({
|
|
||||||
kind: 'member',
|
|
||||||
memberof: v.longname
|
|
||||||
});
|
|
||||||
const methods = find({
|
|
||||||
kind: 'function',
|
|
||||||
memberof: v.longname
|
|
||||||
});
|
|
||||||
const typedefs = find({
|
|
||||||
kind: 'typedef',
|
|
||||||
memberof: v.longname
|
|
||||||
});
|
|
||||||
const events = find({
|
|
||||||
kind: 'event',
|
|
||||||
memberof: v.longname
|
|
||||||
});
|
|
||||||
// Only add modules that contain more than just classes with their
|
|
||||||
// associated Options typedef
|
|
||||||
if (typedefs.length > classes.length || members.length + methods.length > 0) {
|
|
||||||
nav.push({
|
|
||||||
type: 'module',
|
|
||||||
longname: v.longname,
|
|
||||||
prettyname: getPrettyName(v.longname),
|
|
||||||
name: v.name,
|
|
||||||
members: members,
|
|
||||||
methods: methods,
|
|
||||||
typedefs: typedefs,
|
|
||||||
fires: v.fires,
|
|
||||||
events: events
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
members.modules.forEach(function(v) {
|
||||||
|
const classes = find({
|
||||||
|
kind: 'class',
|
||||||
|
memberof: v.longname
|
||||||
|
});
|
||||||
|
const members = find({
|
||||||
|
kind: 'member',
|
||||||
|
memberof: v.longname
|
||||||
|
});
|
||||||
|
const methods = find({
|
||||||
|
kind: 'function',
|
||||||
|
memberof: v.longname
|
||||||
|
});
|
||||||
|
const typedefs = find({
|
||||||
|
kind: 'typedef',
|
||||||
|
memberof: v.longname
|
||||||
|
});
|
||||||
|
const events = find({
|
||||||
|
kind: 'event',
|
||||||
|
memberof: v.longname
|
||||||
|
});
|
||||||
|
// Only add modules that contain more than just classes with their
|
||||||
|
// associated Options typedef
|
||||||
|
if (typedefs.length > classes.length || members.length + methods.length > 0) {
|
||||||
|
nav.push({
|
||||||
|
type: 'module',
|
||||||
|
longname: v.longname,
|
||||||
|
prettyname: getPrettyName(v),
|
||||||
|
name: v.name,
|
||||||
|
members: members,
|
||||||
|
methods: methods,
|
||||||
|
typedefs: typedefs,
|
||||||
|
fires: v.fires,
|
||||||
|
events: events
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nav.sort(function(a, b) {
|
||||||
|
const prettyNameA = a.prettyname.toLowerCase();
|
||||||
|
const prettyNameB = b.prettyname.toLowerCase();
|
||||||
|
if (prettyNameA > prettyNameB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (prettyNameA < prettyNameB) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
return nav;
|
return nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +1,258 @@
|
|||||||
$(function () {
|
$(function () {
|
||||||
// Search Items
|
'use strict';
|
||||||
$('#include_modules').change(function (e) {
|
|
||||||
console.log('change');
|
|
||||||
if ($(this).is(':checked')) {
|
|
||||||
|
|
||||||
|
// Allow user configuration?
|
||||||
|
const allowRegex = true;
|
||||||
|
const minInputForSearch = 1;
|
||||||
|
const minInputForFullText = 2;
|
||||||
|
const expandAllOnInputWithoutSearch = true;
|
||||||
|
|
||||||
|
function constructRegex(searchTerm, makeRe, allowRegex) {
|
||||||
|
try {
|
||||||
|
if (allowRegex) {
|
||||||
|
return makeRe(searchTerm);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
// In case of invalid regexp fall back to non-regexp, but still allow . to match /
|
||||||
|
return makeRe(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\./g, '[./]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWeightFunction(searchTerm, allowRegex) {
|
||||||
|
function makeRe(searchTerm) {
|
||||||
|
return {
|
||||||
|
begin: new RegExp('\\b' + searchTerm), // Begin matches word boundary
|
||||||
|
baseName: new RegExp('\\b' + searchTerm + '[^/]*$'), // Begin matches word boundary of class / module name
|
||||||
|
fullName: new RegExp('\\b' + searchTerm + '(?:[~.]|$)'), // Complete word(s) of class / module matches
|
||||||
|
completeName: new RegExp('^' + searchTerm + '$') // Match from start to finish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const re = constructRegex(searchTerm, makeRe, allowRegex);
|
||||||
|
return function (matchedItem, beginOnly) {
|
||||||
|
// We could get smarter on the weight here
|
||||||
|
const name = matchedItem.dataset.name;
|
||||||
|
if (beginOnly) {
|
||||||
|
return re.baseName.test(name) ? 100 : 1;
|
||||||
|
}
|
||||||
|
// If everything else is equal, prefer shorter names, and prefer classes over modules
|
||||||
|
let weight = 10000 + matchedItem.dataset.longname.length - name.length * 100;
|
||||||
|
if (name.match(re.begin)) {
|
||||||
|
weight += 10000;
|
||||||
|
if (re.baseName.test(name)) {
|
||||||
|
weight += 10000;
|
||||||
|
if (re.fullName.test(name)) {
|
||||||
|
weight += 10000;
|
||||||
|
if (re.completeName.test(name)) {
|
||||||
|
weight += 10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const search = (function () {
|
||||||
|
const $navList = $('.navigation-list');
|
||||||
|
const navListNode = $navList.get(0);
|
||||||
|
let $classItems;
|
||||||
|
let $members;
|
||||||
|
let stateClass = (function () {
|
||||||
|
$navList.removeClass('search-started searching');
|
||||||
|
$navList.addClass('search-empty');
|
||||||
|
return 'search-empty';
|
||||||
|
})();
|
||||||
|
let manualToggles = {};
|
||||||
|
|
||||||
|
// Show an item related a current documentation automatically
|
||||||
|
const longname = $('.page-title').data('filename')
|
||||||
|
.replace(/\.[a-z]+$/, '')
|
||||||
|
.replace('module-', 'module:')
|
||||||
|
.replace(/_/g, '/')
|
||||||
|
.replace(/-/g, '~');
|
||||||
|
const currentItem = navListNode.querySelector('.item[data-longname="' + longname + '"]');
|
||||||
|
if (currentItem) {
|
||||||
|
$navList.prepend(currentItem);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
$navList: $navList,
|
||||||
|
$currentItem: currentItem ? $(currentItem) : undefined,
|
||||||
|
lastSearchTerm: undefined,
|
||||||
|
lastState: {},
|
||||||
|
getClassList: function () {
|
||||||
|
return $classItems || ($classItems = $navList.find('li.item'));
|
||||||
|
},
|
||||||
|
getMembers: function () {
|
||||||
|
return $members || ($members = $navList.find('.item li'));
|
||||||
|
},
|
||||||
|
changeStateClass: function (newClass) {
|
||||||
|
if (newClass !== stateClass) {
|
||||||
|
navListNode.classList.remove(stateClass);
|
||||||
|
navListNode.classList.add(newClass);
|
||||||
|
stateClass = newClass;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
manualToggle: function ($node, show) {
|
||||||
|
$node.addClass('toggle-manual');
|
||||||
|
$node.toggleClass('toggle-manual-hide', !show);
|
||||||
|
$node.toggleClass('toggle-manual-show', show);
|
||||||
|
manualToggles[$node.data('longname')] = $node;
|
||||||
|
},
|
||||||
|
clearManualToggles: function() {
|
||||||
|
for (let clsName in manualToggles) {
|
||||||
|
manualToggles[clsName].removeClass('toggle-manual toggle-manual-show toggle-manual-hide');
|
||||||
|
}
|
||||||
|
manualToggles = {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
const dummy = {subItems: {}};
|
||||||
|
function clearOldMatches(lastState, searchState) {
|
||||||
|
for (let itemName in lastState) {
|
||||||
|
const lastItem = lastState[itemName];
|
||||||
|
const item = searchState[itemName];
|
||||||
|
if (!item) {
|
||||||
|
lastItem.item.classList.remove('match');
|
||||||
|
}
|
||||||
|
if (lastItem.subItems) {
|
||||||
|
clearOldMatches(lastItem.subItems, (item || dummy).subItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch(searchTerm) {
|
||||||
|
searchTerm = searchTerm.toLowerCase();
|
||||||
|
const lastSearchTerm = search.lastSearchTerm;
|
||||||
|
if (searchTerm === lastSearchTerm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid layout reflow by scrolling to top first.
|
||||||
|
search.$navList.scrollTop(0);
|
||||||
|
search.lastSearchTerm = searchTerm;
|
||||||
|
search.clearManualToggles();
|
||||||
|
|
||||||
|
if (searchTerm.length < minInputForSearch) {
|
||||||
|
const state = searchTerm.length && expandAllOnInputWithoutSearch ? 'search-started' : 'search-empty';
|
||||||
|
search.changeStateClass(state);
|
||||||
|
if (lastSearchTerm !== undefined && lastSearchTerm.length >= minInputForSearch) {
|
||||||
|
// Restore the original, sorted order
|
||||||
|
search.$navList.append(search.getClassList());
|
||||||
|
}
|
||||||
|
if (state === 'search-empty' && search.$currentItem) {
|
||||||
|
search.manualToggle(search.$currentItem, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
search.changeStateClass('searching');
|
||||||
}
|
searchTerm = searchTerm.toLowerCase();
|
||||||
});
|
const beginOnly = searchTerm.length < minInputForFullText;
|
||||||
|
const getSearchWeight = getWeightFunction(searchTerm, allowRegex);
|
||||||
var getSearchWeight = function (searchTerm, $matchedItem) {
|
const re = constructRegex(searchTerm, function (searchTerm) {
|
||||||
let weight = 0;
|
return new RegExp((beginOnly ? '\\b' : '') + searchTerm);
|
||||||
// We could get smarter on the weight here
|
}, allowRegex);
|
||||||
if ($matchedItem.data('shortname')
|
const navList = search.$navList.get(0);
|
||||||
&& $matchedItem.data('shortname').toLowerCase() === searchTerm.toLowerCase()) {
|
const classes = [];
|
||||||
weight++;
|
const searchState = {};
|
||||||
}
|
search.getClassList().each(function (i, classEntry) {
|
||||||
return weight;
|
const className = classEntry.dataset.longname;
|
||||||
};
|
if (!(className in searchState) && re.test(classEntry.dataset.name)) {
|
||||||
|
const cls = searchState[className] = {
|
||||||
// sort function callback
|
item: classEntry,
|
||||||
var weightSorter = function (a, b) {
|
// Do the weight thing
|
||||||
var aW = $(a).data('weight') || 0;
|
weight: getSearchWeight(classEntry, beginOnly) * 100000,
|
||||||
var bW = $(b).data('weight') || 0;
|
subItems: {}
|
||||||
return bW - aW;
|
};
|
||||||
};
|
classes.push(cls);
|
||||||
|
classEntry.classList.add('match');
|
||||||
// Search Items
|
|
||||||
$('#search').on('keyup', function (e) {
|
|
||||||
var value = $(this).val();
|
|
||||||
var $el = $('.navigation');
|
|
||||||
|
|
||||||
if (value && value.length > 1) {
|
|
||||||
var regexp = new RegExp(value, 'i');
|
|
||||||
$el.find('li, .member-list').hide();
|
|
||||||
|
|
||||||
$el.find('li').each(function (i, v) {
|
|
||||||
const $item = $(v);
|
|
||||||
const name = $item.data('name');
|
|
||||||
|
|
||||||
if (name && regexp.test(name)) {
|
|
||||||
const $classEntry = $item.closest('.item');
|
|
||||||
const $members = $item.closest('.member-list');
|
|
||||||
|
|
||||||
// Do the weight thing
|
|
||||||
$classEntry.removeData('weight');
|
|
||||||
$classEntry.show();
|
|
||||||
const weight = getSearchWeight(value, $classEntry);
|
|
||||||
$classEntry.data('weight', weight);
|
|
||||||
|
|
||||||
$members.show();
|
|
||||||
$classEntry.show();
|
|
||||||
$item.show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
search.getMembers().each(function (i, li) {
|
||||||
|
const name = li.dataset.name;
|
||||||
|
if (re.test(name)) {
|
||||||
|
const itemMember = li.parentElement.parentElement;
|
||||||
|
const classEntry = itemMember.parentElement;
|
||||||
|
const className = classEntry.dataset.longname;
|
||||||
|
let cls = searchState[className];
|
||||||
|
if (!cls) {
|
||||||
|
cls = searchState[className] = {
|
||||||
|
item: classEntry,
|
||||||
|
weight: 0,
|
||||||
|
subItems: {}
|
||||||
|
};
|
||||||
|
classes.push(cls);
|
||||||
|
classEntry.classList.add('match');
|
||||||
|
}
|
||||||
|
cls.weight += getSearchWeight(li, true);
|
||||||
|
const memberType = itemMember.dataset.type;
|
||||||
|
let members = cls.subItems[memberType];
|
||||||
|
if (!members) {
|
||||||
|
members = cls.subItems[memberType] = {
|
||||||
|
item: itemMember,
|
||||||
|
subItems: {}
|
||||||
|
};
|
||||||
|
itemMember.classList.add('match');
|
||||||
|
}
|
||||||
|
members.subItems[name] = { item: li };
|
||||||
|
li.classList.add('match');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clearOldMatches(search.lastState, searchState);
|
||||||
|
search.lastState = searchState;
|
||||||
|
|
||||||
$(".navigation ul.list li.item:visible")
|
classes.sort(function (a, b) {
|
||||||
.sort(weightSorter) // sort elements
|
return a.weight - b.weight;
|
||||||
.appendTo(".navigation ul.list"); // append again to the list
|
});
|
||||||
|
for (let i = classes.length - 1; i >= 0; --i) {
|
||||||
} else {
|
navList.appendChild(classes[i].item);
|
||||||
$el.find('.item, .member-list').show();
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$el.find('.list').scrollTop(0);
|
const searchInput = $('#search').get(0);
|
||||||
});
|
// Skip searches when typing fast.
|
||||||
|
let key;
|
||||||
|
function queueSearch() {
|
||||||
|
if (!key) {
|
||||||
|
key = setTimeout(function () {
|
||||||
|
key = undefined;
|
||||||
|
|
||||||
|
const searchTerm = searchInput.value;
|
||||||
|
doSearch(searchTerm);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search Items
|
||||||
|
searchInput.addEventListener('input', queueSearch);
|
||||||
|
doSearch(searchInput.value);
|
||||||
|
|
||||||
// Toggle when click an item element
|
// Toggle when click an item element
|
||||||
$('.navigation').on('click', '.toggle', function (e) {
|
search.$navList.on('click', '.toggle', function (e) {
|
||||||
$(this).parent().parent().find('.member-list').toggle();
|
if (event.target.tagName.toLowerCase() === 'a') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const clsItem = $(this).closest('.item');
|
||||||
|
let show;
|
||||||
|
if (clsItem.hasClass('toggle-manual-show')) {
|
||||||
|
show = false;
|
||||||
|
} else if (clsItem.hasClass('toggle-manual-hide')) {
|
||||||
|
show = true;
|
||||||
|
} else {
|
||||||
|
clsItem.find('.member-list li').each(function (i, v) {
|
||||||
|
show = $(v).is(':hidden');
|
||||||
|
return !show;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
search.manualToggle(clsItem, !!show);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show an item related a current documentation automatically
|
|
||||||
var filename = $('.page-title').data('filename')
|
|
||||||
.replace(/\.[a-z]+$/, '')
|
|
||||||
.replace('module-', 'module:')
|
|
||||||
.replace(/_/g, '/')
|
|
||||||
.replace(/-/g, '~');
|
|
||||||
var $currentItem = $('.navigation .item[data-name*="' + filename + '"]:eq(0)');
|
|
||||||
|
|
||||||
if ($currentItem.length) {
|
|
||||||
$currentItem
|
|
||||||
.remove()
|
|
||||||
.prependTo('.navigation .list')
|
|
||||||
.show()
|
|
||||||
.find('.member-list')
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto resizing on navigation
|
// Auto resizing on navigation
|
||||||
var _onResize = function () {
|
var _onResize = function () {
|
||||||
var height = $(window).height();
|
var height = $(window).height();
|
||||||
var $el = $('.navigation');
|
var $el = $('.navigation');
|
||||||
|
|
||||||
$el.height(height).find('.list').height(height - 133);
|
$el.height(height).find('.navigation-list').height(height - 133);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(window).on('resize', _onResize);
|
$(window).on('resize', _onResize);
|
||||||
@@ -137,22 +296,4 @@ $(function () {
|
|||||||
'<a href="' + link + textParts[1].replace('line ', '#L') + '">' +
|
'<a href="' + link + textParts[1].replace('line ', '#L') + '">' +
|
||||||
textParts[1] + '</a>';
|
textParts[1] + '</a>';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Highlighting current anchor
|
|
||||||
|
|
||||||
var anchors = $('.anchor');
|
|
||||||
var _onHashChange = function () {
|
|
||||||
var activeHash = window.document.location.hash
|
|
||||||
.replace(/\./g, '\\.') // Escape dot in element id
|
|
||||||
.replace(/\~/g, '\\~'); // Escape tilde in element id
|
|
||||||
|
|
||||||
anchors.removeClass('highlighted');
|
|
||||||
|
|
||||||
if (activeHash.length > 0) {
|
|
||||||
anchors.filter(activeHash).addClass('highlighted');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(window).on('hashchange', _onHashChange);
|
|
||||||
_onHashChange();
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ body {
|
|||||||
width: 0px;
|
width: 0px;
|
||||||
height: 0px;
|
height: 0px;
|
||||||
}
|
}
|
||||||
.nameContainer .anchor.highlighted + h4 {
|
/* Highlighting current anchor */
|
||||||
|
.nameContainer .anchor:target + h4 {
|
||||||
background-color: #faebcc;
|
background-color: #faebcc;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
@@ -123,7 +124,7 @@ li {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
border-color: #555;
|
border-color: #555;
|
||||||
}
|
}
|
||||||
.navigation .list {
|
.navigation .navigation-list {
|
||||||
padding: 10px 15px 0 15px;
|
padding: 10px 15px 0 15px;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@@ -135,6 +136,24 @@ li {
|
|||||||
border-bottom: 1px solid #333;
|
border-bottom: 1px solid #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navigation .glyphicon {
|
||||||
|
margin-right: 3px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.navigation .item .glyphicon:before {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.navigation .item.toggle-manual .glyphicon:before {
|
||||||
|
transition: transform .1s;
|
||||||
|
}
|
||||||
|
.navigation .item-class.toggle-manual-show .glyphicon:before {
|
||||||
|
/* With 90deg the icon slightly slides left at transition end */
|
||||||
|
transform: rotate(89.9deg);
|
||||||
|
}
|
||||||
|
.navigation .item-module.toggle-manual-show .glyphicon:before {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
.navigation li.perfect-match {
|
.navigation li.perfect-match {
|
||||||
border: 5px solid orange;
|
border: 5px solid orange;
|
||||||
}
|
}
|
||||||
@@ -147,8 +166,8 @@ li {
|
|||||||
}
|
}
|
||||||
.navigation li.item .title {
|
.navigation li.item .title {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
display: -ms-flexbox;
|
||||||
display: block;
|
display: flex;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
.navigation li.item .title a {
|
.navigation li.item .title a {
|
||||||
@@ -184,9 +203,41 @@ li {
|
|||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
.navigation li.item .member-list {
|
.navigation li.item .member-list {
|
||||||
display: none;
|
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* search state */
|
||||||
|
/* show all classes when search is empty */
|
||||||
|
.navigation-list.search-empty .item {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* hide all members by default when search is empty */
|
||||||
|
.navigation-list.search-empty .item .member-list {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* expand all members when input in search field available but too short to search */
|
||||||
|
.navigation-list.search-started li,
|
||||||
|
.navigation-list.search-started .member-list {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* when searching hide everything that is not a match */
|
||||||
|
.navigation-list.searching li,
|
||||||
|
.navigation-list.searching .member-list {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.navigation-list.searching .match {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
/* allow user to hide / show members */
|
||||||
|
.navigation-list .item.toggle-manual-show li,
|
||||||
|
.navigation-list .item.toggle-manual-show .member-list {
|
||||||
|
display: block!important;
|
||||||
|
}
|
||||||
|
.navigation-list:not(.searching) .item.toggle-manual-hide li,
|
||||||
|
.navigation-list:not(.searching) .item.toggle-manual-hide .member-list {
|
||||||
|
display: none!important;
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding: 20px 20px;
|
padding: 20px 20px;
|
||||||
margin-left: 250px;
|
margin-left: 250px;
|
||||||
|
|||||||
@@ -15,17 +15,17 @@ function getItemCssClass(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const printList = v => { ?>
|
const printList = v => { ?>
|
||||||
<li data-name="<?js= v.longname ?>"><?js
|
<li data-name="<?js= toShortName(v.name).toLowerCase() ?>"><?js
|
||||||
}
|
}
|
||||||
const printListWithStability = v => {
|
const printListWithStability = v => {
|
||||||
const cls = v.stability && v.stability !== 'stable' ? ' class="unstable"' : ''; ?>
|
const cls = v.stability && v.stability !== 'stable' ? ' class="unstable"' : ''; ?>
|
||||||
<li data-name="<?js= v.longname ?>"<?js= cls ?>><?js
|
<li data-name="<?js= toShortName(v.name).toLowerCase() ?>"<?js= cls ?>><?js
|
||||||
}
|
}
|
||||||
|
|
||||||
function listContent(item, title, listItemPrinter) {
|
function listContent(item, title, listItemPrinter) {
|
||||||
const type = title.toLowerCase();
|
const type = title.toLowerCase();
|
||||||
if (item[type] && item[type].length) { ?>
|
if (item[type] && item[type].length) { ?>
|
||||||
<div class="member-list">
|
<div class="member-list" data-type="<?js= type ?>">
|
||||||
<span class="subtitle"><?js= title ?></span>
|
<span class="subtitle"><?js= title ?></span>
|
||||||
<ul><?js
|
<ul><?js
|
||||||
item[type].forEach(function (v) {
|
item[type].forEach(function (v) {
|
||||||
@@ -40,12 +40,12 @@ function listContent(item, title, listItemPrinter) {
|
|||||||
<div class="search">
|
<div class="search">
|
||||||
<input id="search" type="text" class="form-control input-sm" placeholder="Search Documentation">
|
<input id="search" type="text" class="form-control input-sm" placeholder="Search Documentation">
|
||||||
</div>
|
</div>
|
||||||
<ul class="list"><?js
|
<ul class="navigation-list search-empty"><?js
|
||||||
this.nav.forEach(function (item) { ?>
|
this.nav.forEach(function (item) { ?>
|
||||||
<li class="item" data-name="<?js= item.longname ?>" data-shortname="<?js= item.name.toLowerCase() ?>">
|
<li class="item item-<?js= item.type ?>" data-longname="<?js= item.longname ?>" data-name="<?js= item.prettyname.toLowerCase() ?>">
|
||||||
<span class="title">
|
<span class="title toggle">
|
||||||
<span class="glyphicon <?js= getItemCssClass(item.type) ?> toggle"></span>
|
<span class="glyphicon <?js= getItemCssClass(item.type) ?>"></span>
|
||||||
<?js= self.linkto(item.longname, item.prettyname) ?>
|
<span><?js= self.linkto(item.longname, item.prettyname.replace(/[.~]/g, '\u200b$&')) ?></span>
|
||||||
</span><?js
|
</span><?js
|
||||||
listContent(item, 'Members', printList);
|
listContent(item, 'Members', printList);
|
||||||
listContent(item, 'Typedefs', printListWithStability);
|
listContent(item, 'Typedefs', printListWithStability);
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ function updateView() {
|
|||||||
view.setCenter(getCenterWithHeading(c, -c[2], view.getResolution()));
|
view.setCenter(getCenterWithHeading(c, -c[2], view.getResolution()));
|
||||||
view.setRotation(-c[2]);
|
view.setRotation(-c[2]);
|
||||||
marker.setPosition(c);
|
marker.setPosition(c);
|
||||||
|
map.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ const map = new Map({
|
|||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
center: [0, 1000000],
|
center: [0, 1000000],
|
||||||
zoom: 2
|
zoom: 2,
|
||||||
|
multiWorld: true
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ docs: >
|
|||||||
This example shows client-side raster reprojection capabilities from
|
This example shows client-side raster reprojection capabilities from
|
||||||
OSM (EPSG:3857) to arbitrary projection by searching
|
OSM (EPSG:3857) to arbitrary projection by searching
|
||||||
in <a href="https://epsg.io/">EPSG.io</a> database.
|
in <a href="https://epsg.io/">EPSG.io</a> database.
|
||||||
tags: "reprojection, projection, proj4js, epsg.io"
|
tags: "reprojection, projection, proj4js, epsg.io, graticule"
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
<form class="form-inline">
|
<form class="form-inline">
|
||||||
<label for="epsg-query">Search projection:</label>
|
<label for="epsg-query">Search projection:</label>
|
||||||
<input type="text" id="epsg-query" placeholder="4326, 27700, US National Atlas, Swiss, France, ..." class="form-control" size="50" />
|
<input type="text" id="epsg-query" placeholder="4326, 27700, 3031, US National Atlas, Swiss, France, ..." class="form-control" size="50" />
|
||||||
<button id="epsg-search" class="btn">Search</button>
|
<button id="epsg-search" class="btn">Search</button>
|
||||||
<span id="epsg-result"></span>
|
<span id="epsg-result"></span>
|
||||||
<div>
|
<div>
|
||||||
@@ -19,5 +19,9 @@ tags: "reprojection, projection, proj4js, epsg.io"
|
|||||||
Render reprojection edges
|
Render reprojection edges
|
||||||
<input type="checkbox" id="render-edges">
|
<input type="checkbox" id="render-edges">
|
||||||
</label>
|
</label>
|
||||||
|
<label for="show-graticule">
|
||||||
|
Show graticule
|
||||||
|
<input type="checkbox" id="show-graticule" />
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,19 +1,34 @@
|
|||||||
import Map from '../src/ol/Map.js';
|
import Map from '../src/ol/Map.js';
|
||||||
import View from '../src/ol/View.js';
|
import View from '../src/ol/View.js';
|
||||||
import {applyTransform} from '../src/ol/extent.js';
|
import {applyTransform} from '../src/ol/extent.js';
|
||||||
|
import Graticule from '../src/ol/layer/Graticule.js';
|
||||||
import TileLayer from '../src/ol/layer/Tile.js';
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
import {get as getProjection, getTransform} from '../src/ol/proj.js';
|
import {get as getProjection, getTransform} from '../src/ol/proj.js';
|
||||||
import {register} from '../src/ol/proj/proj4.js';
|
import {register} from '../src/ol/proj/proj4.js';
|
||||||
import OSM from '../src/ol/source/OSM.js';
|
import OSM from '../src/ol/source/OSM.js';
|
||||||
import TileImage from '../src/ol/source/TileImage.js';
|
import TileImage from '../src/ol/source/TileImage.js';
|
||||||
|
import Stroke from '../src/ol/style/Stroke.js';
|
||||||
import proj4 from 'proj4';
|
import proj4 from 'proj4';
|
||||||
|
|
||||||
|
|
||||||
|
const graticule = new Graticule({
|
||||||
|
// the style to use for the lines, optional.
|
||||||
|
strokeStyle: new Stroke({
|
||||||
|
color: 'rgba(255,120,0,0.9)',
|
||||||
|
width: 2,
|
||||||
|
lineDash: [0.5, 4]
|
||||||
|
}),
|
||||||
|
showLabels: true,
|
||||||
|
visible: false,
|
||||||
|
wrapX: false
|
||||||
|
});
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
source: new OSM()
|
source: new OSM()
|
||||||
})
|
}),
|
||||||
|
graticule
|
||||||
],
|
],
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
@@ -28,6 +43,7 @@ const queryInput = document.getElementById('epsg-query');
|
|||||||
const searchButton = document.getElementById('epsg-search');
|
const searchButton = document.getElementById('epsg-search');
|
||||||
const resultSpan = document.getElementById('epsg-result');
|
const resultSpan = document.getElementById('epsg-result');
|
||||||
const renderEdgesCheckbox = document.getElementById('render-edges');
|
const renderEdgesCheckbox = document.getElementById('render-edges');
|
||||||
|
const showGraticuleCheckbox = document.getElementById('show-graticule');
|
||||||
|
|
||||||
function setProjection(code, name, proj4def, bbox) {
|
function setProjection(code, name, proj4def, bbox) {
|
||||||
if (code === null || name === null || proj4def === null || bbox === null) {
|
if (code === null || name === null || proj4def === null || bbox === null) {
|
||||||
@@ -48,9 +64,15 @@ function setProjection(code, name, proj4def, bbox) {
|
|||||||
const newProj = getProjection(newProjCode);
|
const newProj = getProjection(newProjCode);
|
||||||
const fromLonLat = getTransform('EPSG:4326', newProj);
|
const fromLonLat = getTransform('EPSG:4326', newProj);
|
||||||
|
|
||||||
// very approximate calculation of projection extent
|
let worldExtent = [bbox[1], bbox[2], bbox[3], bbox[0]];
|
||||||
const extent = applyTransform(
|
newProj.setWorldExtent(worldExtent);
|
||||||
[bbox[1], bbox[2], bbox[3], bbox[0]], fromLonLat);
|
|
||||||
|
// approximate calculation of projection extent,
|
||||||
|
// checking if the world extent crosses the dateline
|
||||||
|
if (bbox[1] > bbox[3]) {
|
||||||
|
worldExtent = [bbox[1], bbox[2], bbox[3] + 360, bbox[0]];
|
||||||
|
}
|
||||||
|
const extent = applyTransform(worldExtent, fromLonLat, undefined, 8);
|
||||||
newProj.setExtent(extent);
|
newProj.setExtent(extent);
|
||||||
const newView = new View({
|
const newView = new View({
|
||||||
projection: newProj
|
projection: newProj
|
||||||
@@ -98,7 +120,7 @@ searchButton.onclick = function(event) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle change event.
|
* Handle checkbox change event.
|
||||||
*/
|
*/
|
||||||
renderEdgesCheckbox.onchange = function() {
|
renderEdgesCheckbox.onchange = function() {
|
||||||
map.getLayers().forEach(function(layer) {
|
map.getLayers().forEach(function(layer) {
|
||||||
@@ -110,3 +132,10 @@ renderEdgesCheckbox.onchange = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle checkbox change event.
|
||||||
|
*/
|
||||||
|
showGraticuleCheckbox.onchange = function() {
|
||||||
|
graticule.setVisible(showGraticuleCheckbox.checked);
|
||||||
|
};
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ register(proj4);
|
|||||||
// and a world extent. These are required for the Graticule.
|
// and a world extent. These are required for the Graticule.
|
||||||
const sphereMollweideProjection = new Projection({
|
const sphereMollweideProjection = new Projection({
|
||||||
code: 'ESRI:53009',
|
code: 'ESRI:53009',
|
||||||
extent: [-9009954.605703328, -9009954.605703328,
|
extent: [-18019909.21177587, -9009954.605703328,
|
||||||
9009954.605703328, 9009954.605703328],
|
18019909.21177587, 9009954.605703328],
|
||||||
worldExtent: [-179, -89.99, 179, 89.99]
|
worldExtent: [-179, -89.99, 179, 89.99]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,6 +37,6 @@ const map = new Map({
|
|||||||
view: new View({
|
view: new View({
|
||||||
center: [0, 0],
|
center: [0, 0],
|
||||||
projection: sphereMollweideProjection,
|
projection: sphereMollweideProjection,
|
||||||
zoom: 0
|
zoom: 1
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ docs: >
|
|||||||
This example generates a `GetFeature` request which uses a `PropertyIsEqualTo`
|
This example generates a `GetFeature` request which uses a `PropertyIsEqualTo`
|
||||||
and a `PropertyIsLike` filter, and then posts the request to load the features
|
and a `PropertyIsLike` filter, and then posts the request to load the features
|
||||||
that match the query.
|
that match the query.
|
||||||
tags: "vector, WFS, GetFeature, filter"
|
tags: "vector, WFS, GetFeature, filter, maptiler"
|
||||||
cloak:
|
cloak:
|
||||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '../src/ol/format/filter.js';
|
} from '../src/ol/format/filter.js';
|
||||||
import {WFS, GeoJSON} from '../src/ol/format.js';
|
import {WFS, GeoJSON} from '../src/ol/format.js';
|
||||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
import XYZ from '../src/ol/source/XYZ.js';
|
||||||
import VectorSource from '../src/ol/source/Vector.js';
|
import VectorSource from '../src/ol/source/Vector.js';
|
||||||
import {Stroke, Style} from '../src/ol/style.js';
|
import {Stroke, Style} from '../src/ol/style.js';
|
||||||
|
|
||||||
@@ -23,10 +23,15 @@ const vector = new VectorLayer({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||||
|
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||||
|
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||||
|
|
||||||
const raster = new TileLayer({
|
const raster = new TileLayer({
|
||||||
source: new BingMaps({
|
source: new XYZ({
|
||||||
imagerySet: 'Aerial',
|
attributions: attributions,
|
||||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||||
|
maxZoom: 20
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ title: WFS
|
|||||||
shortdesc: Example of using WFS with a BBOX strategy.
|
shortdesc: Example of using WFS with a BBOX strategy.
|
||||||
docs: >
|
docs: >
|
||||||
This example loads new features from GeoServer WFS when the view extent changes.
|
This example loads new features from GeoServer WFS when the view extent changes.
|
||||||
tags: "vector, WFS, bbox, loading, server"
|
tags: "vector, WFS, bbox, loading, server, maptiler"
|
||||||
cloak:
|
cloak:
|
||||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
|
|||||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
import {bbox as bboxStrategy} from '../src/ol/loadingstrategy.js';
|
import {bbox as bboxStrategy} from '../src/ol/loadingstrategy.js';
|
||||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
import XYZ from '../src/ol/source/XYZ.js';
|
||||||
import VectorSource from '../src/ol/source/Vector.js';
|
import VectorSource from '../src/ol/source/Vector.js';
|
||||||
import {Stroke, Style} from '../src/ol/style.js';
|
import {Stroke, Style} from '../src/ol/style.js';
|
||||||
|
|
||||||
@@ -30,10 +30,15 @@ const vector = new VectorLayer({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||||
|
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||||
|
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||||
|
|
||||||
const raster = new TileLayer({
|
const raster = new TileLayer({
|
||||||
source: new BingMaps({
|
source: new XYZ({
|
||||||
imagerySet: 'Aerial',
|
attributions: attributions,
|
||||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||||
|
maxZoom: 20
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Generated
+243
-1088
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -78,7 +78,7 @@
|
|||||||
"karma-webpack": "^4.0.0-rc.2",
|
"karma-webpack": "^4.0.0-rc.2",
|
||||||
"loglevelnext": "^3.0.1",
|
"loglevelnext": "^3.0.1",
|
||||||
"marked": "0.8.0",
|
"marked": "0.8.0",
|
||||||
"mocha": "7.0.1",
|
"mocha": "7.1.0",
|
||||||
"ol-mapbox-style": "^6.0.0",
|
"ol-mapbox-style": "^6.0.0",
|
||||||
"pixelmatch": "^5.1.0",
|
"pixelmatch": "^5.1.0",
|
||||||
"pngjs": "^3.4.0",
|
"pngjs": "^3.4.0",
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
"typescript": "3.5.3",
|
"typescript": "3.5.3",
|
||||||
"url-polyfill": "^1.1.5",
|
"url-polyfill": "^1.1.5",
|
||||||
"walk": "^2.3.9",
|
"walk": "^2.3.9",
|
||||||
"webpack": "4.41.6",
|
"webpack": "4.42.0",
|
||||||
"webpack-cli": "^3.3.2",
|
"webpack-cli": "^3.3.2",
|
||||||
"webpack-dev-middleware": "^3.6.2",
|
"webpack-dev-middleware": "^3.6.2",
|
||||||
"webpack-dev-server": "^3.3.1",
|
"webpack-dev-server": "^3.3.1",
|
||||||
|
|||||||
@@ -275,7 +275,9 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleTouchMove_(event) {
|
handleTouchMove_(event) {
|
||||||
if (this.originalPointerMoveEvent_.defaultPrevented) {
|
// Due to https://github.com/mpizenberg/elm-pep/issues/2, `this.originalPointerMoveEvent_`
|
||||||
|
// may not be initialized yet when we get here on a platform without native pointer events.
|
||||||
|
if (!this.originalPointerMoveEvent_ || this.originalPointerMoveEvent_.defaultPrevented) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Observable extends EventTarget {
|
|||||||
/**
|
/**
|
||||||
* Listen for a certain type of event.
|
* Listen for a certain type of event.
|
||||||
* @param {string|Array<string>} type The event type or array of event types.
|
* @param {string|Array<string>} type The event type or array of event types.
|
||||||
* @param {function(?): ?} listener The listener function.
|
* @param {import("./events.js").ListenerFunction} listener The listener function.
|
||||||
* @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If
|
* @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If
|
||||||
* called with an array of event types as the first argument, the return
|
* called with an array of event types as the first argument, the return
|
||||||
* will be an array of keys.
|
* will be an array of keys.
|
||||||
|
|||||||
+10
-5
@@ -405,7 +405,6 @@ class View extends BaseObject {
|
|||||||
} else if (options.zoom !== undefined) {
|
} else if (options.zoom !== undefined) {
|
||||||
this.setZoom(options.zoom);
|
this.setZoom(options.zoom);
|
||||||
}
|
}
|
||||||
this.resolveConstraints(0);
|
|
||||||
|
|
||||||
this.setProperties(properties);
|
this.setProperties(properties);
|
||||||
|
|
||||||
@@ -609,10 +608,15 @@ class View extends BaseObject {
|
|||||||
if (series[0].callback) {
|
if (series[0].callback) {
|
||||||
animationCallback(series[0].callback, false);
|
animationCallback(series[0].callback, false);
|
||||||
}
|
}
|
||||||
anchor = anchor ||
|
if (!anchor) {
|
||||||
series.filter(function(animation) {
|
for (let j = 0, jj = series.length; j < jj; ++j) {
|
||||||
return !animation.complete;
|
const animation = series[j];
|
||||||
})[0].anchor;
|
if (!animation.complete) {
|
||||||
|
anchor = animation.anchor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.animations_.length = 0;
|
this.animations_.length = 0;
|
||||||
this.cancelAnchor_ = anchor;
|
this.cancelAnchor_ = anchor;
|
||||||
@@ -762,6 +766,7 @@ class View extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
setViewportSize(opt_size) {
|
setViewportSize(opt_size) {
|
||||||
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
|
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
|
||||||
|
this.resolveConstraints(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+8
-1
@@ -13,7 +13,6 @@ import {clear} from './obj.js';
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener function. This function is called with an event object as argument.
|
* Listener function. This function is called with an event object as argument.
|
||||||
* When the function returns `false`, event propagation will stop.
|
* When the function returns `false`, event propagation will stop.
|
||||||
@@ -22,6 +21,14 @@ import {clear} from './obj.js';
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ListenerObject
|
||||||
|
* @property {ListenerFunction} handleEvent
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {ListenerFunction|ListenerObject} Listener
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers an event listener on an event target. Inspired by
|
* Registers an event listener on an event target. Inspired by
|
||||||
|
|||||||
+12
-9
@@ -56,7 +56,7 @@ class Target extends Disposable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {!Object<string, Array<import("../events.js").ListenerFunction>>}
|
* @type {!Object<string, Array<import("../events.js").Listener>>}
|
||||||
*/
|
*/
|
||||||
this.listeners_ = {};
|
this.listeners_ = {};
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class Target extends Disposable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} type Type.
|
* @param {string} type Type.
|
||||||
* @param {import("../events.js").ListenerFunction} listener Listener.
|
* @param {import("../events.js").Listener} listener Listener.
|
||||||
*/
|
*/
|
||||||
addEventListener(type, listener) {
|
addEventListener(type, listener) {
|
||||||
if (!type || !listener) {
|
if (!type || !listener) {
|
||||||
@@ -85,15 +85,13 @@ class Target extends Disposable {
|
|||||||
* of this type. The event parameter can either be a string or an
|
* of this type. The event parameter can either be a string or an
|
||||||
* Object with a `type` property.
|
* Object with a `type` property.
|
||||||
*
|
*
|
||||||
* @param {{type: string,
|
* @param {import("./Event.js").default|string} event Event object.
|
||||||
* target: (EventTargetLike|undefined),
|
|
||||||
* propagationStopped: (boolean|undefined)}|
|
|
||||||
* import("./Event.js").default|string} event Event object.
|
|
||||||
* @return {boolean|undefined} `false` if anyone called preventDefault on the
|
* @return {boolean|undefined} `false` if anyone called preventDefault on the
|
||||||
* event object or if any of the listeners returned false.
|
* event object or if any of the listeners returned false.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
dispatchEvent(event) {
|
dispatchEvent(event) {
|
||||||
|
/** @type {import("./Event.js").default|Event} */
|
||||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||||
const type = evt.type;
|
const type = evt.type;
|
||||||
if (!evt.target) {
|
if (!evt.target) {
|
||||||
@@ -108,7 +106,12 @@ class Target extends Disposable {
|
|||||||
}
|
}
|
||||||
++this.dispatching_[type];
|
++this.dispatching_[type];
|
||||||
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
||||||
if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
|
if ('handleEvent' in listeners[i]) {
|
||||||
|
propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[i]).handleEvent(evt);
|
||||||
|
} else {
|
||||||
|
propagate = /** @type {import("../events.js").ListenerFunction} */ (listeners[i]).call(this, evt);
|
||||||
|
}
|
||||||
|
if (propagate === false || evt.propagationStopped) {
|
||||||
propagate = false;
|
propagate = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -138,7 +141,7 @@ class Target extends Disposable {
|
|||||||
* order that they will be called in.
|
* order that they will be called in.
|
||||||
*
|
*
|
||||||
* @param {string} type Type.
|
* @param {string} type Type.
|
||||||
* @return {Array<import("../events.js").ListenerFunction>} Listeners.
|
* @return {Array<import("../events.js").Listener>} Listeners.
|
||||||
*/
|
*/
|
||||||
getListeners(type) {
|
getListeners(type) {
|
||||||
return this.listeners_[type];
|
return this.listeners_[type];
|
||||||
@@ -157,7 +160,7 @@ class Target extends Disposable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} type Type.
|
* @param {string} type Type.
|
||||||
* @param {import("../events.js").ListenerFunction} listener Listener.
|
* @param {import("../events.js").Listener} listener Listener.
|
||||||
*/
|
*/
|
||||||
removeEventListener(type, listener) {
|
removeEventListener(type, listener) {
|
||||||
const listeners = this.listeners_[type];
|
const listeners = this.listeners_[type];
|
||||||
|
|||||||
+29
-9
@@ -778,18 +778,38 @@ export function intersectsSegment(extent, start, end) {
|
|||||||
* @param {import("./proj.js").TransformFunction} transformFn Transform function.
|
* @param {import("./proj.js").TransformFunction} transformFn Transform function.
|
||||||
* Called with `[minX, minY, maxX, maxY]` extent coordinates.
|
* Called with `[minX, minY, maxX, maxY]` extent coordinates.
|
||||||
* @param {Extent=} opt_extent Destination extent.
|
* @param {Extent=} opt_extent Destination extent.
|
||||||
|
* @param {number=} opt_stops Number of stops per side used for the transform.
|
||||||
|
* By default only the corners are used.
|
||||||
* @return {Extent} Extent.
|
* @return {Extent} Extent.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
export function applyTransform(extent, transformFn, opt_extent) {
|
export function applyTransform(extent, transformFn, opt_extent, opt_stops) {
|
||||||
const coordinates = [
|
let coordinates = [];
|
||||||
extent[0], extent[1],
|
if (opt_stops > 1) {
|
||||||
extent[0], extent[3],
|
const width = extent[2] - extent[0];
|
||||||
extent[2], extent[1],
|
const height = extent[3] - extent[1];
|
||||||
extent[2], extent[3]
|
for (let i = 0; i < opt_stops; ++i) {
|
||||||
];
|
coordinates.push(
|
||||||
|
extent[0] + width * i / opt_stops, extent[1],
|
||||||
|
extent[2], extent[1] + height * i / opt_stops,
|
||||||
|
extent[2] - width * i / opt_stops, extent[3],
|
||||||
|
extent[0], extent[3] - height * i / opt_stops
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
coordinates = [
|
||||||
|
extent[0], extent[1],
|
||||||
|
extent[2], extent[1],
|
||||||
|
extent[2], extent[3],
|
||||||
|
extent[0], extent[3]
|
||||||
|
];
|
||||||
|
}
|
||||||
transformFn(coordinates, coordinates, 2);
|
transformFn(coordinates, coordinates, 2);
|
||||||
const xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
|
const xs = [];
|
||||||
const ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
|
const ys = [];
|
||||||
|
for (let i = 0, l = coordinates.length; i < l; i += 2) {
|
||||||
|
xs.push(coordinates[i]);
|
||||||
|
ys.push(coordinates[i + 1]);
|
||||||
|
}
|
||||||
return _boundingExtentXYs(xs, ys, opt_extent);
|
return _boundingExtentXYs(xs, ys, opt_extent);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ import {fromUserCoordinate, getUserProjection} from '../proj.js';
|
|||||||
* geometry is the geometry that is returned when the function is called without
|
* geometry is the geometry that is returned when the function is called without
|
||||||
* a second argument.
|
* a second argument.
|
||||||
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=,
|
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=,
|
||||||
* import("../proj/Projection.js").default):
|
* import("../proj/Projection.js").default=):
|
||||||
* import("../geom/SimpleGeometry.js").default} GeometryFunction
|
* import("../geom/SimpleGeometry.js").default} GeometryFunction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
+152
-30
@@ -12,10 +12,19 @@ import VectorSource from '../source/Vector.js';
|
|||||||
import {
|
import {
|
||||||
equivalent as equivalentProjection,
|
equivalent as equivalentProjection,
|
||||||
get as getProjection,
|
get as getProjection,
|
||||||
getTransform,
|
getTransform
|
||||||
transformExtent
|
|
||||||
} from '../proj.js';
|
} from '../proj.js';
|
||||||
import {getCenter, getHeight, getWidth, intersects, equals, getIntersection, isEmpty} from '../extent.js';
|
import {
|
||||||
|
applyTransform,
|
||||||
|
containsCoordinate,
|
||||||
|
equals,
|
||||||
|
getCenter,
|
||||||
|
getHeight,
|
||||||
|
getIntersection,
|
||||||
|
getWidth,
|
||||||
|
intersects,
|
||||||
|
isEmpty
|
||||||
|
} from '../extent.js';
|
||||||
import {clamp} from '../math.js';
|
import {clamp} from '../math.js';
|
||||||
import Style from '../style/Style.js';
|
import Style from '../style/Style.js';
|
||||||
import Feature from '../Feature.js';
|
import Feature from '../Feature.js';
|
||||||
@@ -144,7 +153,8 @@ const INTERVALS = [
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
* Layer that renders a grid for a coordinate system.
|
* Layer that renders a grid for a coordinate system (currently only EPSG:4326 is supported).
|
||||||
|
* Note that the view projection must define both extent and worldExtent.
|
||||||
*
|
*
|
||||||
* @fires import("../render/Event.js").RenderEvent
|
* @fires import("../render/Event.js").RenderEvent
|
||||||
* @api
|
* @api
|
||||||
@@ -208,25 +218,25 @@ class Graticule extends VectorLayer {
|
|||||||
* @type {number}
|
* @type {number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.maxLatP_ = Infinity;
|
this.maxX_ = Infinity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.maxLonP_ = Infinity;
|
this.maxY_ = Infinity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.minLatP_ = -Infinity;
|
this.minX_ = -Infinity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.minLonP_ = -Infinity;
|
this.minY_ = -Infinity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@@ -276,6 +286,30 @@ class Graticule extends VectorLayer {
|
|||||||
*/
|
*/
|
||||||
this.projectionCenterLonLat_ = null;
|
this.projectionCenterLonLat_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.bottomLeft_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.bottomRight_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.topLeft_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.topRight_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array<GraticuleLabelDataType>}
|
* @type {Array<GraticuleLabelDataType>}
|
||||||
* @private
|
* @private
|
||||||
@@ -664,24 +698,67 @@ class Graticule extends VectorLayer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const centerLonLat = this.toLonLatTransform_(center);
|
// Constrain the center to fit into the extent available to the graticule
|
||||||
let centerLon = centerLonLat[0];
|
|
||||||
let centerLat = centerLonLat[1];
|
const validCenterP = [
|
||||||
|
clamp(center[0], this.minX_, this.maxX_),
|
||||||
|
clamp(center[1], this.minY_, this.maxY_)
|
||||||
|
];
|
||||||
|
|
||||||
|
// Transform the center to lon lat
|
||||||
|
// Some projections may have a void area at the poles
|
||||||
|
// so replace any NaN latitudes with the min or max value closest to a pole
|
||||||
|
|
||||||
|
const centerLonLat = this.toLonLatTransform_(validCenterP);
|
||||||
|
if (isNaN(centerLonLat[1])) {
|
||||||
|
centerLonLat[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
|
||||||
|
this.maxLat_ : this.minLat_;
|
||||||
|
}
|
||||||
|
let centerLon = clamp(centerLonLat[0], this.minLon_, this.maxLon_);
|
||||||
|
let centerLat = clamp(centerLonLat[1], this.minLat_, this.maxLat_);
|
||||||
const maxLines = this.maxLines_;
|
const maxLines = this.maxLines_;
|
||||||
let cnt, idx, lat, lon;
|
let cnt, idx, lat, lon;
|
||||||
|
|
||||||
let validExtent = [
|
// Limit the extent to fit into the extent available to the graticule
|
||||||
Math.max(extent[0], this.minLonP_),
|
|
||||||
Math.max(extent[1], this.minLatP_),
|
const validExtentP = [
|
||||||
Math.min(extent[2], this.maxLonP_),
|
clamp(extent[0], this.minX_, this.maxX_),
|
||||||
Math.min(extent[3], this.maxLatP_)
|
clamp(extent[1], this.minY_, this.maxY_),
|
||||||
|
clamp(extent[2], this.minX_, this.maxX_),
|
||||||
|
clamp(extent[3], this.minY_, this.maxY_)
|
||||||
];
|
];
|
||||||
|
|
||||||
validExtent = transformExtent(validExtent, this.projection_, 'EPSG:4326');
|
// Transform the extent to get the lon lat ranges for the edges of the extent
|
||||||
const maxLat = validExtent[3];
|
|
||||||
const maxLon = validExtent[2];
|
const validExtent = applyTransform(validExtentP, this.toLonLatTransform_, undefined, 8);
|
||||||
const minLat = validExtent[1];
|
|
||||||
const minLon = validExtent[0];
|
// Check if extremities of the world extent lie inside the extent
|
||||||
|
// (for example the pole in a polar projection)
|
||||||
|
// and extend the extent as appropriate
|
||||||
|
|
||||||
|
if (containsCoordinate(validExtentP, this.bottomLeft_)) {
|
||||||
|
validExtent[0] = this.minLon_;
|
||||||
|
validExtent[1] = this.minLat_;
|
||||||
|
}
|
||||||
|
if (containsCoordinate(validExtentP, this.bottomRight_)) {
|
||||||
|
validExtent[2] = this.maxLon_;
|
||||||
|
validExtent[1] = this.minLat_;
|
||||||
|
}
|
||||||
|
if (containsCoordinate(validExtentP, this.topLeft_)) {
|
||||||
|
validExtent[0] = this.minLon_;
|
||||||
|
validExtent[3] = this.maxLat_;
|
||||||
|
}
|
||||||
|
if (containsCoordinate(validExtentP, this.topRight_)) {
|
||||||
|
validExtent[2] = this.maxLon_;
|
||||||
|
validExtent[3] = this.maxLat_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The transformed center may also extend the lon lat ranges used for rendering
|
||||||
|
|
||||||
|
const maxLat = clamp(validExtent[3], centerLat, this.maxLat_);
|
||||||
|
const maxLon = clamp(validExtent[2], centerLon, this.maxLon_);
|
||||||
|
const minLat = clamp(validExtent[1], this.minLat_, centerLat);
|
||||||
|
const minLon = clamp(validExtent[0], this.minLon_, centerLon);
|
||||||
|
|
||||||
// Create meridians
|
// Create meridians
|
||||||
|
|
||||||
@@ -752,11 +829,13 @@ class Graticule extends VectorLayer {
|
|||||||
/** @type {Array<number>} **/
|
/** @type {Array<number>} **/
|
||||||
const p2 = [];
|
const p2 = [];
|
||||||
for (let i = 0, ii = this.intervals_.length; i < ii; ++i) {
|
for (let i = 0, ii = this.intervals_.length; i < ii; ++i) {
|
||||||
const delta = this.intervals_[i] / 2;
|
const delta = clamp(this.intervals_[i] / 2, 0, 90);
|
||||||
|
// Don't attempt to transform latitudes beyond the poles!
|
||||||
|
const clampedLat = clamp(centerLat, -90 + delta, 90 - delta);
|
||||||
p1[0] = centerLon - delta;
|
p1[0] = centerLon - delta;
|
||||||
p1[1] = centerLat - delta;
|
p1[1] = clampedLat - delta;
|
||||||
p2[0] = centerLon + delta;
|
p2[0] = centerLon + delta;
|
||||||
p2[1] = centerLat + delta;
|
p2[1] = clampedLat + delta;
|
||||||
this.fromLonLatTransform_(p1, p1);
|
this.fromLonLatTransform_(p1, p1);
|
||||||
this.fromLonLatTransform_(p2, p2);
|
this.fromLonLatTransform_(p2, p2);
|
||||||
const dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
|
const dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
|
||||||
@@ -896,23 +975,66 @@ class Graticule extends VectorLayer {
|
|||||||
const epsg4326Projection = getProjection('EPSG:4326');
|
const epsg4326Projection = getProjection('EPSG:4326');
|
||||||
|
|
||||||
const worldExtent = projection.getWorldExtent();
|
const worldExtent = projection.getWorldExtent();
|
||||||
const worldExtentP = transformExtent(worldExtent, epsg4326Projection, projection);
|
|
||||||
|
|
||||||
this.maxLat_ = worldExtent[3];
|
this.maxLat_ = worldExtent[3];
|
||||||
this.maxLon_ = worldExtent[2];
|
this.maxLon_ = worldExtent[2];
|
||||||
this.minLat_ = worldExtent[1];
|
this.minLat_ = worldExtent[1];
|
||||||
this.minLon_ = worldExtent[0];
|
this.minLon_ = worldExtent[0];
|
||||||
|
|
||||||
this.maxLatP_ = worldExtentP[3];
|
// If the world extent crosses the dateline define a custom transform to
|
||||||
this.maxLonP_ = worldExtentP[2];
|
// return longitudes which wrap the dateline
|
||||||
this.minLatP_ = worldExtentP[1];
|
|
||||||
this.minLonP_ = worldExtentP[0];
|
const toLonLatTransform = getTransform(projection, epsg4326Projection);
|
||||||
|
if (this.minLon_ < this.maxLon_) {
|
||||||
|
this.toLonLatTransform_ = toLonLatTransform;
|
||||||
|
} else {
|
||||||
|
const split = this.minLon_ + this.maxLon_ / 2;
|
||||||
|
this.maxLon_ += 360;
|
||||||
|
this.toLonLatTransform_ = function(coordinates, opt_output, opt_dimension) {
|
||||||
|
const dimension = opt_dimension || 2;
|
||||||
|
const lonLatCoordinates = toLonLatTransform(coordinates, opt_output, dimension);
|
||||||
|
for (let i = 0, l = lonLatCoordinates.length; i < l; i += dimension) {
|
||||||
|
if (lonLatCoordinates[i] < split) {
|
||||||
|
lonLatCoordinates[i] += 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lonLatCoordinates;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the extent to get the limits of the view projection extent
|
||||||
|
// which should be available to the graticule
|
||||||
|
|
||||||
this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection);
|
this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection);
|
||||||
|
const worldExtentP = applyTransform(
|
||||||
|
[this.minLon_, this.minLat_, this.maxLon_, this.maxLat_],
|
||||||
|
this.fromLonLatTransform_,
|
||||||
|
undefined,
|
||||||
|
8
|
||||||
|
);
|
||||||
|
|
||||||
this.toLonLatTransform_ = getTransform(projection, epsg4326Projection);
|
this.minX_ = worldExtentP[0];
|
||||||
|
this.maxX_ = worldExtentP[2];
|
||||||
|
this.minY_ = worldExtentP[1];
|
||||||
|
this.maxY_ = worldExtentP[3];
|
||||||
|
|
||||||
|
// Determine the view projection coordinates of the extremities of the world extent
|
||||||
|
// as these may lie inside a view extent (for example the pole in a polar projection)
|
||||||
|
|
||||||
|
this.bottomLeft_ = this.fromLonLatTransform_([this.minLon_, this.minLat_]);
|
||||||
|
this.bottomRight_ = this.fromLonLatTransform_([this.maxLon_, this.minLat_]);
|
||||||
|
this.topLeft_ = this.fromLonLatTransform_([this.minLon_, this.maxLat_]);
|
||||||
|
this.topRight_ = this.fromLonLatTransform_([this.maxLon_, this.maxLat_]);
|
||||||
|
|
||||||
|
// Transform the projection center to lon lat
|
||||||
|
// Some projections may have a void area at the poles
|
||||||
|
// so replace any NaN latitudes with the min or max value closest to a pole
|
||||||
|
|
||||||
this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent()));
|
this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent()));
|
||||||
|
if (isNaN(this.projectionCenterLonLat_[1])) {
|
||||||
|
this.projectionCenterLonLat_[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
|
||||||
|
this.maxLat_ : this.minLat_;
|
||||||
|
}
|
||||||
|
|
||||||
this.projection_ = projection;
|
this.projection_ = projection;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -476,12 +476,14 @@ export function transform(coordinate, source, destination) {
|
|||||||
* @param {import("./extent.js").Extent} extent The extent to transform.
|
* @param {import("./extent.js").Extent} extent The extent to transform.
|
||||||
* @param {ProjectionLike} source Source projection-like.
|
* @param {ProjectionLike} source Source projection-like.
|
||||||
* @param {ProjectionLike} destination Destination projection-like.
|
* @param {ProjectionLike} destination Destination projection-like.
|
||||||
|
* @param {number=} opt_stops Number of stops per side used for the transform.
|
||||||
|
* By default only the corners are used.
|
||||||
* @return {import("./extent.js").Extent} The transformed extent.
|
* @return {import("./extent.js").Extent} The transformed extent.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
export function transformExtent(extent, source, destination) {
|
export function transformExtent(extent, source, destination, opt_stops) {
|
||||||
const transformFunc = getTransform(source, destination);
|
const transformFunc = getTransform(source, destination);
|
||||||
return applyTransform(extent, transformFunc);
|
return applyTransform(extent, transformFunc, undefined, opt_stops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,8 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
|||||||
this.sourceListenKeys_ = [
|
this.sourceListenKeys_ = [
|
||||||
listen(source, VectorEventType.ADDFEATURE, this.handleSourceFeatureAdded_, this),
|
listen(source, VectorEventType.ADDFEATURE, this.handleSourceFeatureAdded_, this),
|
||||||
listen(source, VectorEventType.CHANGEFEATURE, this.handleSourceFeatureChanged_, this),
|
listen(source, VectorEventType.CHANGEFEATURE, this.handleSourceFeatureChanged_, this),
|
||||||
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this)
|
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this),
|
||||||
|
listen(source, VectorEventType.CLEAR, this.handleSourceFeatureClear_, this)
|
||||||
];
|
];
|
||||||
source.forEachFeature(function(feature) {
|
source.forEachFeature(function(feature) {
|
||||||
this.featureCache_[getUid(feature)] = {
|
this.featureCache_[getUid(feature)] = {
|
||||||
@@ -339,6 +340,14 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
|||||||
this.featureCount_--;
|
this.featureCount_--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
handleSourceFeatureClear_() {
|
||||||
|
this.featureCache_ = {};
|
||||||
|
this.featureCount_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import ImageSource from './Image.js';
|
|||||||
* the value returned by the function is later changed then
|
* the value returned by the function is later changed then
|
||||||
* `changed` should be called on the source for the source to
|
* `changed` should be called on the source for the source to
|
||||||
* invalidate the current cached image. See: {@link module:ol/Observable~Observable#changed}
|
* invalidate the current cached image. See: {@link module:ol/Observable~Observable#changed}
|
||||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||||
* @property {number} [ratio=1.5] Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
|
* @property {number} [ratio=1.5] Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
|
||||||
* width and height of the map viewport, and so on. Must be `1` or higher.
|
* width and height of the map viewport, and so on. Must be `1` or higher.
|
||||||
* @property {Array<number>} [resolutions] Resolutions.
|
* @property {Array<number>} [resolutions] Resolutions.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {appendParams} from '../uri.js';
|
|||||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||||
* the image from the remote server.
|
* the image from the remote server.
|
||||||
* @property {boolean} [useOverlay] If `true`, will use `GETDYNAMICMAPOVERLAYIMAGE`.
|
* @property {boolean} [useOverlay] If `true`, will use `GETDYNAMICMAPOVERLAYIMAGE`.
|
||||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||||
* @property {number} [ratio=1] Ratio. `1` means image requests are the size of the map viewport, `2` means
|
* @property {number} [ratio=1] Ratio. `1` means image requests are the size of the map viewport, `2` means
|
||||||
* twice the width and height of the map viewport, and so on. Must be `1` or higher.
|
* twice the width and height of the map viewport, and so on. Must be `1` or higher.
|
||||||
* @property {Array<number>} [resolutions] Resolutions.
|
* @property {Array<number>} [resolutions] Resolutions.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
|||||||
* @property {import("../extent.js").Extent} [imageExtent] Extent of the image in map coordinates.
|
* @property {import("../extent.js").Extent} [imageExtent] Extent of the image in map coordinates.
|
||||||
* This is the [left, bottom, right, top] map coordinates of your image.
|
* This is the [left, bottom, right, top] map coordinates of your image.
|
||||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
||||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||||
* @property {import("../size.js").Size} [imageSize] Size of the image in pixels. Usually the image size is auto-detected, so this
|
* @property {import("../size.js").Size} [imageSize] Size of the image in pixels. Usually the image size is auto-detected, so this
|
||||||
* only needs to be set if auto-detection fails for some reason.
|
* only needs to be set if auto-detection fails for some reason.
|
||||||
* @property {string} url Image URL.
|
* @property {string} url Image URL.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {createCanvasContext2D} from '../dom.js';
|
|||||||
import {toSize} from '../size.js';
|
import {toSize} from '../size.js';
|
||||||
import TileImage from './TileImage.js';
|
import TileImage from './TileImage.js';
|
||||||
import TileGrid from '../tilegrid/TileGrid.js';
|
import TileGrid from '../tilegrid/TileGrid.js';
|
||||||
|
import {getCenter} from '../extent.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,7 +91,7 @@ export class CustomTile extends ImageTile {
|
|||||||
* Higher values can increase reprojection performance, but decrease precision.
|
* Higher values can increase reprojection performance, but decrease precision.
|
||||||
* @property {object} [reprojectionContextOptions] Optional properties to set on the canvas context used
|
* @property {object} [reprojectionContextOptions] Optional properties to set on the canvas context used
|
||||||
* for reprojection. For example specify `{imageSmoothingEnabled: false}` to disable image smoothing.
|
* for reprojection. For example specify `{imageSmoothingEnabled: false}` to disable image smoothing.
|
||||||
* @property {string} [url] URL template or base URL of the Zoomify service.
|
* @property {string} url URL template or base URL of the Zoomify service.
|
||||||
* A base URL is the fixed part
|
* A base URL is the fixed part
|
||||||
* of the URL, excluding the tile group, z, x, and y folder structure, e.g.
|
* of the URL, excluding the tile group, z, x, and y folder structure, e.g.
|
||||||
* `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
|
* `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
|
||||||
@@ -102,7 +103,7 @@ export class CustomTile extends ImageTile {
|
|||||||
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
||||||
* used instead of defining each one separately in the `urls` option.
|
* used instead of defining each one separately in the `urls` option.
|
||||||
* @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
|
* @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
|
||||||
* @property {import("../size.js").Size} [size] Size of the image.
|
* @property {import("../size.js").Size} size
|
||||||
* @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
|
* @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
|
||||||
* Default sets the TileGrid in the
|
* Default sets the TileGrid in the
|
||||||
* fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
|
* fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
|
||||||
@@ -127,11 +128,11 @@ export class CustomTile extends ImageTile {
|
|||||||
class Zoomify extends TileImage {
|
class Zoomify extends TileImage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Options=} opt_options Options.
|
* @param {Options} opt_options Options.
|
||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
const options = opt_options || {};
|
const options = opt_options;
|
||||||
|
|
||||||
const size = options.size;
|
const size = options.size;
|
||||||
const tierSizeCalculation = options.tierSizeCalculation !== undefined ?
|
const tierSizeCalculation = options.tierSizeCalculation !== undefined ?
|
||||||
@@ -198,7 +199,7 @@ class Zoomify extends TileImage {
|
|||||||
}
|
}
|
||||||
const urls = expandUrl(url);
|
const urls = expandUrl(url);
|
||||||
|
|
||||||
const tileWidth = tileSize * tilePixelRatio;
|
let tileWidth = tileSize * tilePixelRatio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} template Template.
|
* @param {string} template Template.
|
||||||
@@ -262,6 +263,19 @@ class Zoomify extends TileImage {
|
|||||||
*/
|
*/
|
||||||
this.zDirection = options.zDirection;
|
this.zDirection = options.zDirection;
|
||||||
|
|
||||||
|
// Server retina tile detection (non-standard):
|
||||||
|
// Try loading the center tile for the highest resolution. If it is not
|
||||||
|
// available, we are dealing with retina tiles, and need to adjust the
|
||||||
|
// tile url calculation.
|
||||||
|
const tileUrl = tileGrid.getTileCoordForCoordAndResolution(getCenter(tileGrid.getExtent()), resolutions[resolutions.length - 1]);
|
||||||
|
const testTileUrl = tileUrlFunction(tileUrl, 1, null);
|
||||||
|
const image = new Image();
|
||||||
|
image.addEventListener('error', function() {
|
||||||
|
tileWidth = tileSize;
|
||||||
|
this.changed();
|
||||||
|
}.bind(this));
|
||||||
|
image.src = testTileUrl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ export function parseLiteralStyle(style) {
|
|||||||
const parsedSize = expressionToGlsl(vertContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER);
|
const parsedSize = expressionToGlsl(vertContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER);
|
||||||
const parsedOffset = expressionToGlsl(vertContext, offset, ValueTypes.NUMBER_ARRAY);
|
const parsedOffset = expressionToGlsl(vertContext, offset, ValueTypes.NUMBER_ARRAY);
|
||||||
const parsedTexCoord = expressionToGlsl(vertContext, texCoord, ValueTypes.NUMBER_ARRAY);
|
const parsedTexCoord = expressionToGlsl(vertContext, texCoord, ValueTypes.NUMBER_ARRAY);
|
||||||
|
const parsedRotation = expressionToGlsl(vertContext, rotation, ValueTypes.NUMBER);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import("../style/expressions.js").ParsingContext}
|
* @type {import("../style/expressions.js").ParsingContext}
|
||||||
@@ -439,7 +440,6 @@ export function parseLiteralStyle(style) {
|
|||||||
};
|
};
|
||||||
const parsedColor = expressionToGlsl(fragContext, color, ValueTypes.COLOR);
|
const parsedColor = expressionToGlsl(fragContext, color, ValueTypes.COLOR);
|
||||||
const parsedOpacity = expressionToGlsl(fragContext, opacity, ValueTypes.NUMBER);
|
const parsedOpacity = expressionToGlsl(fragContext, opacity, ValueTypes.NUMBER);
|
||||||
const parsedRotation = expressionToGlsl(fragContext, rotation, ValueTypes.NUMBER);
|
|
||||||
|
|
||||||
let opacityFilter = '1.0';
|
let opacityFilter = '1.0';
|
||||||
const visibleSize = `vec2(${expressionToGlsl(fragContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER)}).x`;
|
const visibleSize = `vec2(${expressionToGlsl(fragContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER)}).x`;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as _ol_extent_ from '../../../src/ol/extent.js';
|
import * as _ol_extent_ from '../../../src/ol/extent.js';
|
||||||
import {getTransform} from '../../../src/ol/proj.js';
|
import {getTransform} from '../../../src/ol/proj.js';
|
||||||
|
import {register} from '../../../src/ol/proj/proj4.js';
|
||||||
|
|
||||||
|
|
||||||
describe('ol.extent', function() {
|
describe('ol.extent', function() {
|
||||||
@@ -783,6 +784,38 @@ describe('ol.extent', function() {
|
|||||||
expect(destinationExtent[3]).to.be(30);
|
expect(destinationExtent[3]).to.be(30);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can use the stops option', function() {
|
||||||
|
proj4.defs('EPSG:32632', '+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs');
|
||||||
|
register(proj4);
|
||||||
|
const transformFn = getTransform('EPSG:4326', 'EPSG:32632');
|
||||||
|
const sourceExtentN = [6, 0, 12, 84];
|
||||||
|
const destinationExtentN = _ol_extent_.applyTransform(
|
||||||
|
sourceExtentN, transformFn);
|
||||||
|
expect(destinationExtentN).not.to.be(undefined);
|
||||||
|
expect(destinationExtentN).not.to.be(null);
|
||||||
|
expect(destinationExtentN[0]).to.roughlyEqual(166021.44308053964, 1e-8);
|
||||||
|
expect(destinationExtentN[2]).to.roughlyEqual(833978.5569194605, 1e-8);
|
||||||
|
expect(destinationExtentN[1]).to.roughlyEqual(0, 1e-8);
|
||||||
|
expect(destinationExtentN[3]).to.roughlyEqual(9329005.182447437, 1e-8);
|
||||||
|
const sourceExtentNS = [6, -84, 12, 84];
|
||||||
|
const destinationExtentNS = _ol_extent_.applyTransform(
|
||||||
|
sourceExtentNS, transformFn);
|
||||||
|
expect(destinationExtentNS).not.to.be(undefined);
|
||||||
|
expect(destinationExtentNS).not.to.be(null);
|
||||||
|
expect(destinationExtentNS[0]).to.roughlyEqual(465005.34493886377, 1e-8);
|
||||||
|
expect(destinationExtentNS[2]).to.roughlyEqual(534994.6550611362, 1e-8);
|
||||||
|
expect(destinationExtentNS[1]).to.roughlyEqual(-destinationExtentN[3], 1e-8);
|
||||||
|
expect(destinationExtentNS[3]).to.roughlyEqual(destinationExtentN[3], 1e-8);
|
||||||
|
const destinationExtentNS2 = _ol_extent_.applyTransform(
|
||||||
|
sourceExtentNS, transformFn, undefined, 2);
|
||||||
|
expect(destinationExtentNS2).not.to.be(undefined);
|
||||||
|
expect(destinationExtentNS2).not.to.be(null);
|
||||||
|
expect(destinationExtentNS2[0]).to.roughlyEqual(destinationExtentN[0], 1e-8);
|
||||||
|
expect(destinationExtentNS2[2]).to.roughlyEqual(destinationExtentN[2], 1e-8);
|
||||||
|
expect(destinationExtentNS2[1]).to.roughlyEqual(-destinationExtentN[3], 1e-8);
|
||||||
|
expect(destinationExtentNS2[3]).to.roughlyEqual(destinationExtentN[3], 1e-8);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
|
|
||||||
describe('constructor', function() {
|
describe('constructor', function() {
|
||||||
|
|
||||||
it('requires config "size"', function() {
|
it('requires config "size" and "url"', function() {
|
||||||
let source;
|
let source;
|
||||||
|
|
||||||
// undefined config object
|
// undefined config object
|
||||||
@@ -58,7 +58,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
source = new Zoomify({});
|
source = new Zoomify({});
|
||||||
}).to.throwException();
|
}).to.throwException();
|
||||||
|
|
||||||
// not passing "size" in config object
|
// passing "url" in config object
|
||||||
expect(function() {
|
expect(function() {
|
||||||
source = new Zoomify({
|
source = new Zoomify({
|
||||||
url: 'some-url'
|
url: 'some-url'
|
||||||
@@ -70,6 +70,14 @@ describe('ol.source.Zoomify', function() {
|
|||||||
source = new Zoomify({
|
source = new Zoomify({
|
||||||
size: [47, 11]
|
size: [47, 11]
|
||||||
});
|
});
|
||||||
|
}).to.throwException();
|
||||||
|
|
||||||
|
// passing "size" and "url" in config object
|
||||||
|
expect(function() {
|
||||||
|
source = new Zoomify({
|
||||||
|
url: '',
|
||||||
|
size: [47, 11]
|
||||||
|
});
|
||||||
}).to.not.throwException();
|
}).to.not.throwException();
|
||||||
// we got a source
|
// we got a source
|
||||||
expect(source).to.be.a(Zoomify);
|
expect(source).to.be.a(Zoomify);
|
||||||
@@ -88,6 +96,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
it('does not need "tierSizeCalculation" option', function() {
|
it('does not need "tierSizeCalculation" option', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
new Zoomify({
|
new Zoomify({
|
||||||
|
url: '',
|
||||||
size: [47, 11]
|
size: [47, 11]
|
||||||
});
|
});
|
||||||
}).to.not.throwException();
|
}).to.not.throwException();
|
||||||
@@ -96,6 +105,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
it('accepts "tierSizeCalculation" option "default"', function() {
|
it('accepts "tierSizeCalculation" option "default"', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
new Zoomify({
|
new Zoomify({
|
||||||
|
url: '',
|
||||||
size: [47, 11],
|
size: [47, 11],
|
||||||
tierSizeCalculation: 'default'
|
tierSizeCalculation: 'default'
|
||||||
});
|
});
|
||||||
@@ -105,6 +115,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
it('accepts "tierSizeCalculation" option "truncated"', function() {
|
it('accepts "tierSizeCalculation" option "truncated"', function() {
|
||||||
expect(function() {
|
expect(function() {
|
||||||
new Zoomify({
|
new Zoomify({
|
||||||
|
url: '',
|
||||||
size: [47, 11],
|
size: [47, 11],
|
||||||
tierSizeCalculation: 'truncated'
|
tierSizeCalculation: 'truncated'
|
||||||
});
|
});
|
||||||
@@ -115,6 +126,7 @@ describe('ol.source.Zoomify', function() {
|
|||||||
// passing unknown string will throw
|
// passing unknown string will throw
|
||||||
expect(function() {
|
expect(function() {
|
||||||
new Zoomify({
|
new Zoomify({
|
||||||
|
url: '',
|
||||||
size: [47, 11],
|
size: [47, 11],
|
||||||
tierSizeCalculation: 'ace-of-spades'
|
tierSizeCalculation: 'ace-of-spades'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ describe('ol.View', function() {
|
|||||||
maxResolution: 1000,
|
maxResolution: 1000,
|
||||||
resolution: 1200
|
resolution: 1200
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getResolution()).to.eql(1000);
|
expect(view.getResolution()).to.eql(1000);
|
||||||
expect(view.targetResolution_).to.eql(1000);
|
expect(view.targetResolution_).to.eql(1000);
|
||||||
});
|
});
|
||||||
@@ -45,6 +46,7 @@ describe('ol.View', function() {
|
|||||||
minResolution: 128,
|
minResolution: 128,
|
||||||
resolution: 50
|
resolution: 50
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getResolution()).to.eql(128);
|
expect(view.getResolution()).to.eql(128);
|
||||||
expect(view.targetResolution_).to.eql(128);
|
expect(view.targetResolution_).to.eql(128);
|
||||||
});
|
});
|
||||||
@@ -54,6 +56,7 @@ describe('ol.View', function() {
|
|||||||
resolutions: [1024, 512, 256, 128, 64, 32],
|
resolutions: [1024, 512, 256, 128, 64, 32],
|
||||||
resolution: 1200
|
resolution: 1200
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getResolution()).to.eql(1024);
|
expect(view.getResolution()).to.eql(1024);
|
||||||
expect(view.targetResolution_).to.eql(1024);
|
expect(view.targetResolution_).to.eql(1024);
|
||||||
|
|
||||||
@@ -61,6 +64,7 @@ describe('ol.View', function() {
|
|||||||
resolutions: [1024, 512, 256, 128, 64, 32],
|
resolutions: [1024, 512, 256, 128, 64, 32],
|
||||||
resolution: 10
|
resolution: 10
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getResolution()).to.eql(32);
|
expect(view.getResolution()).to.eql(32);
|
||||||
expect(view.targetResolution_).to.eql(32);
|
expect(view.targetResolution_).to.eql(32);
|
||||||
});
|
});
|
||||||
@@ -70,6 +74,7 @@ describe('ol.View', function() {
|
|||||||
minZoom: 3,
|
minZoom: 3,
|
||||||
zoom: 2
|
zoom: 2
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getZoom()).to.eql(3);
|
expect(view.getZoom()).to.eql(3);
|
||||||
expect(view.targetResolution_).to.eql(view.getMaxResolution());
|
expect(view.targetResolution_).to.eql(view.getMaxResolution());
|
||||||
});
|
});
|
||||||
@@ -79,6 +84,7 @@ describe('ol.View', function() {
|
|||||||
maxZoom: 4,
|
maxZoom: 4,
|
||||||
zoom: 5
|
zoom: 5
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getZoom()).to.eql(4);
|
expect(view.getZoom()).to.eql(4);
|
||||||
expect(view.targetResolution_).to.eql(view.getMaxResolution() / Math.pow(2, 4));
|
expect(view.targetResolution_).to.eql(view.getMaxResolution() / Math.pow(2, 4));
|
||||||
});
|
});
|
||||||
@@ -89,6 +95,7 @@ describe('ol.View', function() {
|
|||||||
extent: [0, 0, 50, 50],
|
extent: [0, 0, 50, 50],
|
||||||
resolution: 1
|
resolution: 1
|
||||||
});
|
});
|
||||||
|
view.setViewportSize();
|
||||||
expect(view.getResolution()).to.eql(0.5);
|
expect(view.getResolution()).to.eql(0.5);
|
||||||
expect(view.targetResolution_).to.eql(0.5);
|
expect(view.targetResolution_).to.eql(0.5);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -511,6 +511,20 @@ void main(void) {
|
|||||||
expect(result.uniforms).to.have.property('u_ratio');
|
expect(result.uniforms).to.have.property('u_ratio');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('parses a style with a rotation expression using an attribute', function() {
|
||||||
|
const result = parseLiteralStyle({
|
||||||
|
symbol: {
|
||||||
|
symbolType: 'square',
|
||||||
|
size: 6,
|
||||||
|
rotation: ['get', 'heading']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.builder.attributes).to.eql(['float a_heading']);
|
||||||
|
expect(result.builder.varyings).to.eql([]);
|
||||||
|
expect(result.builder.rotationExpression).to.eql('a_heading');
|
||||||
|
});
|
||||||
|
|
||||||
it('correctly adds string variables to the string literals mapping', function() {
|
it('correctly adds string variables to the string literals mapping', function() {
|
||||||
const result = parseLiteralStyle({
|
const result = parseLiteralStyle({
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
Reference in New Issue
Block a user