Compare commits

..

96 Commits

Author SHA1 Message Date
Tim Schaub
d77ff64ec2 Doc components 2018-06-12 08:00:27 -06:00
Tim Schaub
ee27cf1e01 Move new examples to site/src/examples 2018-06-12 08:00:27 -06:00
ahocevar
54c438997f Render constructor params 2018-06-12 08:00:27 -06:00
ahocevar
a7d180047a Render class import with constructor conditionally 2018-06-12 08:00:27 -06:00
ahocevar
a224e51c3f Render name of classes without API constructor
FIXED: No import should be listed for these.
2018-06-12 08:00:27 -06:00
ahocevar
0482b7ced4 List classes without API constructor
TODO: No import should be listed for these.
2018-06-12 08:00:27 -06:00
ahocevar
ff729d1357 Render non-member constants 2018-06-12 08:00:27 -06:00
ahocevar
9a08666f1f Add list of static functions 2018-06-12 08:00:27 -06:00
ahocevar
2fa6af0636 Remove logic for no longer existent externs 2018-06-12 08:00:27 -06:00
ahocevar
5a4a98fbe4 Map all symbols to modules 2018-06-12 08:00:27 -06:00
Tim Schaub
c008dd1f2c Starting point for docs 2018-06-12 08:00:27 -06:00
Tim Schaub
fb7d8b7839 Generate module info 2018-06-12 07:59:20 -06:00
Tim Schaub
c5f2787284 Script to build site 2018-06-12 07:59:20 -06:00
Tim Schaub
97a862f8e6 Styled components 2018-06-12 07:53:54 -06:00
Tim Schaub
ac9b0c7c9f Example list on each example page 2018-06-12 07:53:53 -06:00
Tim Schaub
d33026d12c New site setup 2018-06-12 07:53:53 -06:00
Andreas Hocevar
affc59e2c5 Merge pull request #8261 from openlayers/greenkeeper/rollup-0.60.2
Update rollup to the latest version 🚀
2018-06-11 14:00:46 +02:00
greenkeeper[bot]
a67ca1f46c chore(package): update rollup to version 0.60.2 2018-06-11 09:51:32 +00:00
Andreas Hocevar
653e273214 Merge pull request #8260 from openlayers/greenkeeper/sinon-6.0.0
Update sinon to the latest version 🚀
2018-06-11 11:02:39 +02:00
greenkeeper[bot]
2c893d19a4 chore(package): update sinon to version 6.0.0 2018-06-11 07:23:59 +00:00
Andreas Hocevar
288ac0acdd Merge pull request #8258 from ahocevar/webpack-4
Use Webpack 4 for tests (and examples)
2018-06-08 14:56:52 +02:00
ahocevar
b2fef55ae9 Move uglifyjs-webpack-plugin to devDependencies 2018-06-08 13:55:42 +02:00
ahocevar
da755d9e84 Make tests (and sourcemap) work with webpack4 2018-06-08 13:00:10 +02:00
ahocevar
2837272590 Make webpack4 module structure work 2018-06-08 12:58:16 +02:00
ahocevar
649b7be4c2 Make common chunk (and sourcemap) work 2018-06-08 12:57:38 +02:00
ahocevar
f8abb5def1 Update dependencies 2018-06-08 12:56:32 +02:00
Tim Schaub
48cbca1f6e Upgrade to Webpack 4 2018-06-07 11:24:39 +02:00
Andreas Hocevar
79a5bd6538 Merge pull request #8252 from openlayers/greenkeeper/rollup-0.60.1
Update rollup to the latest version 🚀
2018-06-07 10:48:02 +02:00
greenkeeper[bot]
a3a092624e chore(package): update rollup to version 0.60.1 2018-06-07 06:23:01 +00:00
Frédéric Junod
7f71137147 Merge pull request #8250 from fredj/cleanup
Fix various jsdoc types
2018-06-06 16:47:14 +02:00
Andreas Hocevar
3683e1ef6e Merge pull request #8248 from openlayers/greenkeeper/serve-8.0.0
Update serve to the latest version 🚀
2018-06-06 16:15:56 +02:00
Frederic Junod
6444e6989d Add missing properties in option typedef 2018-06-06 16:14:22 +02:00
Frederic Junod
abc9d14dca Convert projection like to Projection in transform function 2018-06-06 16:14:22 +02:00
Frederic Junod
972781ea9d Better array typing 2018-06-06 16:14:22 +02:00
Frederic Junod
104a9a56e9 Simplify opt param test for undefined value
To make the closure compiler happy
2018-06-06 16:14:22 +02:00
greenkeeper[bot]
52a76ded63 chore(package): update serve to version 8.0.0 2018-06-06 10:37:52 +00:00
Andreas Hocevar
a2070362f9 Merge pull request #8247 from openlayers/greenkeeper/rollup-0.60.0
Update rollup to the latest version 🚀
2018-06-06 09:56:37 +02:00
greenkeeper[bot]
9b8883a871 chore(package): update rollup to version 0.60.0 2018-06-06 06:12:52 +00:00
Andreas Hocevar
448a33eb4b Merge pull request #8245 from ahocevar/fix-vectortile-docs
Fix vector tile docs and types
2018-06-05 17:03:40 +02:00
ahocevar
08e0a0dfea Fix vector tile docs and types 2018-06-05 16:38:15 +02:00
Andreas Hocevar
7e2814d110 Merge pull request #8241 from openlayers/greenkeeper/recast-0.15.0
Update recast to the latest version 🚀
2018-06-04 08:47:15 +02:00
greenkeeper[bot]
c21d39840c chore(package): update recast to version 0.15.0 2018-06-02 04:22:24 +00:00
Andreas Hocevar
94b7641f90 Merge pull request #8233 from ahocevar/rollup
Use rollup instead of webpack for the full build
2018-05-30 18:21:16 +02:00
Andreas Hocevar
95b38a1744 Merge pull request #8231 from bjornharrtell/fix-jsts2
Fix JSTS usage with OL classes injected
2018-05-30 14:00:54 +02:00
ahocevar
04e825e49a Use rollup instead of webpack for the full build 2018-05-29 15:24:51 +02:00
Tim Schaub
ab72edd698 Merge pull request #8230 from openlayers/greenkeeper/serve-7.0.0
Update serve to the latest version 🚀
2018-05-28 21:43:17 -06:00
Andreas Hocevar
25034ffd95 Merge pull request #8229 from ahocevar/raster-from-vectorlayer
Support layers instead of renderers for ol/source/Raster
2018-05-28 22:15:02 +02:00
Björn Harrtell
6e27a89fef Fix and simplify import/inject 2018-05-28 21:09:27 +02:00
Björn Harrtell
8369da365f Fix JSTS usage with OL classes injected 2018-05-28 21:09:21 +02:00
greenkeeper[bot]
f02d0afdcf chore(package): update serve to version 7.0.0 2018-05-28 17:11:33 +00:00
ahocevar
f5399de58d Improve API docs 2018-05-28 10:39:29 +02:00
ahocevar
93287cb9fe Remove redundant check 2018-05-28 10:37:22 +02:00
ahocevar
81c0c80a2b Support tile, image and vector layers 2018-05-28 10:28:27 +02:00
ahocevar
137c875df7 Support vector layers instead of renderers for ol/source/Raster 2018-05-28 10:23:47 +02:00
Andreas Hocevar
97dedc7d07 Merge pull request #8227 from ahocevar/better-vectortile-experience
Better vectortile experience
2018-05-28 09:49:26 +02:00
ahocevar
8e42f0601a Add a note about the disabled transition option 2018-05-27 13:48:48 +02:00
ahocevar
da570c3a74 Update tests 2018-05-27 13:48:48 +02:00
Andreas Hocevar
a59dd8ea65 Merge pull request #8225 from ahocevar/image-vector-fixes
renderMode: 'image' fixes for ol/layer/Vector
2018-05-25 14:46:53 +02:00
Andreas Hocevar
eca6918471 Merge pull request #8226 from ahocevar/rastersource-renderer
Accept renderers as sources for the Raster source
2018-05-25 14:45:42 +02:00
ahocevar
3e07eef17e Remove extra param annotation 2018-05-25 12:27:21 +02:00
ahocevar
f53a1e7507 Accept renderers as sources for the raster source 2018-05-25 12:18:02 +02:00
ahocevar
c7207c5a07 Allow using the image renderer vor vector layers 2018-05-25 12:18:02 +02:00
ahocevar
e666b7cdeb Do not clip the image for vector layers 2018-05-25 10:40:20 +02:00
ahocevar
c2c9cdc9ea Update documentation for renderMode: image 2018-05-25 09:47:42 +02:00
ahocevar
4f471c786f Fix prepare/compose sequence to support icon loading 2018-05-25 09:46:44 +02:00
ahocevar
d867ae1f0e Avoid duplicate precompose and postcompose events 2018-05-25 09:45:09 +02:00
ahocevar
c24976155b Prepare tiles for rendering earlier
By overriding getTile() and creating replay and image there, we can do
all preparations earlier and stop creating new tiles when we have maxed
out the frame time budget. It also allows us to get rid of the
drawTileImage override.
2018-05-24 15:56:26 +02:00
ahocevar
690efda169 Stop preparing new tiles when out of frame time budget 2018-05-24 15:55:36 +02:00
ahocevar
d60987b33c Move getTile logic to a dedicated method 2018-05-24 15:49:00 +02:00
ahocevar
710cefc8dc Create interim tiles for vector image tiles 2018-05-24 15:42:30 +02:00
ahocevar
dcdfc22b95 For performance, remove transition for vector tiles 2018-05-24 15:39:33 +02:00
ahocevar
64ad81cffa Use calculated extent 2018-05-23 16:23:37 +02:00
Andreas Hocevar
7149b6ddab Merge pull request #8210 from ahocevar/stable-pattern-offset
Align patterns and gradients to a grid
2018-05-22 17:30:59 +02:00
ahocevar
976bb6b23c Indicate required fill alignment with boolean 2018-05-22 16:30:42 +02:00
ahocevar
7cfa65b8c3 Align patterns and gradients to a grid 2018-05-22 16:05:32 +02:00
Tim Schaub
c32bd2274c Merge pull request #8208 from openlayers/greenkeeper/marked-0.4.0
Update marked to the latest version 🚀
2018-05-21 13:44:08 -06:00
greenkeeper[bot]
791115b826 chore(package): update marked to version 0.4.0 2018-05-21 14:04:05 +00:00
Andreas Hocevar
27313bf65a Merge pull request #8205 from openlayers/greenkeeper/mocha-5.2.0
Update mocha to the latest version 🚀
2018-05-21 04:54:15 -05:00
Andreas Hocevar
8eafdf1884 Merge pull request #8201 from ahocevar/no-babelrc
Remove babelrc, transform using babel-core
2018-05-21 03:52:00 -05:00
ahocevar
614b8cd7be Add babel-core as explicit dev dependency 2018-05-21 10:36:47 +02:00
greenkeeper[bot]
8717f10e60 chore(package): update mocha to version 5.2.0 2018-05-19 02:22:04 +00:00
Andreas Hocevar
9d5983ee68 Merge pull request #8203 from ahocevar/typechecking-complete
Type checking complete
2018-05-18 08:24:01 -05:00
Andreas Hocevar
2949e8d594 Merge pull request #8204 from ahocevar/control-defaults
Document ol/control~defaults in the right place
2018-05-18 08:23:39 -05:00
ahocevar
83e00269b7 Document ol/control~defaults in the right place 2018-05-17 18:19:14 -05:00
ahocevar
ee395c325c Change typecheck warnings to errors 2018-05-17 12:30:01 -05:00
ahocevar
64e1139230 Fix remaining type issues 2018-05-17 12:29:22 -05:00
ahocevar
8b8d94c78a Remove babelrc, transform using babel-core 2018-05-17 11:40:48 -05:00
Frédéric Junod
848de0ab64 Merge pull request #8200 from fredj/f_8199
Set textAlign to the canvas context
2018-05-17 14:57:48 +02:00
Frederic Junod
b34cdb58e3 Set textAlign to the canvas context 2018-05-17 13:15:04 +02:00
Frédéric Junod
8271a51f65 Merge pull request #8194 from fredj/cleanup
miscellaneous code cleanup
2018-05-16 08:31:27 +02:00
Andreas Hocevar
39ce30f09a Merge pull request #8189 from ahocevar/more-apidoc-fixes
More apidoc fixes
2018-05-14 23:11:39 -05:00
Frederic Junod
90ce02941a Better code indentation 2018-05-14 14:58:36 +02:00
Frederic Junod
9f3b103bbf Better variables scoping 2018-05-14 14:49:09 +02:00
Frederic Junod
7f0043694d Remove NOCOMPILE from examples 2018-05-14 14:42:57 +02:00
Andreas Hocevar
ab5efa37b1 Merge pull request #8191 from ahocevar/fix-text-stroke
Do not scale text outline width
2018-05-14 07:29:16 -05:00
ahocevar
26b84f09bd Do not scale text outline width 2018-05-13 18:04:53 -05:00
106 changed files with 17522 additions and 565 deletions

View File

@@ -1,9 +0,0 @@
{
"plugins": ["jsdoc-closure"],
"parserOpts": {
"parser": "recast"
},
"generatorOpts": {
"generator": "recast"
}
}

View File

@@ -2,6 +2,14 @@
### Next release
#### `transition` option of `ol/source/VectorTile` is ignored
The `transition` option to get an opacity transition to fade in tiles has been disabled for `ol/source/VectorTile`. Vector tiles are now always rendered without an opacity transition.
#### `ol/style/Fill` with `CanvasGradient` or `CanvasPattern`
The origin for gradients and patterns has changed from the top-left corner of the extent of the geometry being filled to 512 css pixel increments from map coordinate `[0, 0]`. This allows repeat patterns to be aligned properly with vector tiles. For seamless repeat patterns, width and height of the pattern image must be a factor of two (2, 4, 8, ..., 512).
#### Removal of the renderer option for maps
The `renderer` option has been removed from the `Map` constructor. The purpose of this change is to avoid bundling code in your application that you do not need. Previously, code for both the Canvas and WebGL renderers was included in all applications - even though most people only use one renderer. The `Map` constructor now gives you a Canvas (2D) based renderer. If you want to try the WebGL renderer, you can import the constructor from `ol/WebGLMap`.

View File

@@ -11,7 +11,6 @@
},
"plugins": [
"config/jsdoc/info/api-plugin",
"config/jsdoc/info/define-plugin",
"config/jsdoc/info/virtual-plugin"
"config/jsdoc/info/module-plugin"
]
}

View File

@@ -1,35 +0,0 @@
/**
* @fileoverview This plugin extracts info from boolean defines. This only
* handles boolean defines with the default value in the description. Default
* is assumed to be provided with something like "default is `true`" (case
* insensitive, with or without ticks).
*/
const DEFAULT_VALUE = /default\s+is\s+`?(true|false)`?/i;
/**
* Hook to define new tags.
* @param {Object} dictionary The tag dictionary.
*/
exports.defineTags = function(dictionary) {
dictionary.defineTag('define', {
canHaveType: true,
mustHaveValue: true,
onTagged: function(doclet, tag) {
const types = tag.value.type.names;
if (types.length === 1 && types[0] === 'boolean') {
const match = tag.value.description.match(DEFAULT_VALUE);
if (match) {
doclet.define = {
default: match[1] === 'true'
};
doclet.description = tag.value.description;
}
}
}
});
};

View File

@@ -0,0 +1,135 @@
const path = require('path');
const exportLookup = {};
const moduleLookup = {};
const MODULE_PATH = /^module:(.*)~(\w+)$/;
/**
* Add exports to modules.
*/
exports.handlers = {
symbolFound(event) {
const filename = event.filename;
const node = event.astnode;
let local, exported;
switch (node.type) {
case 'ExportDefaultDeclaration': {
exported = 'default';
switch (node.declaration.type) {
case 'Identifier': {
// export default foo;
local = node.declaration.name;
break;
}
case 'FunctionDeclaration': {
if (!node.declaration.id) {
// export default function() {}
local = '';
} else {
// export default function foo() {}
local = node.declaration.id.name;
}
break;
}
default: {
local = '';
}
}
break;
}
case 'ExportNamedDeclaration': {
if (!node.declaration) {
// export {foo}
// export {foo as bar}
// handled below in ExportSpecifier
return;
}
switch (node.declaration.type) {
case 'FunctionDeclaration': {
if (!node.declaration.id) {
throw new Error(`Expected function declaration to have an id in ${filename}`);
}
const name = node.declaration.id.name;
local = name;
exported = name;
break;
}
default: {
return;
}
}
break;
}
case 'ExportSpecifier': {
if (node.exported.type === 'Identifier') {
exported = node.exported.name;
if (node.local.type === 'Identifier') {
local = node.local.name;
if (node.parent.source) {
const resolved = path.resolve(path.dirname(filename), node.parent.source.value);
local = `module:${resolved}~${local}`;
}
} else {
local = '';
}
} else {
return;
}
break;
}
default: {
return;
}
}
if (!(filename in exportLookup)) {
exportLookup[filename] = {};
}
const exports = exportLookup[filename];
if (exports.hasOwnProperty(exported)) {
throw new Error(`Duplicate export {${local} as ${exported}} in ${filename}`);
}
exports[exported] = local;
},
newDoclet(event) {
const doclet = event.doclet;
if (doclet.kind === 'module') {
const filepath = path.join(doclet.meta.path, doclet.meta.filename);
if (filepath in moduleLookup) {
throw new Error(`Duplicate @module annotation in ${filepath}`);
}
moduleLookup[filepath] = doclet;
}
},
parseComplete(event) {
for (const filepath in moduleLookup) {
const doclet = moduleLookup[filepath];
const exports = exportLookup[filepath];
for (const exported in exports) {
const local = exports[exported];
const match = local.match(MODULE_PATH);
if (match) {
const filepath = match[1];
const mod = moduleLookup[filepath];
if (mod) {
exports[exported] = `module:${mod.name}~${match[2]}`;
}
}
}
doclet.exports = exports; // undefined if no exports
}
}
};

View File

@@ -1,6 +1,5 @@
/**
* @fileoverview Generates JSON output based on exportable symbols (those with
* an api tag) and boolean defines (with a define tag and a default value).
* @fileoverview Generates JSON output based on exportable symbols.
*/
const assert = require('assert');
const path = require('path');
@@ -22,7 +21,7 @@ exports.publish = function(data, opts) {
return types;
}
// get all doclets with the "api" property or define (excluding events)
// get all doclets with the "api" property
const classes = {};
const docs = data(
[
@@ -34,7 +33,7 @@ exports.publish = function(data, opts) {
return true;
}
}
return (typeof this.api == 'boolean' ||
return (this.kind === 'module' || typeof this.api == 'boolean' ||
this.meta && (/[\\\/]externs$/).test(this.meta.path));
}
],
@@ -43,9 +42,9 @@ exports.publish = function(data, opts) {
// get symbols data, filter out those that are members of private classes
const symbols = [];
const defines = [];
const typedefs = [];
const externs = [];
const modules = [];
let base = [];
const augments = {};
const symbolsByName = {};
@@ -59,13 +58,11 @@ exports.publish = function(data, opts) {
}
return include;
}).forEach(function(doc) {
const isExterns = (/[\\\/]externs$/).test(doc.meta.path);
if (doc.define) {
defines.push({
if (doc.kind == 'module') {
modules.push({
name: doc.longname,
description: doc.description,
path: path.join(doc.meta.path, doc.meta.filename),
default: doc.define.default
exports: doc.exports || null,
path: path.join(doc.meta.path, doc.meta.filename)
});
} else if (doc.kind == 'typedef' || doc.isEnum === true) {
typedefs.push({
@@ -82,6 +79,9 @@ exports.publish = function(data, opts) {
if (doc.augments) {
symbol.extends = doc.augments[0];
}
if (doc.memberof) {
symbol.memberof = doc.memberof;
}
if (doc.virtual) {
symbol.virtual = true;
}
@@ -92,7 +92,8 @@ exports.publish = function(data, opts) {
const params = [];
doc.params.forEach(function(param) {
const paramInfo = {
name: param.name
name: param.name,
description: param.description
};
params.push(paramInfo);
paramInfo.types = getTypes(param.type.names);
@@ -126,7 +127,7 @@ exports.publish = function(data, opts) {
});
}
const target = isExterns ? externs : (doc.api ? symbols : base);
const target = doc.api ? symbols : base;
const existingSymbol = symbolsByName[symbol.name];
if (existingSymbol) {
const idx = target.indexOf(existingSymbol);
@@ -155,10 +156,10 @@ exports.publish = function(data, opts) {
process.stdout.write(
JSON.stringify({
symbols: symbols,
defines: defines,
typedefs: typedefs,
externs: externs,
base: base
base: base,
modules: modules
}, null, 2));
});

View File

@@ -1,16 +0,0 @@
/**
* Handle the interface and abstract annotations.
* @param {Object} dictionary The tag dictionary.
*/
exports.defineTags = function(dictionary) {
const classTag = dictionary.lookUp('class');
dictionary.defineTag('interface', {
mustHaveValue: false,
onTagged: function(doclet, tag) {
classTag.onTagged.apply(this, arguments);
doclet.virtual = true;
}
});
};

21
config/rollup.js Normal file
View File

@@ -0,0 +1,21 @@
// Rollup configuration for the full build
import noderesolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import {uglify} from 'rollup-plugin-uglify';
import buble from 'rollup-plugin-buble';
import sourcemaps from 'rollup-plugin-sourcemaps';
export default {
input: 'src/index.js',
output: [
{file: 'build/ol.js', format: 'iife', sourcemap: true}
],
plugins: [
noderesolve(),
commonjs(),
buble(),
uglify(),
sourcemaps()
]
};

View File

@@ -1,14 +0,0 @@
const webpack = require('webpack');
const MinifyPlugin = require('babel-minify-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'build/ol.js'
},
devtool: 'source-map',
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new MinifyPlugin()
]
};

View File

@@ -3,10 +3,11 @@ layout: example.html
title: Styling feature with CanvasGradient or CanvasPattern
shortdesc: Example showing the countries vector layer styled with patterns and gradients.
docs: >
First this example creates a reusable [`CanvasPattern`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern)
This example creates a [`CanvasPattern`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern)
and a [`CanvasGradient`](https://developer.mozilla.org/en/docs/Web/API/CanvasGradient). The countries are loaded from
a GeoJSON file. A style function determines for each country whether to use a fill with the pregenerated
CanvasGradient (rainbow colors) or a CanvasPattern (repeating stacked circles).
a GeoJSON file. A style function determines for each country whether to use a fill with the
CanvasGradient (rainbow colors) or a CanvasPattern (repeating stacked circles). **Note**: For seamless repeat patterns,
image width and height of the pattern image must be a factor of two (2, 4, 8, ..., 512).
tags: "canvas, gradient, pattern, style"
---
<div id="map" class="map"></div>

View File

@@ -1,6 +1,5 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {getWidth} from '../src/ol/extent.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import {DEVICE_PIXEL_RATIO} from '../src/ol/has.js';
import VectorLayer from '../src/ol/layer/Vector.js';
@@ -16,14 +15,8 @@ const context = canvas.getContext('2d');
const pixelRatio = DEVICE_PIXEL_RATIO;
// Generate a rainbow gradient
function gradient(feature, resolution) {
const extent = feature.getGeometry().getExtent();
// Gradient starts on the left edge of each feature, and ends on the right.
// Coordinate origin is the top-left corner of the extent of the geometry, so
// we just divide the geometry's extent width by resolution and multiply with
// pixelRatio to match the renderer's pixel coordinate system.
const grad = context.createLinearGradient(0, 0,
getWidth(extent) / resolution * pixelRatio, 0);
const gradient = (function() {
const grad = context.createLinearGradient(0, 0, 512 * pixelRatio, 0);
grad.addColorStop(0, 'red');
grad.addColorStop(1 / 6, 'orange');
grad.addColorStop(2 / 6, 'yellow');
@@ -32,24 +25,24 @@ function gradient(feature, resolution) {
grad.addColorStop(5 / 6, 'blue');
grad.addColorStop(1, 'purple');
return grad;
}
})();
// Generate a canvasPattern with two circles on white background
const pattern = (function() {
canvas.width = 11 * pixelRatio;
canvas.height = 11 * pixelRatio;
canvas.width = 8 * pixelRatio;
canvas.height = 8 * pixelRatio;
// white background
context.fillStyle = 'white';
context.fillRect(0, 0, canvas.width, canvas.height);
// outer circle
context.fillStyle = 'rgba(102, 0, 102, 0.5)';
context.beginPath();
context.arc(5 * pixelRatio, 5 * pixelRatio, 4 * pixelRatio, 0, 2 * Math.PI);
context.arc(4 * pixelRatio, 4 * pixelRatio, 3 * pixelRatio, 0, 2 * Math.PI);
context.fill();
// inner circle
context.fillStyle = 'rgb(55, 0, 170)';
context.beginPath();
context.arc(5 * pixelRatio, 5 * pixelRatio, 2 * pixelRatio, 0, 2 * Math.PI);
context.arc(4 * pixelRatio, 4 * pixelRatio, 1.5 * pixelRatio, 0, 2 * Math.PI);
context.fill();
return context.createPattern(canvas, 'repeat');
}());
@@ -69,12 +62,11 @@ const style = new Style({
* which either contains the aboove gradient or pattern.
*
* @param {module:ol/Feature~Feature} feature The feature to style.
* @param {number} resolution Resolution.
* @return {module:ol/style/Style} The style to use for the feature.
*/
const getStackedStyle = function(feature, resolution) {
const getStackedStyle = function(feature) {
const id = feature.getId();
fill.setColor(id > 'J' ? gradient(feature, resolution) : pattern);
fill.setColor(id > 'J' ? gradient : pattern);
return style;
};
@@ -94,7 +86,7 @@ const map = new Map({
],
target: 'map',
view: new View({
center: fromLonLat([7, 52]),
center: fromLonLat([16, 48]),
zoom: 3
})
});

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import ImageLayer from '../src/ol/layer/Image.js';

1
examples/d3.js vendored
View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {getWidth, getCenter} from '../src/ol/extent.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {defaults as defaultControls} from '../src/ol/control.js';

View File

@@ -1,5 +1,3 @@
// NOCOMPILE
// this example uses FileSaver.js for which we don't have an externs file.
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {defaults as defaultControls} from '../src/ol/control.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {defaults as defaultControls} from '../src/ol/control.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';

View File

@@ -7,6 +7,6 @@ docs: >
with OpenLayers.
tags: "vector, jsts, buffer"
resources:
- https://cdn.rawgit.com/bjornharrtell/jsts/gh-pages/1.4.0/jsts.min.js
- https://cdn.rawgit.com/bjornharrtell/jsts/gh-pages/1.6.0/jsts.min.js
---
<div id="map" class="map"></div>

View File

@@ -1,5 +1,3 @@
// NOCOMPILE
// this example uses JSTS for which we don't have an externs file.
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
@@ -7,7 +5,8 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {fromLonLat} from '../src/ol/proj.js';
import OSM from '../src/ol/source/OSM.js';
import VectorSource from '../src/ol/source/Vector.js';
import LinearRing from '../src/ol/geom/LinearRing.js';
import {Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon} from '../src/ol/geom.js';
const source = new VectorSource();
fetch('data/geojson/roads-seoul.geojson').then(function(response) {
@@ -17,6 +16,7 @@ fetch('data/geojson/roads-seoul.geojson').then(function(response) {
const features = format.readFeatures(json, {featureProjection: 'EPSG:3857'});
const parser = new jsts.io.OL3Parser();
parser.inject(Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon);
for (let i = 0; i < features.length; i++) {
const feature = features[i];

View File

@@ -1,5 +1,3 @@
// NOCOMPILE
// this example uses d3 for which we don't have an externs file.
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';

View File

@@ -1,4 +1,3 @@
// NOCOMPILE
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';

View File

@@ -1,6 +1,3 @@
// NOCOMPILE
// this example uses topolis and toastr for which we don't have an externs file.
import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';

View File

@@ -1,5 +1,3 @@
// NOCOMPILE
// this example uses turf.js for which we don't have an externs file.
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';

View File

@@ -1,10 +1,7 @@
const MinifyPlugin = require('babel-minify-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const ExampleBuilder = require('./example-builder');
const fs = require('fs');
const merge = require('webpack-merge');
const path = require('path');
const webpack = require('webpack');
const src = path.join(__dirname, '..');
@@ -17,15 +14,21 @@ examples.forEach(example => {
entry[example] = `./${example}.js`;
});
const main = {
module.exports = {
context: src,
target: 'web',
entry: entry,
plugins: [
new webpack.optimize.CommonsChunkPlugin({
optimization: {
runtimeChunk: {
name: 'common'
},
splitChunks: {
name: 'common',
chunks: 'initial',
minChunks: 2
}),
}
},
plugins: [
new ExampleBuilder({
templates: path.join(__dirname, '..', 'templates'),
common: 'common'
@@ -38,45 +41,9 @@ const main = {
{from: 'index.html', to: 'index.html'}
])
],
devtool: 'source-map',
output: {
filename: '[name].js',
path: path.join(__dirname, '..', '..', 'build', 'examples')
}
};
// configuration specific to the dev environment
const dev = {
devtool: 'source-map',
plugins: [
new webpack.EnvironmentPlugin(
Object.assign({NODE_ENV: 'development'}, process.env)
)
]
};
// configuration specific to the prod environment
const prod = {
plugins: [
new webpack.EnvironmentPlugin(
Object.assign({NODE_ENV: 'production'}, process.env)
),
new MinifyPlugin()
]
};
module.exports = env => {
let config;
switch (env) {
case 'prod': {
config = merge(main, prod);
break;
}
default: {
config = merge(main, dev);
}
}
return config;
};

View File

@@ -5,6 +5,7 @@ const marked = require('marked');
const path = require('path');
const pkg = require('../../package.json');
const promisify = require('util').promisify;
const RawSource = require('webpack-sources').RawSource;
const readFile = promisify(fs.readFile);
const isCssRegEx = /\.css$/;
@@ -60,6 +61,28 @@ function createWordIndex(exampleData) {
return index;
}
/**
* Gets the source for the chunk that matches the jsPath
* @param {Object} chunk Chunk.
* @param {string} jsPath Path of the file.
* @return {string} The source.
*/
function getJsSource(chunk, jsPath) {
let jsSource;
for (let i = 0, ii = chunk.modules.length; i < ii; ++i) {
const module = chunk.modules[i];
if (module.modules) {
jsSource = getJsSource(module, jsPath);
if (jsSource) {
return jsSource;
}
}
if (module.identifier == jsPath) {
return module.source;
}
}
}
/**
* A webpack plugin that builds the html files for our examples.
* @param {Object} config Plugin configuration. Requires a `templates` property
@@ -77,7 +100,7 @@ function ExampleBuilder(config) {
* @param {Object} compiler The webpack compiler.
*/
ExampleBuilder.prototype.apply = function(compiler) {
compiler.plugin('emit', async (compilation, callback) => {
compiler.hooks.emit.tapPromise('ExampleBuilder', async (compilation) => {
const chunks = compilation.getStats().toJson().chunks
.filter(chunk => chunk.names[0] !== this.common);
@@ -94,19 +117,11 @@ ExampleBuilder.prototype.apply = function(compiler) {
});
for (const file in assets) {
compilation.assets[file] = {
source: () => assets[file],
size: () => assets[file].length
};
compilation.assets[file] = new RawSource(assets[file]);
}
});
try {
await Promise.all(promises);
} catch (err) {
callback(err);
return;
}
await Promise.all(promises);
const info = {
examples: exampleData,
@@ -114,12 +129,7 @@ ExampleBuilder.prototype.apply = function(compiler) {
};
const indexSource = `var info = ${JSON.stringify(info)}`;
compilation.assets['index.js'] = {
source: () => indexSource,
size: () => indexSource.length
};
callback();
compilation.assets['index.js'] = new RawSource(indexSource);
});
};
@@ -142,14 +152,7 @@ ExampleBuilder.prototype.render = async function(dir, chunk) {
// add in script tag
const jsName = `${name}.js`;
const jsPath = path.join(dir, jsName);
let jsSource;
for (let i = 0, ii = chunk.modules.length; i < ii; ++i) {
const module = chunk.modules[i];
if (module.identifier == jsPath) {
jsSource = module.source;
break;
}
}
let jsSource = getJsSource(chunk, jsPath);
jsSource = jsSource.replace(/'\.\.\/src\//g, '\'');
if (data.cloak) {
for (const entry of data.cloak) {

View File

@@ -14,13 +14,14 @@
"posttest": "npm run typecheck",
"test": "npm run karma -- --single-run",
"karma": "karma start test/karma.config.js",
"serve-examples": "mkdir -p build/examples && webpack --config examples/webpack/config.js --watch & serve build/examples",
"build-examples": "webpack --config examples/webpack/config.js --env=prod",
"build-index": "node tasks/generate-index.js",
"serve-examples": "mkdir -p build/examples && webpack --config examples/webpack/config.js --mode development --watch & serve build/examples",
"build-examples": "webpack --config examples/webpack/config.js --mode production",
"build-index": "node tasks/generate-index",
"build-site": "node tasks/generate-info.js && cd site && npm install && npm run build",
"prebuild": "npm run build-index",
"build": "webpack --config config/webpack.js",
"build": "rollup --config config/rollup.js",
"presrc-closure": "npm run prebuild",
"src-closure": "babel -q --out-dir build/src-closure src/",
"src-closure": "node tasks/transform-types",
"pretypecheck": "npm run src-closure",
"typecheck": "node tasks/typecheck",
"apidoc": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
@@ -39,26 +40,29 @@
"css/ol.css"
],
"dependencies": {
"babel-eslint": "^8.2.3",
"pbf": "3.1.0",
"pixelworks": "1.1.0",
"rbush": "2.0.2"
},
"devDependencies": {
"babel-cli": "6.26.0",
"babel-minify-webpack-plugin": "^0.3.0",
"babel-core": "^6.26.3",
"babel-plugin-jsdoc-closure": "1.5.1",
"chaikin-smooth": "1.0.4",
"chaikin-smooth": "^1.0.4",
"clean-css-cli": "4.1.11",
"copy-webpack-plugin": "^4.0.1",
"copy-webpack-plugin": "^4.4.1",
"coveralls": "3.0.1",
"eslint": "4.19.1",
"eslint-config-openlayers": "^9.2.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-prettier": "^2.6.0",
"eslint-plugin-react": "^7.7.0",
"expect.js": "0.3.1",
"front-matter": "^2.1.2",
"fs-extra": "^6.0.0",
"glob": "^7.1.2",
"google-closure-compiler": "20180506.0.0",
"handlebars": "4.0.11",
"html-webpack-plugin": "^3.0.1",
"istanbul": "0.4.5",
"jquery": "3.3.1",
"jsdoc": "3.5.5",
@@ -68,19 +72,28 @@
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "1.3.0",
"karma-sauce-launcher": "1.2.0",
"karma-webpack": "3.0.0",
"marked": "0.3.19",
"mocha": "5.1.1",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "4.0.0-beta.0",
"marked": "0.4.0",
"mocha": "5.2.0",
"mustache": "^2.3.0",
"pixelmatch": "^4.0.2",
"prettier": "^1.12.0",
"proj4": "2.4.4",
"recast": "0.14.7",
"serve": "^6.5.5",
"sinon": "^5.0.1",
"recast": "0.15.0",
"rollup": "0.60.2",
"rollup-plugin-buble": "0.19.2",
"rollup-plugin-commonjs": "9.1.3",
"rollup-plugin-node-resolve": "3.3.0",
"rollup-plugin-sourcemaps": "0.4.2",
"rollup-plugin-uglify": "4.0.0",
"serve": "^8.1.1",
"sinon": "^6.0.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-polyfill": "^1.0.13",
"walk": "^2.3.9",
"webpack": "3.11.0",
"webpack-merge": "4.1.2"
"webpack": "4.12.0",
"webpack-cli": "^3.0.3"
},
"eslintConfig": {
"extends": "openlayers"

1
site/.babelrc Normal file
View File

@@ -0,0 +1 @@
{}

7
site/.eslintrc Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": "openlayers/react",
"parser": "babel-eslint",
"globals": {
"graphql": false
}
}

4
site/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/node_modules/
/.cache/
/public/
/build/

30
site/gatsby-config.js Normal file
View File

@@ -0,0 +1,30 @@
const path = require('path');
const typography = require('./src/utils/typography');
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-typography',
options: {
pathToConfigModule: 'src/utils/typography.js'
}
},
'gatsby-plugin-emotion',
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'examples',
path: path.join(__dirname, 'src', 'examples')
}
},
{
resolve: 'examples',
options: {
sourceInstanceName: 'examples',
baseCss: typography.toString()
}
},
'gatsby-transformer-remark',
'gatsby-plugin-react-next'
]
};

3
site/gatsby-node.js Normal file
View File

@@ -0,0 +1,3 @@
// exports.onPreBuild = () => {
// // TODO: empty public folder
// };

15861
site/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
site/package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "@ol/site",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "gatsby develop",
"build": "gatsby build"
},
"devDependencies": {
"emotion": "^9.1.3",
"emotion-server": "^9.1.3",
"gatsby": "1.9.250",
"gatsby-link": "1.6.40",
"gatsby-plugin-emotion": "^1.1.16",
"gatsby-plugin-react-helmet": "2.0.10",
"gatsby-plugin-react-next": "^1.0.11",
"gatsby-plugin-typography": "1.7.18",
"gatsby-source-filesystem": "1.5.31",
"gatsby-transformer-remark": "^1.7.40",
"prop-types": "15.6.1",
"react-emotion": "^9.1.3",
"react-helmet": "5.2.0",
"react-markdown": "^3.3.2",
"rollup": "^0.58.1",
"rollup-plugin-commonjs": "^9.1.0",
"rollup-plugin-node-resolve": "^3.3.0",
"string-template": "^1.0.0",
"typography-plugin-code": "^0.16.11",
"typography-theme-noriega": "^0.15.10"
}
}

View File

@@ -0,0 +1,95 @@
import {object} from 'prop-types';
import ExampleList from './ExampleList';
import React, {Component, Fragment} from 'react';
import styled from 'react-emotion';
const Wrapper = styled('div')({
display: 'flex'
});
const Sidebar = styled('div')({
marginRight: '1em'
});
const Content = styled('div')({
minWidth: 300,
flexGrow: 1
});
const Embed = styled('iframe')({
margin: 0,
padding: 0,
height: 350,
width: '100%'
});
const Aside = styled('aside')({
textAlign: 'right',
fontSize: '0.75em'
});
const Block = styled('pre')({
overflow: 'auto'
});
class Example extends Component {
render() {
const example = this.props.data.sitePage.context;
return (
<Wrapper>
<Sidebar>
<ExampleList active={example.slug} />
</Sidebar>
<Content>
<h1>{example.frontmatter.title}</h1>
<Embed src={example.embedUrl} frameBorder="0" />
<Aside>
<p>
<a href={example.embedUrl}>stand-alone version</a>
</p>
</Aside>
<h3>script</h3>
<Block>
<code>{example.js}</code>
</Block>
<h3>markup</h3>
<Block>
<code>{example.html}</code>
</Block>
{example.css && (
<Fragment>
<h3>style</h3>
<Block>
<code>{example.css}</code>
</Block>
</Fragment>
)}
</Content>
</Wrapper>
);
}
}
Example.propTypes = {
data: object.isRequired
};
export const query = graphql`
query ExampleQuery($slug: String!) {
sitePage(context: {slug: {eq: $slug}}) {
context {
slug
frontmatter {
title
}
embedUrl
html
js
css
}
}
}
`;
export default Example;

View File

@@ -0,0 +1,54 @@
import Link from 'gatsby-link';
import React, {Component} from 'react';
import styled from 'react-emotion';
const Wrapper = styled('div')({
minWidth: '10em'
});
const List = styled('ul')({
margin: 0,
listStyle: 'none'
});
class ExampleList extends Component {
constructor(props) {
super(props);
this.state = {
index: null
};
}
componentDidMount() {
fetch('../index.json')
.then(response => response.json())
.then(index => {
this.setState({index});
});
}
renderList() {
const index = this.state.index;
if (!index) {
return '...';
}
const list = [];
for (const id in index) {
const example = index[id];
list.push(
<li key={id}>
<Link to={example.slug}>{example.title}</Link>
</li>
);
}
return <List>{list}</List>;
}
render() {
return <Wrapper>{this.renderList()}</Wrapper>;
}
}
export default ExampleList;

View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charSet="utf-8">
<title>{title}</title>
<style>{baseCss}</style>
<style>{olCss}</style>
<style>
html, body {
height: 100%;
overflow: hidden;
}
#map {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
</style>
<style>{exampleCss}</style>
</head>
<body>
{html}
<script type="module" src="{mainBundleUrl}"></script>
</body>
</html>

View File

@@ -0,0 +1,197 @@
const path = require('path');
const {createFilePath} = require('gatsby-source-filesystem');
const rollup = require('rollup');
const resolve = require('rollup-plugin-node-resolve');
const common = require('rollup-plugin-commonjs');
const fse = require('fs-extra');
const compileTemplate = require('string-template/compile');
let rollupCache;
const rollupPlugins = [resolve(), common()];
let olCss;
async function getOLCss() {
if (olCss) {
return olCss;
}
const cssPath = path.join(__dirname, '..', '..', '..', 'css', 'ol.css');
olCss = await fse.readFile(cssPath, {encoding: 'utf8'});
return olCss;
}
let embedTemplate;
async function getEmbedTemplate() {
if (embedTemplate) {
return embedTemplate;
}
const embedPath = path.join(__dirname, 'embed.html');
const src = await fse.readFile(embedPath, {encoding: 'utf8'});
embedTemplate = compileTemplate(src);
return embedTemplate;
}
exports.onCreateNode = ({node, getNode, boundActionCreators}) => {
const {createNodeField} = boundActionCreators;
if (node.internal.type === 'MarkdownRemark') {
const slug = createFilePath({node, getNode});
createNodeField({
node,
name: 'slug',
value: `/examples${slug}` // TODO: get this from options
});
}
};
exports.createPages = async (
{graphql, boundActionCreators},
{sourceInstanceName, baseCss = ''}
) => {
const {createPage, createRedirect} = boundActionCreators;
createRedirect({
fromPath: `/examples/`,
isPermanent: true,
redirectInBrowser: true,
toPath: `/examples/map/`
});
const {data} = await graphql(`
{
allFile(
filter: {sourceInstanceName: {eq: "${sourceInstanceName}"}, extension: {ne: ""}}
) {
edges {
node {
base
name
extension
absolutePath
childMarkdownRemark {
frontmatter {
title
}
fields {
slug
}
html
}
}
}
}
}
`);
const rollupInputs = [];
const examples = {};
data.allFile.edges.forEach(({node}) => {
const name = node.name;
if (!(name in examples)) {
examples[name] = {};
}
examples[name][node.extension] = node;
if (node.extension === 'js') {
rollupInputs.push(node.absolutePath);
}
});
const bundle = await rollup.rollup({
input: rollupInputs,
plugins: rollupPlugins,
experimentalCodeSplitting: true,
cache: rollupCache
});
const embedDirName = 'example-embeds';
const embedDir = path.join(__dirname, '..', '..', 'public', embedDirName);
const exampleDir = path.join(__dirname, '..', '..', 'public', 'examples');
rollupCache = await bundle.write({
format: 'es',
sourcemap: true,
dir: embedDir
});
const writes = [];
const index = {};
for (const name in examples) {
const node = examples[name].md;
if (!node) {
throw new Error(`Missing ${name}.md`);
}
const markdownNode = node.childMarkdownRemark;
if (!markdownNode) {
throw new Error(`Expected a MarkdownRemark node for ${name}`);
}
const mainBundleUrl = `${name}.js`;
const bundleInfo = rollupCache[mainBundleUrl];
if (!bundleInfo) {
throw new Error(`Expected a js bundle for ${name}`);
}
const jsNode = examples[name].js;
if (!jsNode) {
throw new Error(`Missing ${name}.js`);
}
const moduleIndex = bundleInfo.map.sources.findIndex(
filepath => path.resolve(filepath) === jsNode.absolutePath
);
if (moduleIndex < 0) {
throw new Error(`Could not find ${node.absolutePath} in module list`);
}
const source = bundleInfo.map.sourcesContent[moduleIndex];
if (!source) {
throw new Error(`Could not find source for ${jsNode.absolutePath}`);
}
let exampleCss = '';
const cssNode = examples[name].css;
if (cssNode) {
exampleCss = await fse.readFile(cssNode.absolutePath, {encoding: 'utf8'});
await fse.writeFile(path.join(embedDir, cssNode.base), exampleCss);
}
const embedTemplate = await getEmbedTemplate();
const embed = embedTemplate({
title: markdownNode.frontmatter.title,
baseCss,
olCss: await getOLCss(),
exampleCss,
html: markdownNode.html,
mainBundleUrl
});
const embedName = `${name}.html`;
writes.push(fse.writeFile(path.join(embedDir, embedName), embed));
const slug = markdownNode.fields.slug;
index[name] = {
title: markdownNode.frontmatter.title,
slug
};
createPage({
path: slug,
component: path.join(__dirname, 'components', 'Example.js'),
context: {
slug,
frontmatter: markdownNode.frontmatter,
embedUrl: `/${embedDirName}/${embedName}`,
html: markdownNode.html,
js: source.replace(/'\.\.\/\.\.\/\.\.\/src\/(.*?)\.js/g, "'$1"),
css: exampleCss
}
});
}
await fse.ensureDir(exampleDir);
writes.push(
fse.writeFile(path.join(exampleDir, 'index.json'), JSON.stringify(index))
);
await Promise.all(writes);
};

View File

@@ -0,0 +1 @@
// no-op

View File

@@ -0,0 +1,4 @@
{
"name": "examples",
"main": "index.js"
}

View File

@@ -0,0 +1,76 @@
import React, {Component, Fragment} from 'react';
import {string, array} from 'prop-types';
import Markdown from 'react-markdown';
import {slugify, getShortName, getShortModuleName} from '../../utils/doc';
class Class extends Component {
static propTypes = {
name: string.isRequired,
description: string,
params: array,
exported: string
};
renderArguments() {
if (!this.props.params) {
return null;
}
return (
<Fragment>
<h4>Arguments</h4>
<ul>{this.props.params.map(this.renderArgument)}</ul>
</Fragment>
);
}
renderArgument(arg) {
return (
<li key={arg.name}>
<code>{arg.name}</code>: {arg.description}
</li>
);
}
render() {
const name = this.props.name;
const shortName = getShortName(name);
const moduleName = getShortModuleName(name);
const slug = slugify(name);
const exported = this.props.exported;
let importSyntax;
if (exported) {
if (exported === 'default') {
importSyntax = `import ${shortName} from '${moduleName}';\n\n`;
} else if (exported !== shortName) {
importSyntax = `import {${exported} as ${shortName}} from '${moduleName}';\n\n`;
} else {
importSyntax = `import {${exported}} from '${moduleName}';\n\n`;
}
}
const params = this.props.params || [];
const usage = `new ${shortName}(${params
.map(param => param.name)
.join(', ')});`;
const description = this.props.description || '';
return (
<Fragment>
<a name={slug} href={`#${slug}`} />
<pre>
<code>
{importSyntax}
{usage}
</code>
</pre>
<Markdown source={description} />
{this.renderArguments()}
</Fragment>
);
}
}
export default Class;

View File

@@ -0,0 +1,76 @@
import React, {Component, Fragment} from 'react';
import {string, array} from 'prop-types';
import Markdown from 'react-markdown';
import {slugify, getShortName, getShortModuleName} from '../../utils/doc';
class Func extends Component {
static propTypes = {
name: string.isRequired,
description: string,
params: array,
exported: string
};
renderArguments() {
if (!this.props.params) {
return null;
}
return (
<Fragment>
<h4>Arguments</h4>
<ul>{this.props.params.map(this.renderArgument)}</ul>
</Fragment>
);
}
renderArgument(arg) {
return (
<li key={arg.name}>
<code>{arg.name}</code>: {arg.description}
</li>
);
}
render() {
const name = this.props.name;
const shortName = getShortName(name);
const moduleName = getShortModuleName(name);
const slug = slugify(name);
const exported = this.props.exported;
let importSyntax;
if (exported) {
if (exported === 'default') {
importSyntax = `import ${shortName} from '${moduleName}';\n\n`;
} else if (exported !== shortName) {
importSyntax = `import {${exported} as ${shortName}} from '${moduleName}';\n\n`;
} else {
importSyntax = `import {${exported}} from '${moduleName}';\n\n`;
}
}
const params = this.props.params || [];
const usage = `${shortName}(${params
.map(param => param.name)
.join(', ')});`;
const description = this.props.description || '';
return (
<Fragment>
<a name={slug} href={`#${slug}`} />
<pre>
<code>
{importSyntax}
{usage}
</code>
</pre>
<Markdown source={description} />
{this.renderArguments()}
</Fragment>
);
}
}
export default Func;

View File

@@ -0,0 +1,57 @@
import React, {Component, Fragment} from 'react';
import {string, array} from 'prop-types';
import {slugify, getShortModuleName} from '../../utils/doc';
import Func from './Func';
import Class from './Class';
class Module extends Component {
static propTypes = {
name: string.isRequired,
classes: array.isRequired,
functions: array.isRequired
};
renderClasses() {
if (this.props.classes.length === 0) {
return null;
}
return (
<Fragment>
<h3>Classes</h3>
{this.props.classes.map(cls => <Class key={cls.name} {...cls} />)}
</Fragment>
);
}
renderFuncs() {
if (this.props.functions.length === 0) {
return null;
}
return (
<Fragment>
<h3>Functions</h3>
{this.props.functions.map(func => <Func key={func.name} {...func} />)}
</Fragment>
);
}
render() {
const name = this.props.name;
const slug = slugify(name);
return (
<section>
<a name={slug} href={`#${slug}`}>
<h1>
<code>{getShortModuleName(name)}</code>
</h1>
</a>
{this.renderClasses()}
{this.renderFuncs()}
</section>
);
}
}
export default Module;

View File

@@ -0,0 +1,10 @@
{
"rules": {
"no-unused-vars": [
"error",
{
"varsIgnorePattern": "^map"
}
]
}
}

View File

@@ -0,0 +1,39 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import GeoJSON from '../../../src/ol/format/GeoJSON.js';
import {
Tile as TileLayer,
Vector as VectorLayer
} from '../../../src/ol/layer.js';
import {BingMaps, Vector as VectorSource} from '../../../src/ol/source.js';
import {Style, Stroke} from '../../../src/ol/style.js';
const map = new Map({
layers: [
new TileLayer({
source: new BingMaps({
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
imagerySet: 'Aerial'
})
}),
new VectorLayer({
source: new VectorSource({
format: new GeoJSON(),
url:
'https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json'
}),
opacity: 0.5,
style: new Style({
stroke: new Stroke({
width: 1.25,
color: 'lightgrey'
})
})
})
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});

View File

@@ -0,0 +1,10 @@
---
title: Multiple Layers
shortdesc: Using layers to compose a map.
docs: >
Layers control how data is rendered on a map. In this example, a `Vector` layer displays GeoJSON over tiles from a `Tile` layer.
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
---
<div id="map"></div>

17
site/src/examples/map.js Normal file
View File

@@ -0,0 +1,17 @@
import Map from '../../../src/ol/Map.js';
import View from '../../../src/ol/View.js';
import TileLayer from '../../../src/ol/layer/Tile.js';
import OSM from '../../../src/ol/source/OSM.js';
const map = new Map({
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 1
})
});

7
site/src/examples/map.md Normal file
View File

@@ -0,0 +1,7 @@
---
title: My First Map
shortdesc: Example of a map with a single layer.
docs: >
A map with an OSM source.
---
<div id="map"></div>

44
site/src/layouts/index.js Normal file
View File

@@ -0,0 +1,44 @@
import {func} from 'prop-types';
import Link from 'gatsby-link';
import React from 'react';
import styled from 'react-emotion';
const Page = styled('div')({
margin: '1em auto',
maxWidth: '960px'
});
const Header = styled('header')({
display: 'flex',
alignItems: 'baseline',
padding: '0 2em',
marginBottom: '2em',
'& h1': {
margin: '0 auto 0 0'
}
});
const Main = styled('main')({
padding: '0 2em'
});
const Layout = ({children}) => (
<Page>
<Header>
<h1>
<Link to="/">OpenLayers</Link>
</h1>
<div>
<Link to="/docs/">docs</Link>&nbsp;
<Link to="/examples/">examples</Link>
</div>
</Header>
<Main>{children()}</Main>
</Page>
);
Layout.propTypes = {
children: func.isRequired
};
export default Layout;

19
site/src/pages/docs.js Normal file
View File

@@ -0,0 +1,19 @@
import React, {Component, Fragment} from 'react';
import Module from '../components/doc/Module';
import {getModules} from '../utils/doc';
import info from '../../../build/info.json';
const modules = getModules(info);
class Docs extends Component {
render() {
return (
<Fragment>
{modules.map(mod => <Module key={mod.name} {...mod} />)}
</Fragment>
);
}
}
export default Docs;

View File

@@ -0,0 +1,42 @@
import React, {Component} from 'react';
import {object} from 'prop-types';
import Link from 'gatsby-link';
class Examples extends Component {
renderExample({node}) {
const context = node.context;
return (
<li key={node.id}>
<Link to={context.slug}>{context.frontmatter.title}</Link>
</li>
);
}
render() {
return <ul>{this.props.data.allSitePage.edges.map(this.renderExample)}</ul>;
}
}
Examples.propTypes = {
data: object.isRequired
};
export const query = graphql`
query ExampleList {
allSitePage(filter: {pluginCreator: {name: {eq: "examples"}}}) {
edges {
node {
id
context {
slug
frontmatter {
title
}
}
}
}
}
}
`;
export default Examples;

3
site/src/pages/index.js Normal file
View File

@@ -0,0 +1,3 @@
import React from 'react';
export default () => <p>This is the home page</p>;

111
site/src/utils/doc.js Normal file
View File

@@ -0,0 +1,111 @@
function getLongModuleName(name) {
return name.split(/[~\.]/).shift();
}
export function getShortModuleName(longname) {
return getLongModuleName(longname).slice(7);
}
export function getShortName(longname) {
return longname.split(/[~\.]/).pop();
}
export function slugify(name) {
return name.replace(/[#~\.]/g, '-');
}
function getExported(name, exports) {
const local = getShortName(name);
for (const exported in exports) {
if (exports[exported] === local) {
return exported;
}
}
}
export function getModules(info) {
const moduleLookup = {};
info.modules.forEach(mod => {
moduleLookup[mod.name] = {...mod, functions: [], classes: []};
});
// extract classes
const classLookup = {};
info.symbols.forEach(symbol => {
const name = symbol.name;
const parent = symbol.memberof;
if (symbol.kind === 'class') {
const mod = moduleLookup[parent];
if (!mod) {
throw new Error(
`No module found for class ${name} with parent ${parent}`
);
}
const cls = {
...symbol,
methods: [],
properties: [],
exported: getExported(name, mod.exports)
};
mod.classes.push(cls);
classLookup[name] = cls;
}
});
info.symbols.forEach(symbol => {
const name = symbol.name;
const parent = symbol.memberof;
if (symbol.kind === 'member') {
if (parent in classLookup) {
classLookup[parent].properties.push(symbol);
return;
}
// instance property where constructor is not marked @api
const moduleId = getLongModuleName(name);
const mod = moduleLookup[moduleId];
if (!mod) {
throw new Error(`Unexpected member: ${name}`);
}
const cls = {name: parent, methods: [], properties: [symbol]};
mod.classes.push(cls);
classLookup[parent] = cls;
return;
}
if (symbol.kind === 'function') {
if (parent in moduleLookup) {
moduleLookup[parent].functions.push({
...symbol,
exported: getExported(name, moduleLookup[parent].exports)
});
return;
}
if (parent in classLookup) {
classLookup[parent].methods.push(symbol);
return;
}
// method where constructor is not marked @api
const moduleId = getLongModuleName(name);
const mod = moduleLookup[moduleId];
if (!mod) {
throw new Error(`Unexpected function: ${name}`);
}
const cls = {name: parent, methods: [symbol], properties: []};
mod.classes.push(cls);
classLookup[parent] = cls;
return;
}
});
return Object.keys(moduleLookup)
.sort()
.map(id => moduleLookup[id]);
}

View File

@@ -0,0 +1,14 @@
const Typography = require('typography');
const theme = require('typography-theme-noriega').default;
const CodePlugin = require('typography-plugin-code').default;
theme.plugins = [new CodePlugin()];
theme.overrideThemeStyles = () => ({
a: {
color: '#003c88',
textDecoration: 'none'
}
});
module.exports = new Typography(theme);

View File

@@ -115,8 +115,7 @@ Collection.prototype.clear = function() {
* @api
*/
Collection.prototype.extend = function(arr) {
let i, ii;
for (i = 0, ii = arr.length; i < ii; ++i) {
for (let i = 0, ii = arr.length; i < ii; ++i) {
this.push(arr[i]);
}
return this;
@@ -225,8 +224,7 @@ Collection.prototype.push = function(elem) {
*/
Collection.prototype.remove = function(elem) {
const arr = this.array_;
let i, ii;
for (i = 0, ii = arr.length; i < ii; ++i) {
for (let i = 0, ii = arr.length; i < ii; ++i) {
if (arr[i] === elem) {
return this.removeAt(i);
}
@@ -270,8 +268,7 @@ Collection.prototype.setAt = function(index, elem) {
this.dispatchEvent(
new CollectionEvent(CollectionEventType.ADD, elem));
} else {
let j;
for (j = n; j < index; ++j) {
for (let j = n; j < index; ++j) {
this.insertAt(j, undefined);
}
this.insertAt(index, elem);

View File

@@ -61,6 +61,10 @@ const INTERVALS = [
* longitudes. This function is called with the longitude as argument, and
* should return a formatted string representing the longitude. By default,
* labels are formatted as degrees, minutes, seconds and hemisphere.
* @property {function(number):string} [latLabelFormatter] Label formatter for
* latitudes. This function is called with the latitude as argument, and
* should return a formatted string representing the latitude. By default,
* labels are formatted as degrees, minutes, seconds and hemisphere.
* @property {number} [lonLabelPosition=0] Longitude label position in fractions
* (0..1) of view extent. 0 means at the bottom of the viewport, 1 means at the
* top.
@@ -85,7 +89,7 @@ const INTERVALS = [
* Note that the default's `textBaseline` configuration will not work well for
* `lonLabelPosition` configurations that position labels close to the top of
* the viewport.
* @param {module:ol/style/Text} [latLabelStyle] Latitude label text style.
* @property {module:ol/style/Text} [latLabelStyle] Latitude label text style.
* If not provided, the following style will be used:
* ```js
* new Text({

View File

@@ -303,12 +303,9 @@ const PluggableMap = function(options) {
*/
this.keyHandlerKeys_ = null;
listen(this.viewport_, EventType.CONTEXTMENU,
this.handleBrowserEvent, this);
listen(this.viewport_, EventType.WHEEL,
this.handleBrowserEvent, this);
listen(this.viewport_, EventType.MOUSEWHEEL,
this.handleBrowserEvent, this);
listen(this.viewport_, EventType.CONTEXTMENU, this.handleBrowserEvent, this);
listen(this.viewport_, EventType.WHEEL, this.handleBrowserEvent, this);
listen(this.viewport_, EventType.MOUSEWHEEL, this.handleBrowserEvent, this);
/**
* @type {module:ol/Collection.<module:ol/control/Control>}
@@ -393,9 +390,9 @@ const PluggableMap = function(options) {
* @param {module:ol/control/Control} control Control.
* @this {module:ol/PluggableMap}
*/
function(control) {
(function(control) {
control.setMap(this);
}.bind(this));
}).bind(this));
listen(this.controls, CollectionEventType.ADD,
/**
@@ -418,9 +415,9 @@ const PluggableMap = function(options) {
* @param {module:ol/interaction/Interaction} interaction Interaction.
* @this {module:ol/PluggableMap}
*/
function(interaction) {
(function(interaction) {
interaction.setMap(this);
}.bind(this));
}).bind(this));
listen(this.interactions, CollectionEventType.ADD,
/**

View File

@@ -27,20 +27,18 @@ const TileQueue = function(tilePriorityFunction, tileChangeCallback) {
PriorityQueue.call(
this,
/**
* @param {Array} element Element.
* @return {number} Priority.
*/
* @param {Array} element Element.
* @return {number} Priority.
*/
function(element) {
return tilePriorityFunction.apply(null, element);
},
/**
* @param {Array} element Element.
* @return {string} Key.
*/
* @param {Array} element Element.
* @return {string} Key.
*/
function(element) {
return (
/** @type {module:ol/Tile} */ (element[0]).getKey()
);
return (/** @type {module:ol/Tile} */ (element[0]).getKey());
});
/**
@@ -73,8 +71,7 @@ TileQueue.prototype.enqueue = function(element) {
const added = PriorityQueue.prototype.enqueue.call(this, element);
if (added) {
const tile = element[0];
listen(tile, EventType.CHANGE,
this.handleTileChange, this);
listen(tile, EventType.CHANGE, this.handleTileChange, this);
}
return added;
};
@@ -97,8 +94,7 @@ TileQueue.prototype.handleTileChange = function(event) {
const state = tile.getState();
if (state === TileState.LOADED || state === TileState.ERROR ||
state === TileState.EMPTY || state === TileState.ABORT) {
unlisten(tile, EventType.CHANGE,
this.handleTileChange, this);
unlisten(tile, EventType.CHANGE, this.handleTileChange, this);
const tileKey = tile.getKey();
if (tileKey in this.tilesLoadingKeys_) {
delete this.tilesLoadingKeys_[tileKey];

View File

@@ -9,6 +9,7 @@ import {listen, unlistenByKey} from './events.js';
import {getHeight, getIntersection, getWidth} from './extent.js';
import EventType from './events/EventType.js';
import {loadFeaturesXhr} from './featureloader.js';
import {UNDEFINED} from './functions.js';
/**
@@ -40,13 +41,13 @@ import {loadFeaturesXhr} from './featureloader.js';
* instantiate for source tiles.
* @param {function(this: module:ol/source/VectorTile, module:ol/events/Event)} handleTileChange
* Function to call when a source tile's state changes.
* @param {module:ol/Tile~Options=} opt_options Tile options.
* @param {number} zoom Integer zoom to render the tile for.
*/
const VectorImageTile = function(tileCoord, state, sourceRevision, format,
tileLoadFunction, urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid,
sourceTiles, pixelRatio, projection, tileClass, handleTileChange, opt_options) {
sourceTiles, pixelRatio, projection, tileClass, handleTileChange, zoom) {
Tile.call(this, tileCoord, state, opt_options);
Tile.call(this, tileCoord, state, {transition: 0});
/**
* @private
@@ -78,6 +79,11 @@ const VectorImageTile = function(tileCoord, state, sourceRevision, format,
*/
this.tileKeys = [];
/**
* @type {module:ol/extent~Extent}
*/
this.extent = null;
/**
* @type {number}
*/
@@ -99,9 +105,11 @@ const VectorImageTile = function(tileCoord, state, sourceRevision, format,
this.sourceTileListenerKeys_ = [];
if (urlTileCoord) {
const extent = tileGrid.getTileCoordExtent(urlTileCoord);
const resolution = tileGrid.getResolution(tileCoord[0]);
const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord);
const resolution = tileGrid.getResolution(zoom);
const sourceZ = sourceTileGrid.getZForResolution(resolution);
const useLoadedOnly = zoom != tileCoord[0];
let loadCount = 0;
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
let sharedExtent = getIntersection(extent,
sourceTileGrid.getTileCoordExtent(sourceTileCoord));
@@ -112,9 +120,10 @@ const VectorImageTile = function(tileCoord, state, sourceRevision, format,
if (getWidth(sharedExtent) / resolution >= 0.5 &&
getHeight(sharedExtent) / resolution >= 0.5) {
// only include source tile if overlap is at least 1 pixel
++loadCount;
const sourceTileKey = sourceTileCoord.toString();
let sourceTile = sourceTiles[sourceTileKey];
if (!sourceTile) {
if (!sourceTile && !useLoadedOnly) {
const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
@@ -123,10 +132,29 @@ const VectorImageTile = function(tileCoord, state, sourceRevision, format,
this.sourceTileListenerKeys_.push(
listen(sourceTile, EventType.CHANGE, handleTileChange));
}
sourceTile.consumers++;
this.tileKeys.push(sourceTileKey);
if (sourceTile && (!useLoadedOnly || sourceTile.getState() == TileState.LOADED)) {
sourceTile.consumers++;
this.tileKeys.push(sourceTileKey);
}
}
}.bind(this));
if (useLoadedOnly && loadCount == this.tileKeys.length) {
this.finishLoading_();
}
if (zoom <= tileCoord[0] && this.state != TileState.LOADED) {
while (zoom > tileGrid.getMinZoom()) {
const tile = new VectorImageTile(tileCoord, state, sourceRevision,
format, tileLoadFunction, urlTileCoord, tileUrlFunction,
sourceTileGrid, tileGrid, sourceTiles, pixelRatio, projection,
tileClass, UNDEFINED, --zoom);
if (tile.state == TileState.LOADED) {
this.interimTile = tile;
break;
}
}
}
}
};

View File

@@ -59,7 +59,7 @@ const VectorTile = function(tileCoord, state, src, format, tileLoadFunction, opt
* @private
* @type {module:ol/proj/Projection}
*/
this.projection_;
this.projection_ = null;
/**
* @private

View File

@@ -280,8 +280,7 @@ View.prototype.applyOptions_ = function(options) {
properties[ViewProperty.CENTER] = options.center !== undefined ?
options.center : null;
const resolutionConstraintInfo = createResolutionConstraint(
options);
const resolutionConstraintInfo = createResolutionConstraint(options);
/**
* @private
@@ -638,10 +637,8 @@ View.prototype.calculateCenterZoom = function(resolution, anchor) {
const currentCenter = this.getCenter();
const currentResolution = this.getResolution();
if (currentCenter !== undefined && currentResolution !== undefined) {
const x = anchor[0] -
resolution * (anchor[0] - currentCenter[0]) / currentResolution;
const y = anchor[1] -
resolution * (anchor[1] - currentCenter[1]) / currentResolution;
const x = anchor[0] - resolution * (anchor[0] - currentCenter[0]) / currentResolution;
const y = anchor[1] - resolution * (anchor[1] - currentCenter[1]) / currentResolution;
center = [x, y];
}
return center;
@@ -922,8 +919,7 @@ View.prototype.getValueForResolutionFunction = function(opt_power) {
* @return {number} Value.
*/
function(resolution) {
const value =
(Math.log(maxResolution / resolution) / Math.log(power)) / max;
const value = (Math.log(maxResolution / resolution) / Math.log(power)) / max;
return value;
});
};

View File

@@ -8,8 +8,9 @@ import {toString} from './color.js';
* A type accepted by CanvasRenderingContext2D.fillStyle
* or CanvasRenderingContext2D.strokeStyle.
* Represents a color, pattern, or gradient. The origin for patterns and
* gradients as fill style is the top-left corner of the extent of the geometry
* being filled.
* gradients as fill style is an increment of 512 css pixels from map coordinate
* `[0, 0]`. For seamless repeat patterns, width and height of the pattern image
* must be a factor of two (2, 4, 8, ..., 512).
*
* @typedef {string|CanvasPattern|CanvasGradient} ColorLike
* @api

View File

@@ -38,8 +38,8 @@ const MIN_RATIO = 0.1;
/**
* @typedef {Object} Options
* @property {boolean} [collapsed=true] Whether the control should start collapsed
* or not (expanded).
* @property {string} [className='ol-overviewmap'] CSS class name.
* @property {boolean} [collapsed=true] Whether the control should start collapsed or not (expanded).
* @property {string|Element} [collapseLabel='«'] Text label to use for the
* expanded overviewmap button. Instead of text, also an element (e.g. a `span` element) can be used.
* @property {boolean} [collapsible=true] Whether the control can be collapsed or not.
@@ -151,9 +151,9 @@ const OverviewMap = function(opt_options) {
/**
* @param {module:ol/layer/Layer} layer Layer.
*/
function(layer) {
(function(layer) {
ovmap.addLayer(layer);
}.bind(this));
}).bind(this));
}
const box = document.createElement('DIV');

View File

@@ -36,6 +36,7 @@ import Zoom from './Zoom.js';
* Defaults options.
* @return {module:ol/Collection.<module:ol/control/Control>}
* Controls.
* @function module:ol/control.defaults
* @api
*/
export function defaults(opt_options) {

View File

@@ -66,7 +66,7 @@ inherits(GPX, XMLFeature);
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const NAMESPACE_URIS = [
null,

View File

@@ -232,11 +232,6 @@ function createStyleDefaults() {
zIndex: 0
});
/**
* @const
* @type {Array.<module:ol/style/Style>}
* @private
*/
DEFAULT_STYLE_ARRAY = [DEFAULT_STYLE];
}
@@ -329,7 +324,7 @@ const GX_NAMESPACE_URIS = [
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const NAMESPACE_URIS = [
null,

View File

@@ -38,7 +38,7 @@ inherits(OSMXML, XMLFeature);
/**
* @const
* @type {Array.<string>}
* @type {Array.<null>}
*/
const NAMESPACE_URIS = [null];

View File

@@ -20,7 +20,7 @@ inherits(OWS, XML);
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const NAMESPACE_URIS = [null, 'http://www.opengis.net/ows/1.1'];

View File

@@ -32,7 +32,7 @@ inherits(WMSCapabilities, XML);
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const NAMESPACE_URIS = [
null,

View File

@@ -33,7 +33,7 @@ inherits(WMTSCapabilities, XML);
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const NAMESPACE_URIS = [
null,
@@ -43,7 +43,7 @@ const NAMESPACE_URIS = [
/**
* @const
* @type {Array.<string>}
* @type {Array.<null|string>}
*/
const OWS_NAMESPACE_URIS = [
null,

View File

@@ -135,7 +135,7 @@ inherits(DragAndDrop, Interaction);
/**
* @param {Event} event Event.
* @param {DragEvent} event Event.
* @this {module:ol/interaction/DragAndDrop}
*/
function handleDrop(event) {
@@ -150,7 +150,7 @@ function handleDrop(event) {
/**
* @param {Event} event Event.
* @param {DragEvent} event Event.
*/
function handleStop(event) {
event.stopPropagation();

View File

@@ -43,12 +43,14 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
* @property {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction} [style] Layer style. See
* {@link module:ol/style} for default style which will be used if this is not defined.
* @property {number} [maxTilesLoading=16] Maximum number tiles to load simultaneously.
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will be
* recreated during animations. This means that no vectors will be shown clipped, but the setting
* will have a performance impact for large amounts of vector data. When set to `false`, batches
* will be recreated when no animation is active.
* @property {boolean} [updateWhileInteracting=false] When set to `true`, feature batches will be
* recreated during interactions. See also `updateWhileAnimating`.
* @property {boolean} [updateWhileAnimating=false] When set to `true` and `renderMode`
* is `vector`, feature batches will be recreated during animations. This means that no
* vectors will be shown clipped, but the setting will have a performance impact for large
* amounts of vector data. When set to `false`, batches will be recreated when no animation
* is active.
* @property {boolean} [updateWhileInteracting=false] When set to `true` and `renderMode`
* is `vector`, feature batches will be recreated during interactions. See also
* `updateWhileAnimating`.
*/

View File

@@ -117,8 +117,7 @@ MouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {
// simulated mouse events will be swallowed near a primary touchend
const dx = Math.abs(x - t[0]);
const dy = Math.abs(y - t[1]);
if (dx <= DEDUP_DIST &&
dy <= DEDUP_DIST) {
if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
return true;
}
}

View File

@@ -177,8 +177,7 @@ MsSource.prototype.msPointerCancel = function(inEvent) {
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msLostPointerCapture = function(inEvent) {
const e = this.dispatcher.makeEvent('lostpointercapture',
inEvent, inEvent);
const e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
};
@@ -189,8 +188,7 @@ MsSource.prototype.msLostPointerCapture = function(inEvent) {
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msGotPointerCapture = function(inEvent) {
const e = this.dispatcher.makeEvent('gotpointercapture',
inEvent, inEvent);
const e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
};
export default MsSource;

View File

@@ -172,9 +172,8 @@ PointerEventHandler.prototype.registerSource = function(name, source) {
*/
PointerEventHandler.prototype.register_ = function() {
const l = this.eventSourceList_.length;
let eventSource;
for (let i = 0; i < l; i++) {
eventSource = this.eventSourceList_[i];
const eventSource = this.eventSourceList_[i];
this.addEvents_(eventSource.getEvents());
}
};
@@ -186,9 +185,8 @@ PointerEventHandler.prototype.register_ = function() {
*/
PointerEventHandler.prototype.unregister_ = function() {
const l = this.eventSourceList_.length;
let eventSource;
for (let i = 0; i < l; i++) {
eventSource = this.eventSourceList_[i];
const eventSource = this.eventSourceList_[i];
this.removeEvents_(eventSource.getEvents());
}
};

View File

@@ -122,8 +122,7 @@ TouchSource.prototype.isPrimaryTouch_ = function(inTouch) {
*/
TouchSource.prototype.setPrimaryTouch_ = function(inTouch) {
const count = Object.keys(this.pointerMap).length;
if (count === 0 || (count === 1 &&
POINTER_ID.toString() in this.pointerMap)) {
if (count === 0 || (count === 1 && POINTER_ID.toString() in this.pointerMap)) {
this.firstTouchId_ = inTouch.identifier;
this.cancelResetClickCount_();
}
@@ -213,15 +212,13 @@ TouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {
* @param {function(Event, Object)} inFunction In function.
*/
TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {
const touches = Array.prototype.slice.call(
inEvent.changedTouches);
const touches = Array.prototype.slice.call(inEvent.changedTouches);
const count = touches.length;
function preventDefault() {
inEvent.preventDefault();
}
let i, pointer;
for (i = 0; i < count; ++i) {
pointer = this.touchToPointer_(inEvent, touches[i]);
for (let i = 0; i < count; ++i) {
const pointer = this.touchToPointer_(inEvent, touches[i]);
// forward touch preventDefaults
pointer.preventDefault = preventDefault;
inFunction.call(this, inEvent, pointer);
@@ -237,9 +234,8 @@ TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {
*/
TouchSource.prototype.findTouch_ = function(touchList, searchId) {
const l = touchList.length;
let touch;
for (let i = 0; i < l; i++) {
touch = touchList[i];
const touch = touchList[i];
if (touch.identifier === searchId) {
return true;
}
@@ -267,19 +263,17 @@ TouchSource.prototype.vacuumTouches_ = function(inEvent) {
const count = keys.length;
if (count >= touchList.length) {
const d = [];
let i, key, value;
for (i = 0; i < count; ++i) {
key = keys[i];
value = this.pointerMap[key];
for (let i = 0; i < count; ++i) {
const key = keys[i];
const value = this.pointerMap[key];
// Never remove pointerId == 1, which is mouse.
// Touch identifiers are 2 smaller than their pointerId, which is the
// index in pointermap.
if (key != POINTER_ID &&
!this.findTouch_(touchList, key - 2)) {
if (key != POINTER_ID && !this.findTouch_(touchList, key - 2)) {
d.push(value.out);
}
}
for (i = 0; i < d.length; ++i) {
for (let i = 0; i < d.length; ++i) {
this.cancelOut_(inEvent, d[i]);
}
}

View File

@@ -83,12 +83,6 @@ import {add as addTransformFunc, clear as clearTransformFuncs, get as getTransfo
*/
/**
* Meters per unit lookup table.
* @const
* @type {Object.<module:ol/proj/Units, number>}
* @api
*/
export {METERS_PER_UNIT};
@@ -317,12 +311,11 @@ export function createTransformFromCoordinateTransform(coordTransform) {
const length = input.length;
const dimension = opt_dimension !== undefined ? opt_dimension : 2;
const output = opt_output !== undefined ? opt_output : new Array(length);
let point, i, j;
for (i = 0; i < length; i += dimension) {
point = coordTransform([input[i], input[i + 1]]);
for (let i = 0; i < length; i += dimension) {
const point = coordTransform([input[i], input[i + 1]]);
output[i] = point[0];
output[i + 1] = point[1];
for (j = dimension - 1; j >= 2; --j) {
for (let j = dimension - 1; j >= 2; --j) {
output[i + j] = input[i + j];
}
}

View File

@@ -8,6 +8,7 @@ import GeometryType from '../geom/GeometryType.js';
import {linearRingss as linearRingssCenter} from '../geom/flat/center.js';
import {getInteriorPointOfArray, getInteriorPointsOfMultiArray} from '../geom/flat/interiorpoint.js';
import {interpolatePoint} from '../geom/flat/interpolate.js';
import {get as getProjection} from '../proj.js';
import {transform2D} from '../geom/flat/transform.js';
import {create as createTransform, compose as composeTransform} from '../transform.js';
@@ -264,6 +265,7 @@ RenderFeature.prototype.getType = function() {
* @param {module:ol/proj~ProjectionLike} destination The desired projection.
*/
RenderFeature.prototype.transform = function(source, destination) {
source = getProjection(source);
const pixelExtent = source.getExtent();
const projectedExtent = source.getWorldExtent();
const scale = getHeight(projectedExtent) / getHeight(pixelExtent);

View File

@@ -796,7 +796,7 @@ CanvasImmediateRenderer.prototype.setContextTextState_ = function(textState) {
contextTextState.font = context.font = textState.font;
}
if (contextTextState.textAlign != textAlign) {
contextTextState.textAlign = textAlign;
contextTextState.textAlign = context.textAlign = textAlign;
}
if (contextTextState.textBaseline != textState.textBaseline) {
contextTextState.textBaseline = context.textBaseline =

View File

@@ -87,9 +87,9 @@ const CanvasReplay = function(tolerance, maxExtent, resolution, pixelRatio, over
/**
* @private
* @type {module:ol/coordinate~Coordinate}
* @type {boolean}
*/
this.fillOrigin_;
this.alignFill_;
/**
* @private
@@ -191,7 +191,7 @@ CanvasReplay.prototype.replayTextBackground_ = function(context, p1, p2, p3, p4,
context.lineTo.apply(context, p4);
context.lineTo.apply(context, p1);
if (fillInstruction) {
this.fillOrigin_ = /** @type {Array.<number>} */ (fillInstruction[2]);
this.alignFill_ = /** @type {boolean} */ (fillInstruction[2]);
this.fill_(context);
}
if (strokeInstruction) {
@@ -455,13 +455,14 @@ CanvasReplay.prototype.beginGeometry = function(geometry, feature) {
* @param {CanvasRenderingContext2D} context Context.
*/
CanvasReplay.prototype.fill_ = function(context) {
if (this.fillOrigin_) {
const origin = applyTransform(this.renderedTransform_, this.fillOrigin_.slice());
context.translate(origin[0], origin[1]);
if (this.alignFill_) {
const origin = applyTransform(this.renderedTransform_, [0, 0]);
const repeatSize = 512 * this.pixelRatio;
context.translate(origin[0] % repeatSize, origin[1] % repeatSize);
context.rotate(this.viewRotation_);
}
context.fill();
if (this.fillOrigin_) {
if (this.alignFill_) {
context.setTransform.apply(context, resetTransform);
}
};
@@ -794,7 +795,7 @@ CanvasReplay.prototype.replay_ = function(
break;
case CanvasInstruction.SET_FILL_STYLE:
lastFillInstruction = instruction;
this.fillOrigin_ = instruction[2];
this.alignFill_ = instruction[2];
if (pendingFill) {
this.fill_(context);
@@ -965,8 +966,8 @@ CanvasReplay.prototype.createFill = function(state, geometry) {
const fillStyle = state.fillStyle;
const fillInstruction = [CanvasInstruction.SET_FILL_STYLE, fillStyle];
if (typeof fillStyle !== 'string') {
const fillExtent = geometry.getExtent();
fillInstruction.push([fillExtent[0], fillExtent[3]]);
// Fill is a pattern or gradient - align it!
fillInstruction.push(true);
}
return fillInstruction;
};

View File

@@ -7,7 +7,7 @@ import {createCanvasContext2D} from '../../dom.js';
import {intersects} from '../../extent.js';
import {matchingChunk} from '../../geom/flat/straightchunk.js';
import GeometryType from '../../geom/GeometryType.js';
import {CANVAS_LINE_DASH, SAFARI} from '../../has.js';
import {CANVAS_LINE_DASH} from '../../has.js';
import {labelCache, measureTextWidth, defaultTextAlign, measureTextHeight, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, checkFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
import CanvasInstruction from '../canvas/Instruction.js';
import CanvasReplay from '../canvas/Replay.js';
@@ -314,7 +314,7 @@ CanvasTextReplay.prototype.getImage = function(text, textKey, fillKey, strokeKey
context.font = textState.font;
if (strokeKey) {
context.strokeStyle = strokeState.strokeStyle;
context.lineWidth = strokeWidth * (SAFARI ? scale : 1);
context.lineWidth = strokeWidth;
context.lineCap = strokeState.lineCap;
context.lineJoin = strokeState.lineJoin;
context.miterLimit = strokeState.miterLimit;

View File

@@ -10,13 +10,14 @@ import {equals} from '../../array.js';
import {getHeight, getIntersection, getWidth, isEmpty} from '../../extent.js';
import VectorRenderType from '../../layer/VectorRenderType.js';
import {assign} from '../../obj.js';
import {layerRendererConstructors} from './Map.js';
import IntermediateCanvasRenderer from '../canvas/IntermediateCanvas.js';
import {create as createTransform, compose as composeTransform} from '../../transform.js';
/**
* @constructor
* @extends {module:ol/renderer/canvas/IntermediateCanvas}
* @param {module:ol/layer/Image} imageLayer Single image layer.
* @param {module:ol/layer/Image|module:ol/layer/Vector} imageLayer Image or vector layer.
* @api
*/
const CanvasImageLayerRenderer = function(imageLayer) {
@@ -46,6 +47,16 @@ const CanvasImageLayerRenderer = function(imageLayer) {
*/
this.vectorRenderer_ = null;
if (imageLayer.getType() === LayerType.VECTOR) {
for (let i = 0, ii = layerRendererConstructors.length; i < ii; ++i) {
const ctor = layerRendererConstructors[i];
if (ctor !== CanvasImageLayerRenderer && ctor['handles'](imageLayer)) {
this.vectorRenderer_ = new ctor(imageLayer);
break;
}
}
}
};
inherits(CanvasImageLayerRenderer, IntermediateCanvasRenderer);
@@ -70,18 +81,7 @@ CanvasImageLayerRenderer['handles'] = function(layer) {
* @return {module:ol/renderer/canvas/ImageLayer} The layer renderer.
*/
CanvasImageLayerRenderer['create'] = function(mapRenderer, layer) {
const renderer = new CanvasImageLayerRenderer(/** @type {module:ol/layer/Image} */ (layer));
if (layer.getType() === LayerType.VECTOR) {
const candidates = mapRenderer.getLayerRendererConstructors();
for (let i = 0, ii = candidates.length; i < ii; ++i) {
const candidate = /** @type {Object.<string, Function>} */ (candidates[i]);
if (candidate !== CanvasImageLayerRenderer && candidate['handles'](layer)) {
renderer.setVectorRenderer(candidate['create'](mapRenderer, layer));
break;
}
}
}
return renderer;
return new CanvasImageLayerRenderer(/** @type {module:ol/layer/Image} */ (layer));
};
@@ -129,8 +129,9 @@ CanvasImageLayerRenderer.prototype.prepareFrame = function(frameState, layerStat
const hints = frameState.viewHints;
const vectorRenderer = this.vectorRenderer_;
let renderedExtent = frameState.extent;
if (layerState.extent !== undefined) {
if (!vectorRenderer && layerState.extent !== undefined) {
renderedExtent = getIntersection(renderedExtent, layerState.extent);
}
@@ -143,7 +144,7 @@ CanvasImageLayerRenderer.prototype.prepareFrame = function(frameState, layerStat
projection = sourceProjection;
}
}
const vectorRenderer = this.vectorRenderer_;
let skippedFeatures = this.skippedFeatures_;
if (vectorRenderer) {
const context = vectorRenderer.context;
const imageFrameState = /** @type {module:ol/PluggableMap~FrameState} */ (assign({}, frameState, {
@@ -155,25 +156,25 @@ CanvasImageLayerRenderer.prototype.prepareFrame = function(frameState, layerStat
rotation: 0
}))
}));
const skippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort();
if (vectorRenderer.prepareFrame(imageFrameState, layerState) &&
(vectorRenderer.replayGroupChanged ||
!equals(skippedFeatures, this.skippedFeatures_))) {
context.canvas.width = imageFrameState.size[0] * pixelRatio;
context.canvas.height = imageFrameState.size[1] * pixelRatio;
vectorRenderer.composeFrame(imageFrameState, layerState, context);
this.image_ = new ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas);
this.skippedFeatures_ = skippedFeatures;
}
const newSkippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort();
image = new ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas, function(callback) {
if (vectorRenderer.prepareFrame(imageFrameState, layerState) &&
(vectorRenderer.replayGroupChanged ||
!equals(skippedFeatures, newSkippedFeatures))) {
context.canvas.width = imageFrameState.size[0] * pixelRatio;
context.canvas.height = imageFrameState.size[1] * pixelRatio;
vectorRenderer.compose(context, imageFrameState, layerState);
skippedFeatures = newSkippedFeatures;
callback();
}
});
} else {
image = imageSource.getImage(
renderedExtent, viewResolution, pixelRatio, projection);
if (image) {
const loaded = this.loadImage(image);
if (loaded) {
this.image_ = image;
}
}
}
if (image && this.loadImage(image)) {
this.image_ = image;
this.skippedFeatures_ = skippedFeatures;
}
}
@@ -215,13 +216,4 @@ CanvasImageLayerRenderer.prototype.forEachFeatureAtCoordinate = function(coordin
};
/**
* @param {module:ol/renderer/canvas/VectorLayer} renderer Vector renderer.
*/
CanvasImageLayerRenderer.prototype.setVectorRenderer = function(renderer) {
if (this.vectorRenderer_) {
this.vectorRenderer_.dispose();
}
this.vectorRenderer_ = renderer;
};
export default CanvasImageLayerRenderer;

View File

@@ -3,7 +3,7 @@
*/
import {create as createTransform, apply as applyTransform, compose as composeTransform} from '../../transform.js';
import {inherits} from '../../index.js';
import {stableSort} from '../../array.js';
import {includes, stableSort} from '../../array.js';
import {CLASS_UNSELECTABLE} from '../../css.js';
import {createCanvasContext2D} from '../../dom.js';
import {visibleAtResolution} from '../../layer/Layer.js';
@@ -14,6 +14,13 @@ import CanvasImmediateRenderer from '../../render/canvas/Immediate.js';
import MapRenderer, {sortByZIndex} from '../Map.js';
import SourceState from '../../source/State.js';
/**
* @type {Array.<module:ol/renderer/Layer>}
*/
export const layerRendererConstructors = [];
/**
* @constructor
* @extends {module:ol/renderer/Map}
@@ -202,4 +209,19 @@ CanvasMapRenderer.prototype.forEachLayerAtPixel = function(pixel, frameState, ca
}
return undefined;
};
/**
* @inheritDoc
*/
CanvasMapRenderer.prototype.registerLayerRenderers = function(constructors) {
MapRenderer.prototype.registerLayerRenderers.call(this, constructors);
for (let i = 0, ii = constructors.length; i < ii; ++i) {
const ctor = constructors[i];
if (!includes(layerRendererConstructors, ctor)) {
layerRendererConstructors.push(ctor);
}
}
};
export default CanvasMapRenderer;

View File

@@ -51,6 +51,12 @@ const CanvasTileLayerRenderer = function(tileLayer) {
*/
this.renderedTiles = [];
/**
* @private
* @type {boolean}
*/
this.newTiles_ = false;
/**
* @protected
* @type {module:ol/extent~Extent}
@@ -114,6 +120,34 @@ CanvasTileLayerRenderer.prototype.isDrawableTile_ = function(tile) {
tileState == TileState.ERROR && !useInterimTilesOnError;
};
/**
* @param {number} z Tile coordinate z.
* @param {number} x Tile coordinate x.
* @param {number} y Tile coordinate y.
* @param {number} pixelRatio Pixel ratio.
* @param {module:ol/proj/Projection} projection Projection.
* @return {!module:ol/Tile} Tile.
*/
CanvasTileLayerRenderer.prototype.getTile = function(z, x, y, pixelRatio, projection) {
const layer = this.getLayer();
const source = /** @type {module:ol/source/Tile} */ (layer.getSource());
let tile = source.getTile(z, x, y, pixelRatio, projection);
if (tile.getState() == TileState.ERROR) {
if (!layer.getUseInterimTilesOnError()) {
// When useInterimTilesOnError is false, we consider the error tile as loaded.
tile.setState(TileState.LOADED);
} else if (layer.getPreload() > 0) {
// Preloaded tiles for lower resolutions might have finished loading.
this.newTiles_ = true;
}
}
if (!this.isDrawableTile_(tile)) {
tile = tile.getInterimTile();
}
return tile;
};
/**
* @inheritDoc
*/
@@ -157,32 +191,26 @@ CanvasTileLayerRenderer.prototype.prepareFrame = function(frameState, layerState
const findLoadedTiles = this.createLoadedTileFinder(
tileSource, projection, tilesToDrawByZ);
const hints = frameState.viewHints;
const animatingOrInteracting = hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING];
const tmpExtent = this.tmpExtent;
const tmpTileRange = this.tmpTileRange_;
let newTiles = false;
this.newTiles_ = false;
let tile, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tile = tileSource.getTile(z, x, y, pixelRatio, projection);
if (tile.getState() == TileState.ERROR) {
if (!tileLayer.getUseInterimTilesOnError()) {
// When useInterimTilesOnError is false, we consider the error tile as loaded.
tile.setState(TileState.LOADED);
} else if (tileLayer.getPreload() > 0) {
// Preloaded tiles for lower resolutions might have finished loading.
newTiles = true;
}
}
if (!this.isDrawableTile_(tile)) {
tile = tile.getInterimTile();
if (Date.now() - frameState.time > 16 && animatingOrInteracting) {
continue;
}
tile = this.getTile(z, x, y, pixelRatio, projection);
if (this.isDrawableTile_(tile)) {
const uid = getUid(this);
if (tile.getState() == TileState.LOADED) {
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
const inTransition = tile.inTransition(uid);
if (!newTiles && (inTransition || this.renderedTiles.indexOf(tile) === -1)) {
newTiles = true;
if (!this.newTiles_ && (inTransition || this.renderedTiles.indexOf(tile) === -1)) {
this.newTiles_ = true;
}
}
if (tile.getAlpha(uid, frameState.time) === 1) {
@@ -206,10 +234,8 @@ CanvasTileLayerRenderer.prototype.prepareFrame = function(frameState, layerState
}
const renderedResolution = tileResolution * pixelRatio / tilePixelRatio * oversampling;
const hints = frameState.viewHints;
const animatingOrInteracting = hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING];
if (!(this.renderedResolution && Date.now() - frameState.time > 16 && animatingOrInteracting) && (
newTiles ||
this.newTiles_ ||
!(this.renderedExtent_ && containsExtent(this.renderedExtent_, extent)) ||
this.renderedRevision != sourceRevision ||
oversampling != this.oversampling_ ||

View File

@@ -116,10 +116,11 @@ CanvasVectorLayerRenderer.prototype.disposeInternal = function() {
/**
* @inheritDoc
* @param {CanvasRenderingContext2D} context Context.
* @param {module:ol/PluggableMap~FrameState} frameState Frame state.
* @param {module:ol/layer/Layer~State} layerState Layer state.
*/
CanvasVectorLayerRenderer.prototype.composeFrame = function(frameState, layerState, context) {
CanvasVectorLayerRenderer.prototype.compose = function(context, frameState, layerState) {
const extent = frameState.extent;
const pixelRatio = frameState.pixelRatio;
const skippedFeatureUids = layerState.managed ?
@@ -132,8 +133,6 @@ CanvasVectorLayerRenderer.prototype.composeFrame = function(frameState, layerSta
let transform = this.getTransform(frameState, 0);
this.preCompose(context, frameState, transform);
// clipped rendering if layer extent is set
const clipExtent = layerState.extent;
const clipped = clipExtent !== undefined;
@@ -207,8 +206,6 @@ CanvasVectorLayerRenderer.prototype.composeFrame = function(frameState, layerSta
replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids);
startX -= worldWidth;
}
// restore original transform for render and compose events
transform = this.getTransform(frameState, 0);
}
rotateAtOffset(replayContext, rotation,
width / 2, height / 2);
@@ -236,8 +233,17 @@ CanvasVectorLayerRenderer.prototype.composeFrame = function(frameState, layerSta
if (clipped) {
context.restore();
}
this.postCompose(context, frameState, layerState, transform);
};
/**
* @inheritDoc
*/
CanvasVectorLayerRenderer.prototype.composeFrame = function(frameState, layerState, context) {
const transform = this.getTransform(frameState, 0);
this.preCompose(context, frameState, transform);
this.compose(context, frameState, layerState);
this.postCompose(context, frameState, layerState, transform);
};

View File

@@ -126,6 +126,21 @@ CanvasVectorTileLayerRenderer.prototype.disposeInternal = function() {
};
/**
* @inheritDoc
*/
CanvasVectorTileLayerRenderer.prototype.getTile = function(z, x, y, pixelRatio, projection) {
const tile = CanvasTileLayerRenderer.prototype.getTile.call(this, z, x, y, pixelRatio, projection);
if (tile.getState() === TileState.LOADED) {
this.createReplayGroup_(tile, pixelRatio, projection);
if (this.context) {
this.renderTileImage_(tile, pixelRatio, projection);
}
}
return tile;
};
/**
* @inheritDoc
*/
@@ -149,13 +164,12 @@ CanvasVectorTileLayerRenderer.prototype.prepareFrame = function(frameState, laye
/**
* @param {module:ol/VectorImageTile} tile Tile.
* @param {module:ol/PluggableMap~FrameState} frameState Frame state.
* @param {number} pixelRatio Pixel ratio.
* @param {module:ol/proj/Projection} projection Projection.
* @private
*/
CanvasVectorTileLayerRenderer.prototype.createReplayGroup_ = function(tile, frameState) {
CanvasVectorTileLayerRenderer.prototype.createReplayGroup_ = function(tile, pixelRatio, projection) {
const layer = this.getLayer();
const pixelRatio = frameState.pixelRatio;
const projection = frameState.viewState.projection;
const revision = layer.getRevision();
const renderOrder = /** @type {module:ol/render~OrderFunction} */ (layer.getRenderOrder()) || null;
@@ -169,7 +183,7 @@ CanvasVectorTileLayerRenderer.prototype.createReplayGroup_ = function(tile, fram
const sourceTileGrid = source.getTileGrid();
const tileGrid = source.getTileGridForProjection(projection);
const resolution = tileGrid.getResolution(tile.tileCoord[0]);
const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
const tileExtent = tile.extent;
const zIndexKeys = {};
for (let t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
@@ -241,20 +255,6 @@ CanvasVectorTileLayerRenderer.prototype.createReplayGroup_ = function(tile, fram
};
/**
* @inheritDoc
*/
CanvasVectorTileLayerRenderer.prototype.drawTileImage = function(
tile, frameState, layerState, x, y, w, h, gutter, transition) {
const vectorImageTile = /** @type {module:ol/VectorImageTile} */ (tile);
this.createReplayGroup_(vectorImageTile, frameState);
if (this.context) {
this.renderTileImage_(vectorImageTile, frameState, layerState);
CanvasTileLayerRenderer.prototype.drawTileImage.apply(this, arguments);
}
};
/**
* @inheritDoc
*/
@@ -269,16 +269,11 @@ CanvasVectorTileLayerRenderer.prototype.forEachFeatureAtCoordinate = function(co
/** @type {Array.<module:ol/VectorImageTile>} */
const renderedTiles = this.renderedTiles;
const source = /** @type {module:ol/source/VectorTile} */ (layer.getSource());
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
let bufferedExtent, found;
let i, ii, replayGroup;
let tile, tileCoord, tileExtent;
for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
tile = renderedTiles[i];
tileCoord = tile.wrappedTileCoord;
tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
bufferedExtent = buffer(tileExtent, hitTolerance * resolution, bufferedExtent);
const tile = renderedTiles[i];
bufferedExtent = buffer(tile.extent, hitTolerance * resolution, bufferedExtent);
if (!containsCoordinate(bufferedExtent, coordinate)) {
continue;
}
@@ -388,8 +383,7 @@ CanvasVectorTileLayerRenderer.prototype.postCompose = function(context, frameSta
continue;
}
const tileCoord = tile.tileCoord;
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] -
tileGrid.getTileCoordExtent(tile.wrappedTileCoord, this.tmpExtent)[0];
const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent)[0] - tile.extent[0];
let transform = undefined;
for (let t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
const sourceTile = tile.getTile(tile.tileKeys[t]);
@@ -472,12 +466,12 @@ CanvasVectorTileLayerRenderer.prototype.renderFeature = function(feature, square
/**
* @param {module:ol/VectorImageTile} tile Tile.
* @param {module:ol/PluggableMap~FrameState} frameState Frame state.
* @param {module:ol/layer/Layer~State} layerState Layer state.
* @param {number} pixelRatio Pixel ratio.
* @param {module:ol/proj/Projection} projection Projection.
* @private
*/
CanvasVectorTileLayerRenderer.prototype.renderTileImage_ = function(
tile, frameState, layerState) {
tile, pixelRatio, projection) {
const layer = this.getLayer();
const replayState = tile.getReplayState(layer);
const revision = layer.getRevision();
@@ -486,12 +480,11 @@ CanvasVectorTileLayerRenderer.prototype.renderTileImage_ = function(
replayState.renderedTileRevision = revision;
const tileCoord = tile.wrappedTileCoord;
const z = tileCoord[0];
const pixelRatio = frameState.pixelRatio;
const source = /** @type {module:ol/source/VectorTile} */ (layer.getSource());
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
const tileGrid = source.getTileGridForProjection(projection);
const resolution = tileGrid.getResolution(z);
const context = tile.getContext(layer);
const size = source.getTilePixelSize(z, pixelRatio, frameState.viewState.projection);
const size = source.getTilePixelSize(z, pixelRatio, projection);
context.canvas.width = size[0];
context.canvas.height = size[1];
const tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
@@ -509,4 +502,5 @@ CanvasVectorTileLayerRenderer.prototype.renderTileImage_ = function(
}
}
};
export default CanvasVectorTileLayerRenderer;

View File

@@ -130,14 +130,14 @@ const WebGLMapRenderer = function(map) {
* @return {number} Priority.
* @this {module:ol/renderer/webgl/Map}
*/
function(element) {
(function(element) {
const tileCenter = /** @type {module:ol/coordinate~Coordinate} */ (element[1]);
const tileResolution = /** @type {number} */ (element[2]);
const deltaX = tileCenter[0] - this.focus_[0];
const deltaY = tileCenter[1] - this.focus_[1];
return 65536 * Math.log(tileResolution) +
Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
}.bind(this),
}).bind(this),
/**
* @param {Array.<*>} element Element.
* @return {string} Key.

View File

@@ -13,6 +13,10 @@ import {appendParams} from '../uri.js';
/**
* @typedef {Object} Options
* @property {string} [url] The mapagent url.
* @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that
* you must provide a `crossOrigin` value if you are using the WebGL renderer or if you want to
* access pixel data with the Canvas renderer. See
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image} for more detail.
* @property {number} [displayDpi=96] The display resolution.
* @property {number} [metersPerUnit=1] The meters-per-unit value.
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting

View File

@@ -10,6 +10,8 @@ import Event from '../events/Event.js';
import EventType from '../events/EventType.js';
import {Processor} from 'pixelworks/lib/index';
import {equals, getCenter, getHeight, getWidth} from '../extent.js';
import LayerType from '../LayerType.js';
import Layer from '../layer/Layer.js';
import ImageLayer from '../layer/Image.js';
import TileLayer from '../layer/Tile.js';
import {assign} from '../obj.js';
@@ -111,7 +113,8 @@ inherits(RasterSourceEvent, Event);
/**
* @typedef {Object} Options
* @property {Array.<module:ol/source/Source>} sources Input sources.
* @property {Array.<module:ol/source/Source|module:ol/layer/Layer>} sources Input
* sources or layers. Vector layers must be configured with `renderMode: 'image'`.
* @property {module:ol/source/Raster~Operation} [operation] Raster operation.
* The operation will be called with data from input sources
* and the output will be assigned to the raster source.
@@ -487,6 +490,11 @@ function createRenderer(source) {
renderer = createTileRenderer(source);
} else if (source instanceof ImageSource) {
renderer = createImageRenderer(source);
} else if (source instanceof TileLayer) {
renderer = new CanvasTileLayerRenderer(source);
} else if (source instanceof Layer &&
(source.getType() == LayerType.IMAGE || source.getType() == LayerType.VECTOR)) {
renderer = new CanvasImageLayerRenderer(source);
}
return renderer;
}

View File

@@ -31,24 +31,26 @@ import {createXYZ, extentFromProjection, createForProjection} from '../tilegrid.
* tile.setLoader(function() {
* var data = // ... fetch data
* var format = tile.getFormat();
* tile.setProjection(format.readProjection(data));
* tile.setFeatures(format.readFeatures(data, {
* // uncomment the line below for ol/format/MVT only
* extent: tile.getExtent(),
* // featureProjection is not required for ol/format/MVT
* featureProjection: map.getView().getProjection()
* }));
* // the line below is only required for ol/format/MVT
* tile.setExtent(format.getLastExtent());
* };
* });
* @property {module:ol/Tile~UrlFunction} [tileUrlFunction] Optional function to get tile URL given a tile coordinate and the projection.
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
* used instead of defining each one separately in the `urls` option.
* @property {number} [transition] A duration for tile opacity
* transitions in milliseconds. A duration of 0 disables the opacity transition.
* @property {Array.<string>} [urls] An array of URL templates.
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* When set to `false`, only one world
* will be rendered. When set to `true`, tiles will be wrapped horizontally to
* render multiple worlds.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
*/
@@ -168,8 +170,7 @@ VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projection) {
this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction,
this.tileGrid, this.getTileGridForProjection(projection),
this.sourceTiles_, pixelRatio, projection, this.tileClass,
this.handleTileChange.bind(this),
this.tileOptions);
this.handleTileChange.bind(this), tileCoord[0]);
this.tileCache.set(tileCoordKey, tile);
return tile;

View File

@@ -18,7 +18,7 @@ import {createXYZ, extentFromProjection} from '../tilegrid.js';
* @property {boolean} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).
* Higher values can increase reprojection performance, but decrease precision.
* @property {number} [maxZoom=18] Optional max zoom level.
* @property {number} [maxZoom=0] Optional min zoom level.
* @property {number} [minZoom=0] Optional min zoom level.
* @property {module:ol/tilegrid/TileGrid} [tileGrid] Tile grid.
* @property {module:ol/Tile~LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is
* ```js

View File

@@ -195,8 +195,7 @@ AtlasManager.prototype.add = function(id, width, height,
}
/** @type {?module:ol/style/Atlas~AtlasInfo} */
const info = this.add_(false,
id, width, height, renderCallback, opt_this);
const info = this.add_(false, id, width, height, renderCallback, opt_this);
if (!info) {
return null;
}
@@ -227,8 +226,7 @@ AtlasManager.prototype.add = function(id, width, height,
* @return {?module:ol/style/Atlas~AtlasInfo} The position and atlas image for the entry,
* or `null` if the image is too big.
*/
AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height,
renderCallback, opt_this) {
AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height, renderCallback, opt_this) {
const atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_;
let atlas, info, i, ii;
for (i = 0, ii = atlases.length; i < ii; ++i) {

View File

@@ -335,10 +335,8 @@ export function makeSimpleNodeFactory(opt_nodeName, opt_namespaceURI) {
if (nodeName === undefined) {
nodeName = opt_nodeName;
}
let namespaceURI = opt_namespaceURI;
if (opt_namespaceURI === undefined) {
namespaceURI = node.namespaceURI;
}
const namespaceURI = opt_namespaceURI !== undefined ? opt_namespaceURI : node.namespaceURI;
return createElementNS(namespaceURI, /** @type {string} */ (nodeName));
}
);

View File

@@ -99,9 +99,6 @@ function parseOutput(output) {
if (!Array.isArray(info.symbols)) {
throw new Error('Expected symbols array: ' + output);
}
if (!Array.isArray(info.defines)) {
throw new Error('Expected defines array: ' + output);
}
return info;
}

31
tasks/transform-types.js Normal file
View File

@@ -0,0 +1,31 @@
/**
* @filedesc
* Transforms type comments in all source files to types that Closure Compiler
* understands.
*/
const glob = require('glob');
const mkdirp = require('mkdirp').sync;
const fs = require('fs');
const path = require('path');
const transform = require('babel-core').transformFileSync;
const options = {
plugins: 'jsdoc-closure',
parserOpts: {
parser: 'recast'
},
generatorOpts: {
generator: 'recast'
}
};
const outDir = path.join('build', 'src-closure');
glob('src/**/*.js', (err, matches) => {
matches.forEach(match => {
const out = path.join(outDir, path.relative('src', match));
mkdirp(path.dirname(out));
fs.writeFileSync(out, transform(match, options).code, 'utf-8');
});
});

View File

@@ -3,6 +3,7 @@ const Compiler = require('google-closure-compiler').compiler;
const compiler = new Compiler({
js: [
'./build/src-closure/**.js',
// Resolve dependencies
'./node_modules/pbf/package.json', './node_modules/pbf/**.js', './node_modules/ieee754/**.js',
'./node_modules/pixelworks/package.json', './node_modules/pixelworks/**.js',
'./node_modules/rbush/package.json', './node_modules/rbush/**.js', 'node_modules/quickselect/**.js'
@@ -10,11 +11,10 @@ const compiler = new Compiler({
entry_point: './build/src-closure/index.js',
module_resolution: 'NODE',
dependency_mode: 'STRICT',
process_common_js_modules: true,
checks_only: true,
//FIXME Change newCheckTypes to jscomp_error when we have path types everywhere
jscomp_warning: ['newCheckTypes'],
jscomp_error: ['newCheckTypes'],
// Options to make dependencies work
process_common_js_modules: true,
hide_warnings_for: 'node_modules'
});

View File

@@ -1,58 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>OL Spec Runner</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="../node_modules/mocha/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script type="text/javascript" src="../node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="../node_modules/expect.js/index.js"></script>
<script type="text/javascript" src="../node_modules/sinon/pkg/sinon.js"></script>
<script type="text/javascript" src="../node_modules/mocha/mocha.js"></script>
<script type="text/javascript" src="../node_modules/proj4/dist/proj4.js"></script>
<script type="text/javascript" src="test-extensions.js"></script>
<!-- load polyfills: Always load the URL polyfill in a gated form so that
MS Edge has it -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL|always|gated"></script>
<script>
if (typeof initMochaPhantomJS === 'function') {
initMochaPhantomJS()
}
mocha.setup({
ui: 'bdd',
bail: false
});
</script>
<!-- This script is provided by the debug server (started with `make serve`) -->
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
var runner = mocha.run();
if (window.console && console.log) {
// write stacks to the console for failed tests
runner.on('fail', function(test, err) {
if (test.duration > test._timeout) {
var titles = [];
for (var p = test; p; p = p.parent) {
if (p.title) {
titles.unshift(p.title);
}
}
console.log('Test timed out:', titles.join(' > '));
}
console.error(test.err.stack);
});
}
</script>
<!--
Tests should not depend on any specific markup and should instead create
whatever elements are needed (cleaning up when done).
-->
</body>
</html>

5
test/index_test.js Normal file
View File

@@ -0,0 +1,5 @@
// require all modules ending in ".test.js" from the
// current directory and all subdirectories
const testsContext = require.context('.', true, /\.test\.js$/);
testsContext.keys().forEach(testsContext);

Some files were not shown because too many files have changed in this diff Show More