Compare commits

..

4 Commits

Author SHA1 Message Date
Tim Schaub
cb63b398d3 Merge pull request #9255 from openlayers/release-v5.3.1
Updates for 5.3.1
2019-02-21 13:16:41 -07:00
Tim Schaub
ce89a82e6a Updates for 5.3.1 2019-02-21 13:07:15 -07:00
Tim Schaub
1c269d6e0b Merge pull request #9253 from romanzoller/hotfix-PR-8893
Add proj.js to the sideEffects list
2019-02-21 13:02:24 -07:00
Frederic Junod
83b8fe4b33 Add proj.js to the sideEffects list 2019-02-21 17:10:20 +01:00
566 changed files with 18618 additions and 91552 deletions

View File

@@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- image: circleci/node:latest-browsers
- image: circleci/node:10-browsers
working_directory: ~/repo
@@ -14,7 +14,7 @@ jobs:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-
- run:
- run:
name: Install Dependencies
command: npm install
@@ -22,16 +22,12 @@ jobs:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
- run:
- run:
name: Run Tests
command: npm test
- store_artifacts:
path: rendering/cases/
destination: rendering
- run:
- run:
name: Build Examples
command: npm run build-examples

View File

@@ -11,3 +11,7 @@ insert_final_newline = true
[*.md]
indent_size = 2
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
indent_size = 4

9
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,9 @@
<!--
Thank you for your interest in making OpenLayers better!
If you are reporting a bug, please link to an example that reproduces the problem. This will make it easier for people who may want to help you debug.
If you have a usage question, you might want to try Stack Overflow first: https://stackoverflow.com/questions/tagged/openlayers
Thanks
-->

View File

@@ -1,19 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
labels:
- bug
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.

View File

@@ -1,13 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
labels:
- feature request
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.

View File

@@ -42,7 +42,7 @@ Your pull request must:
* Follow OpenLayers's coding style.
* Pass the integration tests run automatically by the CircleCI Continuous
* Pass the integration tests run automatically by the Travis Continuous
Integration system.
* Address a single issue or add a single item of functionality.

View File

@@ -5,9 +5,9 @@
You will obviously start by
[forking](https://github.com/openlayers/openlayers/fork) the OpenLayers repository.
### CircleCI
### Travis CI
The CircleCI hook is enabled on the Github repository. This means every pull request
The Travis CI hook is enabled on the Github repository. This means every pull request
is run through a full test suite to ensure it compiles and passes the tests. Failing
pull requests will not be merged.

13
Makefile Normal file
View File

@@ -0,0 +1,13 @@
SRC_GLSL := $(shell find src -type f -name '*.glsl')
SRC_SHADER_JS := $(patsubst %shader.glsl,%shader.js,$(SRC_GLSL))
SRC_SHADERLOCATIONS_JS := $(patsubst %shader.glsl,%shader/Locations.js,$(SRC_GLSL))
.PHONY: shaders
shaders: $(SRC_SHADER_JS) $(SRC_SHADERLOCATIONS_JS)
%shader.js: %shader.glsl src/ol/webgl/shader.mustache tasks/glslunit.js
@node tasks/glslunit.js --input $< | ./node_modules/.bin/mustache - src/ol/webgl/shader.mustache > $@
%shader/Locations.js: %shader.glsl src/ol/webgl/shaderlocations.mustache tasks/glslunit.js
@mkdir -p $(@D)
@node tasks/glslunit.js --input $< | ./node_modules/.bin/mustache - src/ol/webgl/shaderlocations.mustache > $@

View File

@@ -41,28 +41,6 @@ See the following examples for more detail on bundling OpenLayers with your appl
* Using [Parcel](https://github.com/openlayers/ol-parcel)
* Using [Browserify](https://github.com/openlayers/ol-browserify)
## TypeScript and VS Code IntelliSense support
The `ol` package contains a `src/` folder with JSDoc annotated sources. TypeScript can get type definitions from these sources with a `tsconfig.json` like this:
```js
{
"compilerOptions": {
// Enable JavaScript support
"allowJs": true,
// Point to the JSDoc typed sources when using modules from the ol package
"baseUrl": "./",
"paths": {
"ol": ["node_modules/ol/src"],
"ol/*": ["node_modules/ol/src/*"]
}
},
"include": [
// Include JavaScript files from the ol package
"node_modules/ol/**/*.js"
]
}
```
## Supported Browsers
OpenLayers runs on all modern browsers that support [HTML5](https://html.spec.whatwg.org/multipage/) and [ECMAScript 5](http://www.ecma-international.org/ecma-262/5.1/). This includes Chrome, Firefox, Safari and Edge. For older browsers and platforms like Internet Explorer (down to version 9) and Android 4.x, [polyfills](http://polyfill.io) for `requestAnimationFrame` and `Element.prototype.classList` are required, and using the KML format requires a polyfill for `URL`.
@@ -84,4 +62,4 @@ Please see our guide on [contributing](CONTRIBUTING.md) if you're interested in
- Need help? Find it on [Stack Overflow using the tag 'openlayers'](http://stackoverflow.com/questions/tagged/openlayers)
- Follow [@openlayers](https://twitter.com/openlayers) on Twitter
[![CircleCI](https://circleci.com/gh/openlayers/openlayers/tree/master.svg?style=svg)](https://circleci.com/gh/openlayers/openlayers/tree/master)
[![Build Status](https://travis-ci.org/openlayers/openlayers.svg?branch=master)](https://travis-ci.org/openlayers/openlayers)

View File

@@ -2,128 +2,6 @@
### Next version
#### Backwards incompatible changes
##### Removal of the deprecated "inherits" function
The `inherits` function that was used to inherit the prototype methods from one constructor into another has been removed.
The standard ECMAScript classes should be used instead.
##### New internal tile coordinates
Previously, the internal tile coordinates used in the library had an unusual row order the origin of the tile coordinate system was at the top left as expected, but the rows increased upwards. This meant that all tile coordinates within a tile grid's extent had negative `y` values.
Now, the internal tile coordinates used in the library have the same row order as standard (e.g. XYZ) tile coordinates. The origin is at the top left (as before), and rows or `y` values increase downward. So the top left tile of a tile grid is now `0, 0`, whereas it was `0, -1` before.
```
x, y values for tile coordinates
origin
*__________________________
| | | |
| 0, 0 | 1, 0 | 2, 0 |
|________|________|________|
| | | |
| 0, 1 | 1, 1 | 2, 1 |
|________|________|________|
| | | |
| 0, 2 | 1, 2 | 2, 2 |
|________|________|________|
```
This change should only affect you if you were using a custom `tileLoadFunction` or `tileUrlFunction`. For example, if you used to have a `tileUrlFunction` that looked like this:
```js
// before
function tileUrlFunction(tileCoord) {
const z = tileCoord[0];
const x = tileCoord[1];
const y = -tileCoord[2] - 1;
// do something with z, x, y
}
```
You would now do something like this:
```js
// after
function tileUrlFunction(tileCoord) {
const z = tileCoord[0];
const x = tileCoord[1];
const y = tileCoord[2];
// do something with z, x, y
}
```
In addition (this should be exceedingly rare), if you previously created a `ol/tilegrid/WMTS` by hand and you were providing an array of `sizes`, you no longer have to provide a negative height if your tile origin is the top-left corner (the common case). On the other hand, if you are providing a custom array of `sizes` and your origin is the bottom of the grid (this is uncommon), your height values must now be negative.
##### Removal of the "vector" render mode for vector tile layers
If you were previously using `VectorTile` layers with `renderMode: 'vector'`, you have to remove this configuration option. That mode was removed. `'hybrid'` (default) and `'image'` are still available.
##### New `prerender` and `postrender` layer events replace old `precompose`, `render` and `postcompose` events
If you were previously registering for `precompose` and `postcompose` events, you should now register for `prerender` and `postrender` events on layers. Instead of the previous `render` event, you should now listen for `postrender`. Layers are no longer composed to a single Canvas element. Instead, they are added to the map viewport as individual elements.
##### New `getVectorContext` function provides access to the immediate vector rendering API
Previously, render events included a `vectorContext` property that allowed you to render features or geometries directly to the map. This is still possible, but you now have to explicitly create a vector context with the `getVectorContext` function. This change makes the immediate rendering API an explicit dependency if your application uses it. If you don't use this API, your application bundle will not include the vector rendering modules (as it did before).
Here is an abbreviated example of how to use the `getVectorContext` function:
```js
import {getVectorContext} from 'ol/render';
// construct your map and layers as usual
layer.on('postrender', function(event) {
const vectorContext = getVectorContext(event);
// use any of the drawing methods on the vector context
});
```
##### Layers can only be added to a single map
Previously, it was possible to render a single layer in two maps. Now, each layer can only belong to a single map (in the same way that a single DOM element can only have one parent).
##### The `OverviewMap` requires a list of layers.
Due to the constraint above (layers can only be added to a single map), the overview map needs to be constructed with a list of layers.
##### The `ol/Graticule` has been replaced by `ol/layer/Graticule`
Previously, a graticule was not a layer. Now it is. See the graticule example for details on how to add a graticule layer to your map.
##### Drop of support for the experimental WebGL renderer
The WebGL map and layers renderers are gone, replaced by a `WebGLHelper` function that provides a lightweight,
low-level access to the WebGL API. This is implemented in a new `WebGLPointsLayer` which does simple rendering of large number
of points with custom shaders.
This is now used in the `Heatmap` layer.
The removed classes and components are:
* `WebGLMap` and `WebGLMapRenderer`
* `WebGLLayerRenderer`
* `WebGLImageLayer` and `WebGLImageLayerRenderer`
* `WebGLTileLayer` and `WebGLTileLayerRenderer`
* `WebGLVectorLayer` and `WebGLVectorLayerRenderer`
* `WebGLReplay` and derived classes, along with associated shaders
* `WebGLReplayGroup`
* `WebGLImmediateRenderer`
* `WebGLMap`
* The shader build process using `mustache` and the `Makefile` at the root
##### Removal of the AtlasManager
Following the removal of the experimental WebGL renderer, the AtlasManager has been removed as well. The atlas was only used by this renderer.
The non API `getChecksum` functions of the style is also removed.
#### Other changes
##### Always load tiles while animating or interacting
`ol/PluggableMap` and subclasses no longer support the `loadTilesWhileAnimating` and `loadTilesWhileInteracting` options. These options were used to enable tile loading during animations and interactions. With the new DOM composition render strategy, it is no longer necessary to postpone tile loading until after animations or interactions.
### v5.3.0
#### The `getUid` function returns string
@@ -134,7 +12,7 @@ The `getUid` function from the `ol/util` module now returns a string instead of
When a map contains a layer from a `ol/source/OSM` source, the `ol/control/Attribution` control will be shown with the `collapsible: false` behavior.
To get the previous behavior, configure the `ol/control/Attribution` control with `collapsible: true`.
To get the previous behavior, configure the `ol/control/Attribution` control with `collapsible: true`.
### v5.2.0

6
changelog/v5.3.1.md Normal file
View File

@@ -0,0 +1,6 @@
# 5.3.1
The 5.3.1 release is a patch that addresses an issue when using `angular-cli` to build an OpenLayers-based application.
* [#9253](https://github.com/openlayers/openlayers/pull/9253) - Add proj.js to the sideEffects list ([@romanzoller](https://github.com/romanzoller))

View File

@@ -4,62 +4,12 @@ var version = obj.packageInfo.version;
<!DOCTYPE html>
<html lang="en">
<head>
<script>
var gaProperty = 'UA-2577926-1';
// Disable tracking if the opt-out cookie exists.
var disableStr = 'ga-disable-' + gaProperty;
if (document.cookie.indexOf(disableStr + '=true') > -1) {
window[disableStr] = true;
}
function gaOptout() {
document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
window[disableStr] = true;
}
function gaOptoutRevoke() {
document.cookie = disableStr + '=false; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
window[disableStr] = false;
}
</script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-2577926-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-2577926-1', { 'anonymize_ip': true });
</script>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js"></script>
<script>
window.addEventListener("load", function() {
window.cookieconsent.initialise({
'palette': {
'popup': {
'background': '#eaf7f7',
'text': '#5c7291'
},
'button': {
'background': '#56cbdb',
'text': '#ffffff'
}
},
'theme': 'edgeless',
'type': 'opt-out',
'onInitialise': function (status) {
if (!this.hasConsented()) {
gaOptout()
}
},
'onStatusChange': function(status, chosenBefore) {
if (!this.hasConsented()) {
gaOptout()
}
},
'onRevokeChoice': function() {
gaOptoutRevoke()
}
})
});
gtag('config', 'UA-2577926-1');
</script>
<meta charset="utf-8">
<title>OpenLayers v<?js= version ?> API - <?js= title ?></title>

View File

@@ -1,64 +0,0 @@
{
"compilerOptions": {
/* Basic Options */
"target": "ES5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "../build/ol", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
"importHelpers": false, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": false, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": false, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
"inlineSources": false /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
},
"include": [
"../build/ol/src/**/*.js"
],
"exclude": []
}

View File

@@ -111,7 +111,7 @@ Features for `updates` must have an id set by the feature reader or `ol.Feature#
### 28
`renderMode` must be `'image'` or `'hybrid'`.
`renderMode` must be `'image'`, `'hybrid'` or `'vector'`.
### 29

View File

@@ -18,14 +18,14 @@ Below you'll find a complete working example. Create a new file, copy in the co
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/{{ latest }}/css/ol.css" type="text/css">
<link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/{{ latest }}/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/{{ latest }}/build/ol.js"></script>
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/{{ latest }}/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
@@ -60,7 +60,7 @@ To include a map a web page you will need 3 things:
### Include OpenLayers
```xml
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/{{ latest }}/build/ol.js"></script>
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/{{ latest }}/build/ol.js"></script>
```
The first part is to include the JavaScript library. For the purpose of this tutorial, here we simply point to the openlayers.org website to get the whole library. In a production environment, we would build a custom version of the library including only the module needed for our application.

View File

@@ -17,7 +17,7 @@ OpenLayers is available as [`ol` npm package](https://npmjs.com/package/ol), whi
## Renderers and Browser Support
By default, OpenLayers uses a performance optimized Canvas renderer.
By default, OpenLayers uses a performance optimized Canvas renderer. An experimental WebGL renderer (without text rendering support) is also available.
OpenLayers runs on all modern browsers that support [HTML5](https://html.spec.whatwg.org/multipage/) and [ECMAScript 5](http://www.ecma-international.org/ecma-262/5.1/). This includes Chrome, Firefox, Safari and Edge. For older browsers and platforms like Internet Explorer (down to version 9) and Android 4.x, [polyfills](http://polyfill.io), the application bundle needs to be transpiled (e.g. using [Babel](https://babeljs.io)) and bundled with polyfills for `requestAnimationFrame`, `Element.prototype.classList` and `URL`.
@@ -44,6 +44,6 @@ import {Tile, Vector} from 'ol/layer';
In addition to these re-exported classes, modules with lowercase names also provide constants or functions as named exports:
```js
import {getUid} from 'ol';
import {inherits} from 'ol';
import {fromLonLat} from 'ol/proj';
```

View File

@@ -11,11 +11,9 @@ In this tutorial, we will be using [Parcel](https://parceljs.org) to bundle our
## Initial steps
Create a new empty directory for your project and navigate to it by running `mkdir new-project && cd new-project`. Initialize your project with
Create a new empty directory for your project and navigate to it by running `mkdir new-project && cd new-project`. Initialize your project using `npm init` and answer the questions asked.
npm init
This will create a `package.json` file in your working directory. Add OpenLayers as dependency to your application with
Add OpenLayers as dependency to your application with
npm install ol
@@ -71,21 +69,13 @@ You will also need an `index.html` file that will use your bundle. Here is a sim
## Creating a bundle
With two additional lines in `package.json` you can introduce the commands `npm run build` and `npm start` to manually build your bundle and watch for changes, respectively. The final `package.json` with the two additional commands `"start"` and `"build"` should look like this:
With simple scripts you can introduce the commands `npm run build` and `npm start` to manually build your bundle and watch for changes, respectively. Add the following to the script section in `package.json`:
```json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
},
"author": "",
"license": "ISC"
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
}
```
That's it. Now to run your application, enter

View File

@@ -5,12 +5,10 @@
"common": false,
"createMapboxStreetsV6Style": false,
"d3": false,
"domtoimage": false,
"geojsonvt": false,
"GyroNorm": false,
"jsPDF": false,
"jsts": false,
"mapboxgl": false,
"saveAs": false,
"toastr": false,
"topojson": false,

View File

@@ -24,6 +24,9 @@ const map = new Map({
source: new OSM()
})
],
// Improve user experience by loading tiles while animating. Will make
// animations stutter on mobile or slow devices.
loadTilesWhileAnimating: true,
view: view
});

View File

@@ -29,6 +29,9 @@ for (i = 0, ii = styles.length; i < ii; ++i) {
}
const map = new Map({
layers: layers,
// Improve user experience by loading tiles while dragging/zooming. Will make
// zooming choppy on mobile or slow devices.
loadTilesWhileInteracting: true,
target: 'map',
view: new View({
center: [-6655.5402445057125, 6709968.258934638],

4
examples/blend-modes.css Normal file
View File

@@ -0,0 +1,4 @@
.map{
background-repeat: repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAApSURBVBiVY7x///5/BjSgqKjIiC7GhC6ACwygQgxHMzAwMGDz4FDwDAD5/wevjSk4mwAAAABJRU5ErkJggg==);
}

68
examples/blend-modes.html Normal file
View File

@@ -0,0 +1,68 @@
---
layout: example.html
title: Blend Modes
shortdesc: Shows how to change the canvas compositing / blending mode in post- and precompose eventhandlers.
docs: >
<p>This example shows how to change the canvas compositing / blending mode in
post- and precompose event handlers. The Canvas 2D API provides the property
<code>globalCompositeOperation</code> with which one can influence which
composition operation will be used when drawing on the canvas. The various
options are well described on the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation">MDN
documentation page</a>.</p>
<p>In this example three circles on the corners of an equilateral triangle are
drawn with red, green or blue styles respectively. By setting the
<code>globalCompositeOperation</code> you can change how these colors turn out
when they are combined on the map.</p>
<p>You can select an operation in the select-field and you can also control
which layers will be affected by the chosen operation through the layer
checkboxes.</p>
tags: "blendmode, blend-mode, blend mode, blendingmode, blending-mode, blending mode, composition, compositing, canvas, vector"
---
<div id="map" class="map"></div>
<form class="form-horizontal">
<label>
<select id="blend-mode" class="form-control">
<option value="source-over">source-over (default)</option>
<option>source-in</option>
<option>source-out</option>
<option>source-atop</option>
<option>destination-over</option>
<option>destination-in</option>
<option>destination-out</option>
<option>destination-atop</option>
<option>lighter</option>
<option>copy</option>
<option>xor</option>
<option>multiply</option>
<option>screen</option>
<option>overlay</option>
<option>darken</option>
<option>lighten</option>
<option>color-dodge</option>
<option>color-burn</option>
<option>hard-light</option>
<option>soft-light</option>
<option selected>difference</option>
<option>exclusion</option>
<option>hue</option>
<option>saturation</option>
<option>color</option>
<option>luminosity</option>
</select>
Canvas compositing / blending mode
</label>
<label>
<input type="checkbox" id="affect-red" checked>
Red circle affected
</label>
<label>
<input type="checkbox" id="affect-green" checked>
Green circle affected
</label>
<label>
<input type="checkbox" id="affect-blue" checked>
Blue circle affected
</label>
</form>

173
examples/blend-modes.js Normal file
View File

@@ -0,0 +1,173 @@
import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
// Create separate layers for red, green an blue circles.
//
// Every layer has one feature that is styled with a circle, together the
// features form the corners of an equilateral triangle and their styles overlap
const redLayer = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([0, 0]))]
}),
style: new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(255,0,0,0.8)'
}),
stroke: new Stroke({
color: 'rgb(255,0,0)',
width: 15
}),
radius: 120
})
})
});
const greenLayer = new VectorLayer({
source: new VectorSource({
// 433.013 is roughly 250 * Math.sqrt(3)
features: [new Feature(new Point([250, 433.013]))]
}),
style: new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(0,255,0,0.8)'
}),
stroke: new Stroke({
color: 'rgb(0,255,0)',
width: 15
}),
radius: 120
})
})
});
const blueLayer = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([500, 0]))]
}),
style: new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(0,0,255,0.8)'
}),
stroke: new Stroke({
color: 'rgb(0,0,255)',
width: 15
}),
radius: 120
})
})
});
// Create the map, the view is centered on the triangle. Zooming and panning is
// restricted to a sane area
const map = new Map({
layers: [
redLayer,
greenLayer,
blueLayer
],
target: 'map',
view: new View({
center: [250, 220],
extent: [0, 0, 500, 500],
resolution: 4,
minResolution: 2,
maxResolution: 32
})
});
// Get the form elements and bind the listeners
const select = document.getElementById('blend-mode');
const affectRed = document.getElementById('affect-red');
const affectGreen = document.getElementById('affect-green');
const affectBlue = document.getElementById('affect-blue');
/**
* This method sets the globalCompositeOperation to the value of the select
* field and it is bound to the precompose event of the layers.
*
* @param {module:ol/render/Event~RenderEvent} evt The render event.
*/
const setBlendModeFromSelect = function(evt) {
evt.context.globalCompositeOperation = select.value;
};
/**
* This method resets the globalCompositeOperation to the default value of
* 'source-over' and it is bound to the postcompose event of the layers.
*
* @param {module:ol/render/Event~RenderEvent} evt The render event.
*/
const resetBlendModeFromSelect = function(evt) {
evt.context.globalCompositeOperation = 'source-over';
};
/**
* Bind the pre- and postcompose handlers to the passed layer.
*
* @param {module:ol/layer/Vector} layer The layer to bind the handlers to.
*/
const bindLayerListeners = function(layer) {
layer.on('precompose', setBlendModeFromSelect);
layer.on('postcompose', resetBlendModeFromSelect);
};
/**
* Unind the pre- and postcompose handlers to the passed layers.
*
* @param {module:ol/layer/Vector} layer The layer to unbind the handlers from.
*/
const unbindLayerListeners = function(layer) {
layer.un('precompose', setBlendModeFromSelect);
layer.un('postcompose', resetBlendModeFromSelect);
};
/**
* Handler for the click event of the 'affect-XXX' checkboxes.
*
* @this {HTMLInputElement}
*/
const affectLayerClicked = function() {
let layer;
if (this.id == 'affect-red') {
layer = redLayer;
} else if (this.id == 'affect-green') {
layer = greenLayer;
} else {
layer = blueLayer;
}
if (this.checked) {
bindLayerListeners(layer);
} else {
unbindLayerListeners(layer);
}
map.render();
};
// Rerender map when blend mode changes
select.addEventListener('change', function() {
map.render();
});
// Unbind / bind listeners depending on the checked state when the checkboxes
// are clicked
affectRed.addEventListener('click', affectLayerClicked);
affectGreen.addEventListener('click', affectLayerClicked);
affectBlue.addEventListener('click', affectLayerClicked);
// Initially bind listeners
bindLayerListeners(redLayer);
bindLayerListeners(greenLayer);
bindLayerListeners(blueLayer);

View File

@@ -61,8 +61,8 @@ const style = new Style({
* The styling function for the vector layer, will return an array of styles
* which either contains the aboove gradient or pattern.
*
* @param {import("../src/ol/Feature.js").default} feature The feature to style.
* @return {Style} The style to use for the feature.
* @param {module:ol/Feature~Feature} feature The feature to style.
* @return {module:ol/style/Style} The style to use for the feature.
*/
const getStackedStyle = function(feature) {
const id = feature.getId();

View File

@@ -4,7 +4,10 @@ title: Canvas Tiles
shortdesc: Renders tiles with coordinates for debugging.
docs: >
The black grid tiles are generated on the client with an HTML5 canvas. The
displayed tile coordinates are the XYZ tile coordinates.
displayed tile coordinates are OpenLayers tile coordinates. These increase
from bottom to top, but standard XYZ tiling scheme coordinates increase from
top to bottom. To calculate the `y` for a standard XYZ tile coordinate, use
`-y - 1`.
tags: "layers, openstreetmap, canvas"
---
<div id="map" class="map"></div>

View File

@@ -1,21 +1,26 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import {fromLonLat} from '../src/ol/proj.js';
import {OSM, TileDebug} from '../src/ol/source.js';
const osmSource = new OSM();
const map = new Map({
layers: [
new TileLayer({
source: new OSM()
source: osmSource
}),
new TileLayer({
source: new TileDebug()
source: new TileDebug({
projection: 'EPSG:3857',
tileGrid: osmSource.getTileGrid()
})
})
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 1
center: fromLonLat([-0.1275, 51.507222]),
zoom: 10
})
});

View File

@@ -50,7 +50,7 @@ const map = new Map({
const zoomtoswitzerlandbest = document.getElementById('zoomtoswitzerlandbest');
zoomtoswitzerlandbest.addEventListener('click', function() {
const feature = source.getFeatures()[0];
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
const polygon = /** @type {module:ol/geom/SimpleGeometry~SimpleGeometry} */ (feature.getGeometry());
view.fit(polygon, {padding: [170, 50, 30, 150], constrainResolution: false});
}, false);
@@ -58,7 +58,7 @@ const zoomtoswitzerlandconstrained =
document.getElementById('zoomtoswitzerlandconstrained');
zoomtoswitzerlandconstrained.addEventListener('click', function() {
const feature = source.getFeatures()[0];
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
const polygon = /** @type {module:ol/geom/SimpleGeometry~SimpleGeometry} */ (feature.getGeometry());
view.fit(polygon, {padding: [170, 50, 30, 150]});
}, false);
@@ -66,21 +66,21 @@ const zoomtoswitzerlandnearest =
document.getElementById('zoomtoswitzerlandnearest');
zoomtoswitzerlandnearest.addEventListener('click', function() {
const feature = source.getFeatures()[0];
const polygon = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
const polygon = /** @type {module:ol/geom/SimpleGeometry~SimpleGeometry} */ (feature.getGeometry());
view.fit(polygon, {padding: [170, 50, 30, 150], nearest: true});
}, false);
const zoomtolausanne = document.getElementById('zoomtolausanne');
zoomtolausanne.addEventListener('click', function() {
const feature = source.getFeatures()[1];
const point = /** @type {import("../src/ol/geom/SimpleGeometry.js").default} */ (feature.getGeometry());
const point = /** @type {module:ol/geom/SimpleGeometry~SimpleGeometry} */ (feature.getGeometry());
view.fit(point, {padding: [170, 50, 30, 150], minResolution: 50});
}, false);
const centerlausanne = document.getElementById('centerlausanne');
centerlausanne.addEventListener('click', function() {
const feature = source.getFeatures()[1];
const point = /** @type {import("../src/ol/geom/Point.js").default} */ (feature.getGeometry());
const size = map.getSize();
const point = /** @type {module:ol/geom/Point~Point} */ (feature.getGeometry());
const size = /** @type {module:ol/size~Size} */ (map.getSize());
view.centerOn(point.getCoordinates(), size, [570, 500]);
}, false);

View File

@@ -9,11 +9,14 @@ import OSM from '../src/ol/source/OSM.js';
// Define rotate to north control.
//
/**
* @constructor
* @extends {module:ol/control/Control~Control}
* @param {Object=} opt_options Control options.
*/
class RotateNorthControl extends Control {
/**
* @param {Object=} opt_options Control options.
*/
constructor(opt_options) {
const options = opt_options || {};

View File

@@ -8,6 +8,10 @@ import {TileJSON, Vector as VectorSource} from '../src/ol/source.js';
import {Fill, Icon, Stroke, Style} from '../src/ol/style.js';
/**
* @constructor
* @extends {module:ol/interaction/Pointer}
*/
class Drag extends PointerInteraction {
constructor() {
super({
@@ -18,7 +22,7 @@ class Drag extends PointerInteraction {
});
/**
* @type {import("../src/ol/coordinate.js").Coordinate}
* @type {module:ol/pixel~Pixel}
* @private
*/
this.coordinate_ = null;
@@ -30,7 +34,7 @@ class Drag extends PointerInteraction {
this.cursor_ = 'pointer';
/**
* @type {Feature}
* @type {module:ol/Feature~Feature}
* @private
*/
this.feature_ = null;
@@ -45,7 +49,7 @@ class Drag extends PointerInteraction {
/**
* @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.
* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt Map browser event.
* @return {boolean} `true` to start the drag sequence.
*/
function handleDownEvent(evt) {
@@ -66,7 +70,7 @@ function handleDownEvent(evt) {
/**
* @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.
* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt Map browser event.
*/
function handleDragEvent(evt) {
const deltaX = evt.coordinate[0] - this.coordinate_[0];
@@ -81,7 +85,7 @@ function handleDragEvent(evt) {
/**
* @param {import("../src/ol/MapBrowserEvent.js").default} evt Event.
* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt Event.
*/
function handleMoveEvent(evt) {
if (this.cursor_) {
@@ -137,13 +141,13 @@ const map = new Map({
features: [pointFeature, lineFeature, polygonFeature]
}),
style: new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.95,
src: 'data/icon.png'
}),
})),
stroke: new Stroke({
width: 3,
color: [255, 0, 0, 1]

View File

@@ -1,4 +0,0 @@
path.boundary {
fill: none;
stroke: #777;
}

View File

@@ -3,7 +3,7 @@ layout: example.html
title: d3 Integration
shortdesc: Example of using OpenLayers and d3 together.
docs: >
The example loads TopoJSON geometries and uses d3 (<code>d3.geo.path</code>) to render these geometries to a SVG element.
<p>The example loads TopoJSON geometries and uses d3 (<code>d3.geo.path</code>) to render these geometries to a canvas element that is then used as the image of an OpenLayers image layer.</p>
tags: "d3"
resources:
- https://unpkg.com/d3@4.12.0/build/d3.js

122
examples/d3.js vendored
View File

@@ -1,70 +1,10 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {getWidth, getCenter} from '../src/ol/extent.js';
import {Layer, Tile as TileLayer} from '../src/ol/layer.js';
import SourceState from '../src/ol/source/State';
import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
import {fromLonLat, toLonLat} from '../src/ol/proj.js';
import Stamen from '../src/ol/source/Stamen.js';
import {ImageCanvas as ImageCanvasSource, Stamen} from '../src/ol/source.js';
class CanvasLayer extends Layer {
constructor(options) {
super(options);
this.features = options.features;
this.svg = d3.select(document.createElement('div')).append('svg')
.style('position', 'absolute');
this.svg.append('path')
.datum(this.features)
.attr('class', 'boundary');
}
getSourceState() {
return SourceState.READY;
}
render(frameState) {
const width = frameState.size[0];
const height = frameState.size[1];
const projection = frameState.viewState.projection;
const d3Projection = d3.geoMercator().scale(1).translate([0, 0]);
let d3Path = d3.geoPath().projection(d3Projection);
const pixelBounds = d3Path.bounds(this.features);
const pixelBoundsWidth = pixelBounds[1][0] - pixelBounds[0][0];
const pixelBoundsHeight = pixelBounds[1][1] - pixelBounds[0][1];
const geoBounds = d3.geoBounds(this.features);
const geoBoundsLeftBottom = fromLonLat(geoBounds[0], projection);
const geoBoundsRightTop = fromLonLat(geoBounds[1], projection);
let geoBoundsWidth = geoBoundsRightTop[0] - geoBoundsLeftBottom[0];
if (geoBoundsWidth < 0) {
geoBoundsWidth += getWidth(projection.getExtent());
}
const geoBoundsHeight = geoBoundsRightTop[1] - geoBoundsLeftBottom[1];
const widthResolution = geoBoundsWidth / pixelBoundsWidth;
const heightResolution = geoBoundsHeight / pixelBoundsHeight;
const r = Math.max(widthResolution, heightResolution);
const scale = r / frameState.viewState.resolution;
const center = toLonLat(getCenter(frameState.extent), projection);
d3Projection.scale(scale).center(center).translate([width / 2, height / 2]);
d3Path = d3Path.projection(d3Projection);
d3Path(this.features);
this.svg.attr('width', width);
this.svg.attr('height', height);
this.svg.select('path')
.attr('d', d3Path);
return this.svg.node();
}
}
const map = new Map({
layers: [
@@ -86,10 +26,62 @@ const map = new Map({
* Load the topojson data and create an ol/layer/Image for that data.
*/
d3.json('data/topojson/us.json', function(error, us) {
const features = topojson.feature(us, us.objects.counties);
const layer = new CanvasLayer({
features: topojson.feature(us, us.objects.counties)
/**
* This function uses d3 to render the topojson features to a canvas.
* @param {module:ol/extent~Extent} extent Extent.
* @param {number} resolution Resolution.
* @param {number} pixelRatio Pixel ratio.
* @param {module:ol/size~Size} size Size.
* @param {module:ol/proj/Projection~Projection} projection Projection.
* @return {HTMLCanvasElement} A canvas element.
*/
const canvasFunction = function(extent, resolution, pixelRatio, size, projection) {
const canvasWidth = size[0];
const canvasHeight = size[1];
const canvas = d3.select(document.createElement('canvas'));
canvas.attr('width', canvasWidth).attr('height', canvasHeight);
const context = canvas.node().getContext('2d');
const d3Projection = d3.geoMercator().scale(1).translate([0, 0]);
let d3Path = d3.geoPath().projection(d3Projection);
const pixelBounds = d3Path.bounds(features);
const pixelBoundsWidth = pixelBounds[1][0] - pixelBounds[0][0];
const pixelBoundsHeight = pixelBounds[1][1] - pixelBounds[0][1];
const geoBounds = d3.geoBounds(features);
const geoBoundsLeftBottom = fromLonLat(geoBounds[0], projection);
const geoBoundsRightTop = fromLonLat(geoBounds[1], projection);
let geoBoundsWidth = geoBoundsRightTop[0] - geoBoundsLeftBottom[0];
if (geoBoundsWidth < 0) {
geoBoundsWidth += getWidth(projection.getExtent());
}
const geoBoundsHeight = geoBoundsRightTop[1] - geoBoundsLeftBottom[1];
const widthResolution = geoBoundsWidth / pixelBoundsWidth;
const heightResolution = geoBoundsHeight / pixelBoundsHeight;
const r = Math.max(widthResolution, heightResolution);
const scale = r / (resolution / pixelRatio);
const center = toLonLat(getCenter(extent), projection);
d3Projection.scale(scale).center(center)
.translate([canvasWidth / 2, canvasHeight / 2]);
d3Path = d3Path.projection(d3Projection).context(context);
d3Path(features);
context.stroke();
return canvas.node();
};
const layer = new ImageLayer({
source: new ImageCanvasSource({
canvasFunction: canvasFunction,
projection: 'EPSG:3857'
})
});
map.addLayer(layer);
});

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -29,7 +29,7 @@ gn.init().then(function() {
gn.start(function(event) {
const center = view.getCenter();
const resolution = view.getResolution();
const alpha = toRadians(event.do.alpha);
const alpha = toRadians(event.do.beta);
const beta = toRadians(event.do.beta);
const gamma = toRadians(event.do.gamma);

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Drag-and-Drop Image Vector
shortdesc: Example of using the drag-and-drop interaction with image vector rendering.
docs: >
Example of using the drag-and-drop interaction with an `ol/layer/VectorImage` layer. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client.
Example of using the drag-and-drop interaction with an `ol/layer/Vector` with `renderMode: 'image'`. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client.
tags: "drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, vector, image"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5

View File

@@ -2,7 +2,7 @@ import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import {GPX, GeoJSON, IGC, KML, TopoJSON} from '../src/ol/format.js';
import {defaults as defaultInteractions, DragAndDrop} from '../src/ol/interaction.js';
import {VectorImage as VectorImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
import {Vector as VectorLayer, Tile as TileLayer} from '../src/ol/layer.js';
import {BingMaps, Vector as VectorSource} from '../src/ol/source.js';
const dragAndDropInteraction = new DragAndDrop({
@@ -36,7 +36,8 @@ dragAndDropInteraction.on('addfeatures', function(event) {
const vectorSource = new VectorSource({
features: event.features
});
map.addLayer(new VectorImageLayer({
map.addLayer(new VectorLayer({
renderMode: 'image',
source: vectorSource
}));
map.getView().fit(vectorSource.getExtent());

View File

@@ -4,14 +4,14 @@ import {MultiPoint, Point} from '../src/ol/geom.js';
import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
const tileLayer = new TileLayer({
source: new OSM()
});
const map = new Map({
layers: [tileLayer],
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: new View({
center: [0, 0],
@@ -46,8 +46,8 @@ const omegaTheta = 30000; // Rotation period in ms
const R = 7e6;
const r = 2e6;
const p = 2e6;
tileLayer.on('postrender', function(event) {
const vectorContext = getVectorContext(event);
map.on('postcompose', function(event) {
const vectorContext = event.vectorContext;
const frameState = event.frameState;
const theta = 2 * Math.PI * frameState.time / omegaTheta;
const coordinates = [];

View File

@@ -3,12 +3,12 @@ layout: example.html
title: Map Export
shortdesc: Example of exporting a map as a PNG image.
docs: >
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/dom-to-image-more">dom-to-image-more</a>
library.
Example of exporting a map as a PNG image. This example requires a browser
that supports <a href="https://developer.mozilla.org/de/docs/Web/API/HTMLCanvasElement/toBlob#Browser_compatibility">
<code>canvas.toBlob()</code></a>.
tags: "export, png, openstreetmap"
resources:
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
- https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
---
<div id="map" class="map"></div>
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
<a id="image-download" download="map.png"></a>

View File

@@ -24,13 +24,15 @@ const map = new Map({
});
document.getElementById('export-png').addEventListener('click', function() {
map.once('rendercomplete', function() {
domtoimage.toPng(map.getViewport().querySelector('.ol-layers'))
.then(function(dataURL) {
const link = document.getElementById('image-download');
link.href = dataURL;
link.click();
map.once('rendercomplete', function(event) {
const canvas = event.context.canvas;
if (navigator.msSaveBlob) {
navigator.msSaveBlob(canvas.msToBlob(), 'map.png');
} else {
canvas.toBlob(function(blob) {
saveAs(blob, 'map.png');
});
}
});
map.renderSync();
});

View File

@@ -7,7 +7,6 @@ docs: >
tags: "export, pdf, openstreetmap"
resources:
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
- https://unpkg.com/dom-to-image-more@2.7.1/dist/dom-to-image-more.min.js
---
<div class="row-fluid">
<div class="span12">

View File

@@ -53,20 +53,20 @@ exportButton.addEventListener('click', function() {
const dim = dims[format];
const width = Math.round(dim[0] * resolution / 25.4);
const height = Math.round(dim[1] * resolution / 25.4);
const size = map.getSize();
const size = /** @type {module:ol/size~Size} */ (map.getSize());
const extent = map.getView().calculateExtent(size);
map.once('rendercomplete', function() {
domtoimage.toJpeg(map.getViewport().querySelector('.ol-layers')).then(function(dataUrl) {
const pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().fit(extent, {size});
exportButton.disabled = false;
document.body.style.cursor = 'auto';
});
map.once('rendercomplete', function(event) {
const canvas = event.context.canvas;
const data = canvas.toDataURL('image/jpeg');
const pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().fit(extent, {size});
exportButton.disabled = false;
document.body.style.cursor = 'auto';
});
// Set print size

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Custom Animation
shortdesc: Demonstrates how to animate features.
docs: >
This example shows how to use <b>postrender</b> and <b>vectorContext</b> to
This example shows how to use <b>postcompose</b> and <b>vectorContext</b> to
animate features. Here we choose to do a flash animation each time a feature
is added to the layer.
tags: "animation, vector, feature, flash"

View File

@@ -8,16 +8,16 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import {fromLonLat} from '../src/ol/proj.js';
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import {Circle as CircleStyle, Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
const tileLayer = new TileLayer({
source: new OSM({
wrapX: false
})
});
const map = new Map({
layers: [tileLayer],
layers: [
new TileLayer({
source: new OSM({
wrapX: false
})
})
],
target: 'map',
view: new View({
center: [0, 0],
@@ -44,10 +44,10 @@ function addRandomFeature() {
const duration = 3000;
function flash(feature) {
const start = new Date().getTime();
const listenerKey = tileLayer.on('postrender', animate);
const listenerKey = map.on('postcompose', animate);
function animate(event) {
const vectorContext = getVectorContext(event);
const vectorContext = event.vectorContext;
const frameState = event.frameState;
const flashGeom = feature.getGeometry().clone();
const elapsed = frameState.time - start;
@@ -72,7 +72,7 @@ function flash(feature) {
unByKey(listenerKey);
return;
}
// tell OpenLayers to continue postrender animation
// tell OpenLayers to continue postcompose animation
map.render();
}
}

View File

@@ -3,10 +3,10 @@ layout: example.html
title: Marker Animation
shortdesc: Demonstrates how to move a feature along a line.
docs: >
This example shows how to use <b>postrender</b> events and a <b>vector context</b> to
animate a marker feature along a line. In this example an encoded polyline
This example shows how to use <b>postcompose</b> and <b>vectorContext</b> to
animate a (marker) feature along a line. In this example an encoded polyline
is being used.
tags: "animation, feature, postrender, polyline"
tags: "animation, feature, postcompose, polyline"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here

View File

@@ -7,7 +7,6 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import BingMaps from '../src/ol/source/BingMaps.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
// This long string is placed here due to jsFiddle limitations.
// It is usually loaded with AJAX.
@@ -53,7 +52,7 @@ const polyline = [
'~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL'
].join('');
const route = /** @type {import("../src/ol/geom/LineString.js").default} */ (new Polyline({
const route = /** @type {module:ol/geom/LineString~LineString} */ (new Polyline({
factor: 1e6
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
@@ -124,6 +123,7 @@ const vectorLayer = new VectorLayer({
const center = [-5639523.95, -3501274.52];
const map = new Map({
target: document.getElementById('map'),
loadTilesWhileAnimating: true,
view: new View({
center: center,
zoom: 10,
@@ -142,7 +142,7 @@ const map = new Map({
});
const moveFeature = function(event) {
const vectorContext = getVectorContext(event);
const vectorContext = event.vectorContext;
const frameState = event.frameState;
if (animating) {
@@ -160,7 +160,7 @@ const moveFeature = function(event) {
const feature = new Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
// tell OpenLayers to continue the postrender animation
// tell OpenLayers to continue the postcompose animation
map.render();
};
@@ -176,7 +176,7 @@ function startAnimation() {
geoMarker.setStyle(null);
// just in case you pan somewhere else
map.getView().setCenter(center);
vectorLayer.on('postrender', moveFeature);
map.on('postcompose', moveFeature);
map.render();
}
}
@@ -191,10 +191,10 @@ function stopAnimation(ended) {
// if animation cancelled set the marker at the beginning
const coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
const geometry = /** @type {import("../src/ol/geom/Point").default} */ (geoMarker.getGeometry());
geometry.setCoordinates(coord);
/** @type {module:ol/geom/Point~Point} */ (geoMarker.getGeometry())
.setCoordinates(coord);
//remove listener
vectorLayer.un('postrender', moveFeature);
map.un('postcompose', moveFeature);
}
startButton.addEventListener('click', startAnimation, false);

View File

@@ -1,12 +1,12 @@
---
layout: example.html
title: Flight Animation
shortdesc: Demonstrates how to animate flights with ´postrender´.
shortdesc: Demonstrates how to animate flights with ´postcompose´.
docs: >
This example shows how to use <b>postrender</b> and <b>vectorContext</b> to
This example shows how to use <b>postcompose</b> and <b>vectorContext</b> to
animate flights. A great circle arc between two airports is calculated using
<a href="https://github.com/springmeyer/arc.js">arc.js</a> and then the flight
paths are animated with <b>postrender</b>. The flight data is provided by
paths are animated with <b>postcompose</b>. The flight data is provided by
<a href="http://openflights.org/data.html">OpenFlights</a> (a simplified data
set from the <a href="https://www.mapbox.com/mapbox.js/example/v1.0.0/animating-flight-paths/">
Mapbox.js documentation</a> is used).

View File

@@ -6,17 +6,14 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import Stamen from '../src/ol/source/Stamen.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
const tileLayer = new TileLayer({
source: new Stamen({
layer: 'toner'
})
});
const map = new Map({
layers: [
tileLayer
new TileLayer({
source: new Stamen({
layer: 'toner'
})
})
],
target: 'map',
view: new View({
@@ -66,7 +63,7 @@ const flightsSource = new VectorSource({
addLater(feature, i * 50);
}
}
tileLayer.on('postrender', animateFlights);
map.on('postcompose', animateFlights);
});
}
});
@@ -88,7 +85,7 @@ map.addLayer(flightsLayer);
const pointsPerMs = 0.1;
function animateFlights(event) {
const vectorContext = getVectorContext(event);
const vectorContext = event.vectorContext;
const frameState = event.frameState;
vectorContext.setStyle(style);

View File

@@ -77,7 +77,7 @@ fetch(url).then(function(response) {
tileLoadFunction: function(tile) {
const format = tile.getFormat();
const tileCoord = tile.getTileCoord();
const data = tileIndex.getTile(tileCoord[0], tileCoord[1], tileCoord[2]);
const data = tileIndex.getTile(tileCoord[0], tileCoord[1], -tileCoord[2] - 1);
const features = format.readFeatures(
JSON.stringify({

View File

@@ -13,13 +13,13 @@ const view = new View({
zoom: 19
});
const tileLayer = new TileLayer({
source: new OSM()
});
// creating the map
const map = new Map({
layers: [tileLayer],
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: view
});
@@ -36,7 +36,7 @@ map.addOverlay(marker);
// LineString to store the different geolocation positions. This LineString
// is time aware.
// The Z dimension is actually used to store the rotation (heading).
const positions = new LineString([], 'XYZM');
const positions = new LineString([], /** @type {module:ol/geom/GeometryLayout} */ ('XYZM'));
// Geolocation Control
const geolocation = new Geolocation({
@@ -155,7 +155,7 @@ const geolocateBtn = document.getElementById('geolocate');
geolocateBtn.addEventListener('click', function() {
geolocation.setTracking(true); // Start position tracking
tileLayer.on('postrender', updateView);
map.on('postcompose', updateView);
map.render();
disableButtons();
@@ -197,7 +197,7 @@ simulateBtn.addEventListener('click', function() {
}
geolocate();
tileLayer.on('postrender', updateView);
map.on('postcompose', updateView);
map.render();
disableButtons();

View File

@@ -1,9 +1,9 @@
---
layout: example.html
title: Map Graticule
shortdesc: This example shows how to add a graticule layer to a map.
shortdesc: This example shows how to add a graticule overlay to a map.
docs: >
This example shows how to add a graticule layer to a map.
This example shows how to add a graticule overlay to a map.
tags: "graticule"
---
<div id="map" class="map"></div>

View File

@@ -1,4 +1,4 @@
import Graticule from '../src/ol/layer/Graticule.js';
import Graticule from '../src/ol/Graticule.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
@@ -13,16 +13,6 @@ const map = new Map({
source: new OSM({
wrapX: false
})
}),
new Graticule({
// the style to use for the lines, optional.
strokeStyle: new Stroke({
color: 'rgba(255,120,0,0.9)',
width: 2,
lineDash: [0.5, 4]
}),
showLabels: true,
wrapX: false
})
],
target: 'map',
@@ -31,3 +21,16 @@ const map = new Map({
zoom: 5
})
});
// Create the graticule component
const graticule = new Graticule({
// the style to use for the lines, optional.
strokeStyle: new Stroke({
color: 'rgba(255,120,0,0.9)',
width: 2,
lineDash: [0.5, 4]
}),
showLabels: true
});
graticule.setMap(map);

View File

@@ -43,14 +43,11 @@ const map = new Map({
})
});
const blurHandler = function() {
vector.setBlur(parseInt(blur.value, 10));
};
blur.addEventListener('input', blurHandler);
blur.addEventListener('change', blurHandler);
const radiusHandler = function() {
blur.addEventListener('input', function() {
vector.setBlur(parseInt(blur.value, 10));
});
radius.addEventListener('input', function() {
vector.setRadius(parseInt(radius.value, 10));
};
radius.addEventListener('input', radiusHandler);
radius.addEventListener('change', radiusHandler);
});

View File

@@ -69,6 +69,9 @@ for (i = 0, ii = hereLayers.length; i < ii; ++i) {
const map = new Map({
layers: layers,
// Improve user experience by loading tiles while dragging/zooming. Will make
// zooming choppy on mobile or slow devices.
loadTilesWhileInteracting: true,
target: 'map',
view: new View({
center: [921371.9389, 6358337.7609],

View File

@@ -22,27 +22,27 @@ const madrid = new Feature({
});
rome.setStyle(new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
color: '#8959A8',
crossOrigin: 'anonymous',
src: 'data/dot.png'
})
}))
}));
london.setStyle(new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
color: '#4271AE',
crossOrigin: 'anonymous',
src: 'data/dot.png'
})
}))
}));
madrid.setStyle(new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
color: [113, 140, 0],
crossOrigin: 'anonymous',
src: 'data/dot.png'
})
}))
}));

View File

@@ -11,13 +11,13 @@ import {Icon, Style} from '../src/ol/style.js';
function createStyle(src, img) {
return new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
anchor: [0.5, 0.96],
crossOrigin: 'anonymous',
src: src,
img: img,
imgSize: img ? [img.width, img.height] : undefined
})
}))
});
}

View File

@@ -1,17 +1,10 @@
---
layout: example.html
title: Icon Sprites with WebGL
shortdesc: Rendering many icons with WebGL
shortdesc: Icon sprite with WebGL
docs: >
This example shows how to use `ol/renderer/webgl/PointsLayer` to render
a very large amount of sprites. The above map is based on a dataset from the National UFO Reporting Center: each
icon marks a UFO sighting according to its reported shape (disk, light, fireball...). The older the sighting, the redder
the icon.
A very simple sprite atlas is used in the form of a PNG file containing all icons on a grid. Then, the `texCoordCallback`
option of the `ol/renderer/webgl/PointsLayer` constructor is used to specify which sprite to use according to the sighting shape.
The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings
tags: "webgl, icon, sprite, point, ufo"
<p>In this example a sprite image is used for the icon styles. Using a sprite is required to get good performance with WebGL.</p>
tags: "webgl, icon, sprite, vector, point"
---
<div id="map" class="map"></div>
<div id="info">&nbsp;</div>

View File

@@ -1,124 +1,136 @@
import Map from '../src/ol/Map.js';
import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/WebGLMap.js';
import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import TileJSON from '../src/ol/source/TileJSON';
import Feature from '../src/ol/Feature';
import Point from '../src/ol/geom/Point';
import VectorLayer from '../src/ol/layer/Vector';
import {Vector} from '../src/ol/source';
import {fromLonLat} from '../src/ol/proj';
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer';
import {lerp} from '../src/ol/math';
import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Icon, Style} from '../src/ol/style.js';
const features = [];
const vectorSource = new Vector({
features: [],
attributions: 'National UFO Reporting Center'
const iconInfo = [{
offset: [0, 0],
opacity: 1.0,
rotateWithView: true,
rotation: 0.0,
scale: 1.0,
size: [55, 55]
}, {
offset: [110, 86],
opacity: 0.75,
rotateWithView: false,
rotation: Math.PI / 2.0,
scale: 1.25,
size: [55, 55]
}, {
offset: [55, 0],
opacity: 0.5,
rotateWithView: true,
rotation: Math.PI / 3.0,
scale: 1.5,
size: [55, 86]
}, {
offset: [212, 0],
opacity: 1.0,
rotateWithView: true,
rotation: 0.0,
scale: 1.0,
size: [44, 44]
}];
let i;
const iconCount = iconInfo.length;
const icons = new Array(iconCount);
for (i = 0; i < iconCount; ++i) {
const info = iconInfo[i];
icons[i] = new Icon({
offset: info.offset,
opacity: info.opacity,
rotateWithView: info.rotateWithView,
rotation: info.rotation,
scale: info.scale,
size: info.size,
crossOrigin: 'anonymous',
src: 'data/Butterfly.png'
});
}
const featureCount = 50000;
const features = new Array(featureCount);
let feature, geometry;
const e = 25000000;
for (i = 0; i < featureCount; ++i) {
geometry = new Point(
[2 * e * Math.random() - e, 2 * e * Math.random() - e]);
feature = new Feature(geometry);
feature.setStyle(
new Style({
image: icons[i % (iconCount - 1)]
})
);
features[i] = feature;
}
const vectorSource = new VectorSource({
features: features
});
const vector = new VectorLayer({
source: vectorSource
});
const texture = document.createElement('img');
texture.src = 'data/ufo_shapes.png';
// This describes the content of the associated sprite sheet
// coords are u0, v0, u1, v1 for a given shape
const shapeTextureCoords = {
'light': [0, 0.5, 0.25, 0],
'sphere': [0.25, 0.5, 0.5, 0],
'circle': [0.25, 0.5, 0.5, 0],
'disc': [0.5, 0.5, 0.75, 0],
'oval': [0.5, 0.5, 0.75, 0],
'triangle': [0.75, 0.5, 1, 0],
'fireball': [0, 1, 0.25, 0.5],
'default': [0.75, 1, 1, 0.5]
};
const oldColor = [255, 160, 110];
const newColor = [180, 255, 200];
class WebglPointsLayer extends VectorLayer {
createRenderer() {
return new WebGLPointsLayerRenderer(this, {
texture: texture,
colorCallback: function(feature, vertex, component) {
// component at index 3 is alpha
if (component === 3) {
return 1;
}
// color is interpolated based on year (min is 1910, max is 2013)
// please note: most values are between 2000-2013
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
return lerp(oldColor[component], newColor[component], ratio * ratio) / 255;
},
texCoordCallback: function(feature, component) {
let coords = shapeTextureCoords[feature.get('shape')];
if (!coords) {
coords = shapeTextureCoords['default'];
}
return coords[component];
},
sizeCallback: function() {
return 16;
}
});
}
}
function loadData() {
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/ufo_sighting_data.csv');
client.onload = function() {
const csv = client.responseText;
let curIndex;
let prevIndex = 0;
let line;
while ((curIndex = csv.indexOf('\n', prevIndex)) > 0) {
line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
prevIndex = curIndex + 1;
// skip header
if (prevIndex === 0) {
continue;
}
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
// only keep valid points
if (isNaN(coords[0]) || isNaN(coords[1])) {
continue;
}
features.push(new Feature({
datetime: line[0],
year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
shape: line[2],
duration: line[3],
geometry: new Point(coords)
}));
}
vectorSource.addFeatures(features);
};
client.send();
}
loadData();
new Map({
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.world-dark.json?secure',
crossOrigin: 'anonymous'
})
}),
new WebglPointsLayer({
source: vectorSource
})
],
const map = new Map({
layers: [vector],
target: document.getElementById('map'),
view: new View({
center: [0, 4000000],
zoom: 2
center: [0, 0],
zoom: 5
})
});
const overlayFeatures = [];
for (i = 0; i < featureCount; i += 30) {
const clone = features[i].clone();
clone.setStyle(null);
overlayFeatures.push(clone);
}
new VectorLayer({
map: map,
source: new VectorSource({
features: overlayFeatures
}),
style: new Style({
image: icons[iconCount - 1]
})
});
map.on('click', function(evt) {
const info = document.getElementById('info');
info.innerHTML =
'Hold on a second, while I catch those butterflies for you ...';
window.setTimeout(function() {
const features = [];
map.forEachFeatureAtPixel(evt.pixel, function(feature) {
features.push(feature);
return false;
});
if (features.length === 1) {
info.innerHTML = 'Got one butterfly';
} else if (features.length > 1) {
info.innerHTML = 'Got ' + features.length + ' butterflies';
} else {
info.innerHTML = 'Couldn\'t catch a single butterfly';
}
}, 1);
});
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
const hit = map.hasFeatureAtPixel(pixel);
map.getTarget().style.cursor = hit ? 'pointer' : '';
});

View File

@@ -17,12 +17,12 @@ const iconFeature = new Feature({
});
const iconStyle = new Style({
image: new Icon({
image: new Icon(/** @type {module:ol/style/Icon~Options} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'data/icon.png'
})
}))
});
iconFeature.setStyle(iconStyle);

View File

@@ -7,7 +7,6 @@ import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
import OSM, {ATTRIBUTION} from '../src/ol/source/OSM.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
const colors = {
@@ -74,10 +73,6 @@ vectorSource.on('addfeature', function(event) {
time.duration = time.stop - time.start;
});
const vectorLayer = new VectorLayer({
source: vectorSource,
style: styleFunction
});
const map = new Map({
layers: [
@@ -91,7 +86,10 @@ const map = new Map({
'?apikey=0e6fc415256d4fbb9b5166a718591d71'
})
}),
vectorLayer
new VectorLayer({
source: vectorSource,
style: styleFunction
})
],
target: 'map',
view: new View({
@@ -155,8 +153,8 @@ const style = new Style({
stroke: stroke
})
});
vectorLayer.on('postrender', function(evt) {
const vectorContext = getVectorContext(evt);
map.on('postcompose', function(evt) {
const vectorContext = evt.vectorContext;
vectorContext.setStyle(style);
if (point !== null) {
vectorContext.drawGeometry(point);
@@ -183,7 +181,7 @@ document.getElementById('time').addEventListener('input', function() {
const value = parseInt(this.value, 10) / 100;
const m = time.start + (time.duration * value);
vectorSource.forEachFeature(function(feature) {
const geometry = /** @type {import("../src/ol/geom/LineString.js").default} */ (feature.getGeometry());
const geometry = /** @type {module:ol/geom/LineString~LineString} */ (feature.getGeometry());
const coordinate = geometry.getCoordinateAtM(m, true);
let highlight = feature.get('highlight');
if (highlight === undefined) {

View File

@@ -3,9 +3,9 @@ layout: example.html
title: Image Filters
shortdesc: Apply a filter to imagery
docs: >
<p>Layer rendering can be manipulated in <code>prerender</code> and <code>postrender</code> event listeners.
<p>Layer rendering can be manipulated in <code>precompose</code> and <code>postcompose</code> event listeners.
These listeners get an event with a reference to the Canvas rendering context.
In this example, the <code>postrender</code> listener applies a filter to the image data.</p>
In this example, the <code>postcompose</code> listener applies a filter to the image data.</p>
tags: "filter, image manipulation"
cloak:
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5

View File

@@ -90,9 +90,9 @@ select.onchange = function() {
/**
* Apply a filter on "postrender" events.
* Apply a filter on "postcompose" events.
*/
imagery.on('postrender', function(event) {
imagery.on('postcompose', function(event) {
convolve(event.context, selectedKernel);
});

View File

@@ -6,7 +6,7 @@ import ImageWMS from '../src/ol/source/ImageWMS.js';
/**
* Renders a progress bar.
* @param {HTMLElement} el The target element.
* @param {Element} el The target element.
* @constructor
*/
function Progress(el) {

View File

@@ -1,9 +1,9 @@
---
layout: example.html
title: Vector Image Layer
shortdesc: Example of rendering vector data as an image layer.
title: Image Vector Layer
shortdesc: Example of an image vector layer.
docs: >
<p>This example uses <code>ol/layer/VectorImage</code> for faster rendering during interaction and animations, at the cost of less accurate rendering.</p>
<p>This example uses <code>ol/layer/Vector</code> with `renderMode: 'image'`. This mode results in faster rendering during interaction and animations, at the cost of less accurate rendering.</p>
tags: "vector, image"
---
<div id="map" class="map"></div>

View File

@@ -1,7 +1,6 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
import VectorImageLayer from '../src/ol/layer/VectorImage.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Fill, Stroke, Style, Text} from '../src/ol/style.js';
@@ -20,8 +19,8 @@ const style = new Style({
const map = new Map({
layers: [
new VectorImageLayer({
imageRatio: 2,
new VectorLayer({
renderMode: 'image',
source: new VectorSource({
url: 'data/geojson/countries.geojson',
format: new GeoJSON()

View File

@@ -0,0 +1,12 @@
---
layout: example.html
title: Layer Clipping with WebGL
shortdesc: Layer WebGL clipping example.
docs: >
This example shows how to use the <code>precompose</code> and <code>postcompose</code> rendering hooks to clip layers using WebGL.
tags: "clipping, webgl, openstreetmap"
---
<div id="map" class="map"></div>
<div id="no-webgl" class="alert alert-danger" style="display: none">
This example requires a browser that supports <a href="http://get.webgl.org/">WebGL</a>.
</div>

View File

@@ -0,0 +1,101 @@
import Map from '../src/ol/WebGLMap.js';
import View from '../src/ol/View.js';
import {WEBGL} from '../src/ol/has.js';
import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js';
if (!WEBGL) {
const info = document.getElementById('no-webgl');
/**
* display error message
*/
info.style.display = '';
} else {
const osm = new TileLayer({
source: new OSM()
});
const map = new Map({
layers: [osm],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
const fragmentShaderSource = [
'precision mediump float;',
'void main() {',
'}'
].join('');
const vertexShaderSource = [
'attribute vec2 a_position;',
'void main() {',
' gl_Position = vec4(a_position, 0, 1);',
'}'
].join('');
osm.on('precompose', function(event) {
const context = event.glContext;
const gl = context.getGL();
const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
context.useProgram(program);
const positionLocation = gl.getAttribLocation(program, 'a_position');
gl.enable(gl.STENCIL_TEST);
gl.colorMask(false, false, false, false);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
// first band
-1.0, -1.0, -0.75, -1.0, -1.0, 1.0,
-1.0, 1.0, -0.75, -1.0, -0.75, 1.0,
// second band
-0.5, -1.0, -0.25, -1.0, -0.5, 1.0,
-0.5, 1.0, -0.25, -1.0, -0.25, 1.0,
// third band
0.0, -1.0, 0.25, -1.0, 0.0, 1.0,
0.0, 1.0, 0.25, -1.0, 0.25, 1.0,
// forth band
0.5, -1.0, 0.75, -1.0, 0.5, 1.0,
0.5, 1.0, 0.75, -1.0, 0.75, 1.0
]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 24);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.deleteBuffer(buffer);
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.NOTEQUAL, 0, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
});
osm.on('postcompose', function(event) {
const context = event.glContext;
const gl = context.getGL();
gl.disable(gl.STENCIL_TEST);
});
}

View File

@@ -16,7 +16,7 @@ const map = new Map({
})
});
osm.on('prerender', function(event) {
osm.on('precompose', function(event) {
const ctx = event.context;
ctx.save();
const pixelRatio = event.frameState.pixelRatio;
@@ -38,7 +38,7 @@ osm.on('prerender', function(event) {
ctx.translate(-size[0] / 2 * pixelRatio, -size[1] / 2 * pixelRatio);
});
osm.on('postrender', function(event) {
osm.on('postcompose', function(event) {
const ctx = event.context;
ctx.restore();
});

View File

@@ -3,9 +3,9 @@ layout: example.html
title: Layer Spy
shortdesc: View a portion of one layer over another
docs: >
<p>Layer rendering can be manipulated in <code>prerender</code> and <code>postrender</code> event listeners.
<p>Layer rendering can be manipulated in <code>precompose</code> and <code>postcompose</code> event listeners.
These listeners get an event with a reference to the Canvas rendering context.
In this example, the <code>prerender</code> listener sets a clipping mask around the most
In this example, the <code>precompose</code> listener sets a clipping mask around the most
recent mouse position, giving you a spyglass effect for viewing one layer over another.</p>
<p>Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the spyglass size.</p>
tags: "spy, image manipulation"

View File

@@ -52,7 +52,7 @@ container.addEventListener('mouseout', function() {
});
// before rendering the layer, do some clipping
imagery.on('prerender', function(event) {
imagery.on('precompose', function(event) {
const ctx = event.context;
const pixelRatio = event.frameState.pixelRatio;
ctx.save();
@@ -69,7 +69,7 @@ imagery.on('prerender', function(event) {
});
// after rendering the layer, restore the canvas context
imagery.on('postrender', function(event) {
imagery.on('postcompose', function(event) {
const ctx = event.context;
ctx.restore();
});

View File

@@ -25,7 +25,7 @@ const map = new Map({
const swipe = document.getElementById('swipe');
bing.on('prerender', function(event) {
bing.on('precompose', function(event) {
const ctx = event.context;
const width = ctx.canvas.width * (swipe.value / 100);
@@ -35,7 +35,7 @@ bing.on('prerender', function(event) {
ctx.clip();
});
bing.on('postrender', function(event) {
bing.on('postcompose', function(event) {
const ctx = event.context;
ctx.restore();
});

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Magnify
shortdesc: Show a magnified version of imager under the pointer
docs: >
<p>This example makes use of the <code>postrender</code> event listener to
<p>This example makes use of the <code>postcompose</code> event listener to
oversample imagery in a circle around the pointer location. Listeners for this event have access to the Canvas context and can manipulate image data.</p>
<p>Move around the map to see the effect. Use the ↑ up and ↓ down arrow keys to adjust the magnified circle size.</p>
tags: "magnify, image manipulation"

View File

@@ -3,7 +3,6 @@ import View from '../src/ol/View.js';
import TileLayer from '../src/ol/layer/Tile.js';
import {fromLonLat} from '../src/ol/proj.js';
import BingMaps from '../src/ol/source/BingMaps.js';
import {getRenderPixel} from '../src/ol/render.js';
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
@@ -49,17 +48,16 @@ container.addEventListener('mouseout', function() {
});
// after rendering the layer, show an oversampled version around the pointer
imagery.on('postrender', function(event) {
imagery.on('postcompose', function(event) {
if (mousePosition) {
const pixel = getRenderPixel(event, mousePosition);
const offset = getRenderPixel(event, [mousePosition[0] + radius, mousePosition[1]]);
const half = Math.sqrt(Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2));
const context = event.context;
const centerX = pixel[0];
const centerY = pixel[1];
const pixelRatio = event.frameState.pixelRatio;
const half = radius * pixelRatio;
const centerX = mousePosition[0] * pixelRatio;
const centerY = mousePosition[1] * pixelRatio;
const originX = centerX - half;
const originY = centerY - half;
const size = Math.round(2 * half + 1);
const size = 2 * half + 1;
const sourceData = context.getImageData(originX, originY, size, size).data;
const dest = context.createImageData(size, size);
const destData = dest.data;
@@ -84,7 +82,7 @@ imagery.on('postrender', function(event) {
}
context.beginPath();
context.arc(centerX, centerY, half, 0, 2 * Math.PI);
context.lineWidth = 3 * half / radius;
context.lineWidth = 3 * pixelRatio;
context.strokeStyle = 'rgba(255,255,255,0.5)';
context.putImageData(dest, originX, originY);
context.stroke();

View File

@@ -1,14 +0,0 @@
---
layout: example.html
title: Mapbox-gl Layer
shortdesc: Example of a Mapbox-gl-js layer integration.
docs: >
Show how to add a mapbox-gl-js layer in an openlayers map. **Note**: Make sure to get your own Mapbox API key when using this example. No map will be visible when the API key has expired.
tags: "simple, mapbox, vector, tiles"
resources:
- https://unpkg.com/mapbox-gl@0.51.0/dist/mapbox-gl.js
cloak:
- key: ER67WIiPdCQvhgsUjoWK
value: Your Mapbox access token from http://mapbox.com/ here
---
<div id="map" class="map"></div>

View File

@@ -1,218 +0,0 @@
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import Layer from '../src/ol/layer/Layer';
import {assign} from '../src/ol/obj';
import {getTransform} from '../src/ol/proj';
import SourceState from '../src/ol/source/State';
import {Stroke, Style} from '../src/ol/style.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
class Mapbox extends Layer {
/**
* @param {import('./Base.js').Options} options Layer options.
*/
constructor(options) {
const baseOptions = assign({}, options);
super(baseOptions);
this.baseOptions = baseOptions;
/**
* @private
* @type boolean
*/
this.loaded = false;
this.initMap();
}
initMap() {
const map = this.map_;
const view = map.getView();
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
const center = transformToLatLng(view.getCenter());
this.centerLastRender = view.getCenter();
this.zoomLastRender = view.getZoom();
this.centerLastRender = view.getCenter();
this.zoomLastRender = view.getZoom();
const options = assign(this.baseOptions, {
attributionControl: false,
boxZoom: false,
center,
container: map.getTargetElement(),
doubleClickZoom: false,
dragPan: false,
dragRotate: false,
interactive: false,
keyboard: false,
pitchWithRotate: false,
scrollZoom: false,
touchZoomRotate: false,
zoom: view.getZoom() - 1
});
this.mbmap = new mapboxgl.Map(options);
this.mbmap.on('load', function() {
this.mbmap.getCanvas().remove();
this.loaded = true;
this.map_.render();
[
'mapboxgl-control-container'
].forEach(className => document.getElementsByClassName(className)[0].remove());
}.bind(this));
this.mbmap.on('render', function() {
// Reset offset
if (this.centerNextRender) {
this.centerLastRender = this.centerNextRender;
}
if (this.zoomNextRender) {
this.zoomLastRender = this.zoomNextRender;
}
this.updateRenderedPosition([0, 0], 1);
}.bind(this));
}
/**
*
* @inheritDoc
*/
render(frameState) {
const map = this.map_;
const view = map.getView();
const transformToLatLng = getTransform(view.getProjection(), 'EPSG:4326');
this.centerNextRender = view.getCenter();
const lastRender = map.getPixelFromCoordinate(this.centerLastRender);
const nextRender = map.getPixelFromCoordinate(this.centerNextRender);
const centerOffset = [lastRender[0] - nextRender[0], lastRender[1] - nextRender[1]];
this.zoomNextRender = view.getZoom();
const zoomOffset = Math.pow(2, this.zoomNextRender - this.zoomLastRender);
this.updateRenderedPosition(centerOffset, zoomOffset);
const rotation = frameState.viewState.rotation;
if (rotation) {
this.mbmap.rotateTo(-rotation * 180 / Math.PI, {
animate: false
});
}
// Re-render mbmap
const center = transformToLatLng(this.centerNextRender);
const zoom = view.getZoom() - 1;
this.mbmap.jumpTo({
center: center,
zoom: zoom
});
return this.mbmap.getCanvas();
}
updateRenderedPosition(centerOffset, zoomOffset) {
const style = this.mbmap.getCanvas().style;
style.left = Math.round(centerOffset[0]) + 'px';
style.top = Math.round(centerOffset[1]) + 'px';
style.transform = 'scale(' + zoomOffset + ')';
}
setVisible(visible) {
super.setVisible(visible);
const canvas = this.mbmap.getCanvas();
canvas.style.display = visible ? 'block' : 'none';
}
setOpacity(opacity) {
super.setOpacity(opacity);
const canvas = this.mbmap.getCanvas();
canvas.style.opacity = opacity;
}
setZIndex(zindex) {
super.setZIndex(zindex);
const canvas = this.mbmap.getCanvas();
canvas.style.zIndex = zindex;
}
/**
* @inheritDoc
*/
getSourceState() {
return this.loaded ? SourceState.READY : SourceState.UNDEFINED;
}
setMap(map) {
this.map_ = map;
}
}
mapboxgl.Map.prototype._setupContainer = function _setupContainer() {
const container = this._container;
container.classList.add('mapboxgl-map');
const canvasContainer = this._canvasContainer = container.firstChild;
this._canvas = document.createElement('canvas');
canvasContainer.insertBefore(this._canvas, canvasContainer.firstChild);
this._canvas.style.position = 'absolute';
this._canvas.addEventListener('webglcontextlost', this._contextLost, false);
this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false);
this._canvas.setAttribute('tabindex', '0');
this._canvas.setAttribute('aria-label', 'Map');
this._canvas.className = 'mapboxgl-canvas';
const dimensions = this._containerDimensions();
this._resizeCanvas(dimensions[0], dimensions[1]);
this._controlContainer = canvasContainer;
const controlContainer = this._controlContainer = document.createElement('div');
controlContainer.className = 'mapboxgl-control-container';
container.appendChild(controlContainer);
const positions = this._controlPositions = {};
['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function(positionName) {
const elem = document.createElement('div');
elem.className = 'mapboxgl-ctrl-' + positionName;
controlContainer.appendChild(elem);
positions[positionName] = elem;
});
};
const style = new Style({
stroke: new Stroke({
color: '#319FD3',
width: 2
})
});
const vectorLayer = new VectorLayer({
source: new VectorSource({
url: 'data/geojson/countries.geojson',
format: new GeoJSON()
}),
style: style
});
const map = new Map({
target: 'map',
view: new View({
center: [-10997148, 4569099],
zoom: 4
})
});
const key = 'ER67WIiPdCQvhgsUjoWK';
const mbLayer = new Mapbox({
map: map,
container: map.getTarget(),
style: 'https://maps.tilehosting.com/styles/bright/style.json?key=' + key
});
map.addLayer(mbLayer);
map.addLayer(vectorLayer);

View File

@@ -1,32 +0,0 @@
---
layout: example-verbatim.html
title: Vector tiles created from a Mapbox Style object
shortdesc: Example of using ol-mapbox-style with tiles from tilehosting.com.
tags: "vector tiles, mapbox style, ol-mapbox-style"
cloak:
- key: lirfd6Fegsjkvs0lshxe
value: Your API key from http://tilehosting.com/ here
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>Mapbox Style objects with ol-mapbox-style</title>
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<style type="text/css">
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script src="common.js"></script>
<script src="mapbox-style.js"></script>
</body>
</html>

View File

@@ -1,3 +0,0 @@
import apply from 'ol-mapbox-style';
apply('map', 'https://maps.tilehosting.com/styles/topo/style.json?key=ER67WIiPdCQvhgsUjoWK');

View File

@@ -21,7 +21,7 @@ function tileUrlFunction(tileCoord) {
'{z}/{x}/{y}.vector.pbf?access_token=' + key)
.replace('{z}', String(tileCoord[0] * 2 - 1))
.replace('{x}', String(tileCoord[1]))
.replace('{y}', String(tileCoord[2]))
.replace('{y}', String(-tileCoord[2] - 1))
.replace('{a-d}', 'abcd'.substr(
((tileCoord[1] << tileCoord[0]) + tileCoord[2]) % 4, 1));
}

View File

@@ -38,35 +38,35 @@ const vector = new VectorLayer({
/**
* Currently drawn feature.
* @type {import("../src/ol/Feature.js").default}
* @type {module:ol/Feature~Feature}
*/
let sketch;
/**
* The help tooltip element.
* @type {HTMLElement}
* @type {Element}
*/
let helpTooltipElement;
/**
* Overlay to show the help messages.
* @type {Overlay}
* @type {module:ol/Overlay}
*/
let helpTooltip;
/**
* The measure tooltip element.
* @type {HTMLElement}
* @type {Element}
*/
let measureTooltipElement;
/**
* Overlay to show the measurement.
* @type {Overlay}
* @type {module:ol/Overlay}
*/
let measureTooltip;
@@ -87,7 +87,7 @@ const continueLineMsg = 'Click to continue drawing the line';
/**
* Handle pointer move.
* @param {import("../src/ol/MapBrowserEvent").default} evt The event.
* @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt The event.
*/
const pointerMoveHandler = function(evt) {
if (evt.dragging) {
@@ -97,7 +97,7 @@ const pointerMoveHandler = function(evt) {
let helpMsg = 'Click to start drawing';
if (sketch) {
const geom = sketch.getGeometry();
const geom = (sketch.getGeometry());
if (geom instanceof Polygon) {
helpMsg = continuePolygonMsg;
} else if (geom instanceof LineString) {
@@ -134,7 +134,7 @@ let draw; // global so we can remove it later
/**
* Format length output.
* @param {LineString} line The line.
* @param {module:ol/geom/LineString~LineString} line The line.
* @return {string} The formatted length.
*/
const formatLength = function(line) {
@@ -153,7 +153,7 @@ const formatLength = function(line) {
/**
* Format area output.
* @param {Polygon} polygon The polygon.
* @param {module:ol/geom/Polygon~Polygon} polygon The polygon.
* @return {string} Formatted area.
*/
const formatArea = function(polygon) {
@@ -205,7 +205,7 @@ function addInteraction() {
// set sketch
sketch = evt.feature;
/** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */
/** @type {module:ol/coordinate~Coordinate|undefined} */
let tooltipCoord = evt.coordinate;
listener = sketch.getGeometry().on('change', function(evt) {
@@ -221,7 +221,7 @@ function addInteraction() {
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(tooltipCoord);
});
});
}, this);
draw.on('drawend',
function() {
@@ -233,7 +233,7 @@ function addInteraction() {
measureTooltipElement = null;
createMeasureTooltip();
unByKey(listener);
});
}, this);
}

View File

@@ -3,8 +3,7 @@ layout: example.html
title: Overview Map Control
shortdesc: Example of OverviewMap control.
docs: >
This example demonstrates the use of the OverviewMap control. Both the main map and the overview map are configured with layers using the same source.
Please note that explicitly configuring layers for the overview map is mandatory.
This example demonstrates the use of the OverviewMap control.
tags: "overview, overviewmap"
---
<div id="map" class="map"></div>

View File

@@ -4,22 +4,13 @@ import {defaults as defaultControls, OverviewMap} from '../src/ol/control.js';
import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js';
const source = new OSM();
const overviewMapControl = new OverviewMap({
layers: [
new TileLayer({
source: source
})
]
});
const map = new Map({
controls: defaultControls().extend([
overviewMapControl
new OverviewMap()
]),
layers: [
new TileLayer({
source: source
source: new OSM()
})
],
target: 'map',

View File

@@ -109,7 +109,7 @@ fetch(url).then(function(response) {
options.projection = 'EPSG:3413';
options.wrapX = false;
layers['wmts3413'] = new TileLayer({
source: new WMTS(options)
source: new WMTS(/** @type {!module:ol/source/WMTS~Options} */ (options))
});
});

View File

@@ -1,46 +1,42 @@
(function() {
function compress(json) {
return LZString.compressToBase64(JSON.stringify(json))
.replace(/\+/g, `-`)
.replace(/\//g, `_`)
.replace(/=+$/, ``);
}
var htmlClipboard = new Clipboard('#copy-html-button');
htmlClipboard.on('success', function(e) {
e.clearSelection();
});
var jsClipboard = new Clipboard('#copy-js-button');
jsClipboard.on('success', function(e) {
e.clearSelection();
});
var pkgClipboard = new Clipboard('#copy-pkg-button');
pkgClipboard.on('success', function(e) {
var clipboard = new Clipboard('#copy-button');
clipboard.on('success', function(e) {
e.clearSelection();
});
var codepenButton = document.getElementsByClassName('codepen-button')[0];
var codepenButton = document.getElementById('codepen-button');
if (codepenButton) {
codepenButton.onclick = function(event) {
event.preventDefault();
var form = document.getElementById('codepen-form');
const html = document.getElementById('example-html-source').innerText;
const js = document.getElementById('example-js-source').innerText;
const pkgJson = document.getElementById('example-pkg-source').innerText;
form.parameters.value = compress({
files: {
'index.html': {
content: html
},
'index.js': {
content: js
},
"package.json": {
content: pkgJson
}
}
});
// Doc : https://blog.codepen.io/documentation/api/prefill/
var resources = form.resources.value.split(',');
var data = {
title: form.title.value,
description: form.description.value,
layout: 'left',
html: form.html.value,
css: form.css.value,
js: form.js.value,
css_external: resources.filter(function(resource) {
return resource.lastIndexOf('.css') === resource.length - 4;
}).join(';'),
js_external: resources.filter(function(resource) {
return resource.lastIndexOf('.js') === resource.length - 3;
}).join(';')
};
// binary flags to display html, css, js and/or console tabs
data.editors = '' + Number(data.html.length > 0) +
Number(data.css.length > 0) +
Number(data.js.length > 0) +
Number(data.js.indexOf('console') > 0);
form.data.value = JSON.stringify(data);
form.submit();
};
}

View File

@@ -91,27 +91,22 @@ pre[class*="language-"] {
background: #FFFFFF;
}
pre>legend {
font-size: 100%;
font-weight: bold;
}
.source-controls {
#source-controls {
position: absolute;
margin-top: 10px;
margin-top: 20px;
right: 40px;
}
.source-controls a {
#source-controls a {
margin-left: 15px;
}
.copy-button {
#copy-button {
text-decoration: none;
cursor: pointer;
}
.codepen-button {
#codepen-button {
text-decoration: none;
cursor: pointer;
}

View File

@@ -14,19 +14,3 @@ tags: "scale-line, openstreetmap"
<option value="nautical">nautical mile</option>
<option value="metric" selected>metric</option>
</select>
<select id="type">
<option value="scaleline">ScaleLine</option>
<option value="scalebar">ScaleBar</option>
</select>
<select id="steps" style="display:none">
<option value=2>2 steps</option>
<option value=4 selected>4 steps</option>
<option value=6>6 steps</option>
<option value=8>8 steps</option>
</select>
<div id="showScaleTextDiv" style="display:none">
<input type="checkbox" id="showScaleText" checked>Show scale text
</div>

View File

@@ -4,36 +4,12 @@ import {defaults as defaultControls, ScaleLine} from '../src/ol/control.js';
import TileLayer from '../src/ol/layer/Tile.js';
import OSM from '../src/ol/source/OSM.js';
const unitsSelect = document.getElementById('units');
const typeSelect = document.getElementById('type');
const stepsSelect = document.getElementById('steps');
const scaleTextCheckbox = document.getElementById('showScaleText');
const showScaleTextDiv = document.getElementById('showScaleTextDiv');
let scaleType = 'scaleline';
let scaleBarSteps = 4;
let scaleBarText = true;
let control;
const scaleLineControl = new ScaleLine();
function scaleControl() {
if (scaleType === 'scaleline') {
control = new ScaleLine({
units: unitsSelect.value
});
return control;
}
control = new ScaleLine({
units: unitsSelect.value,
bar: true,
steps: scaleBarSteps,
text: scaleBarText,
minWidth: 140
});
return control;
}
const map = new Map({
controls: defaultControls().extend([
scaleControl()
scaleLineControl
]),
layers: [
new TileLayer({
@@ -47,34 +23,10 @@ const map = new Map({
})
});
const unitsSelect = document.getElementById('units');
function onChange() {
control.setUnits(unitsSelect.value);
}
function onChangeType() {
scaleType = typeSelect.value;
if (typeSelect.value === 'scalebar') {
stepsSelect.style.display = 'inline';
showScaleTextDiv.style.display = 'inline';
map.removeControl(control);
map.addControl(scaleControl());
} else {
stepsSelect.style.display = 'none';
showScaleTextDiv.style.display = 'none';
map.removeControl(control);
map.addControl(scaleControl());
}
}
function onChangeSteps() {
scaleBarSteps = parseInt(stepsSelect.value, 10);
map.removeControl(control);
map.addControl(scaleControl());
}
function onChangeScaleText() {
scaleBarText = scaleTextCheckbox.checked;
map.removeControl(control);
map.addControl(scaleControl());
scaleLineControl.setUnits(unitsSelect.value);
}
unitsSelect.addEventListener('change', onChange);
typeSelect.addEventListener('change', onChangeType);
stepsSelect.addEventListener('change', onChangeSteps);
scaleTextCheckbox.addEventListener('change', onChangeScaleText);
onChange();

View File

@@ -2,7 +2,7 @@ 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';
import {fromLonLat} from '../src/ol/proj.js';
import {Raster as RasterSource, TileJSON} from '../src/ol/source.js';
import RasterSource from '../src/ol/source/Raster.js';
import XYZ from '../src/ol/source/XYZ.js';
function flood(pixels, data) {
@@ -37,9 +37,8 @@ const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new TileJSON({
url: 'https://api.tiles.mapbox.com/v3/mapbox.world-light.json?secure',
crossOrigin: 'anonymous'
source: new XYZ({
url: 'https://api.mapbox.com/styles/v1/tschaub/ciutc102t00c62js5fqd47kqw/tiles/256/{z}/{x}/{y}?access_token=' + key
})
}),
new ImageLayer({

View File

@@ -1,3 +0,0 @@
.bw {
filter: grayscale(100%);
}

View File

@@ -3,7 +3,7 @@ layout: example.html
title: Semi-Transparent Layer
shortdesc: Example of a map with a semi-transparent layer.
docs: >
This example will display a tiled MaxBox layer semi-transparently over an OSM background. The OSM layer is changed to back and white by using a CSS filter.
This example will display a tiled MaxBox layer semi-transparently over an OSM background.
tags: "transparent, osm, tilejson"
---
<div id="map" class="map"></div>

View File

@@ -9,7 +9,6 @@ import TileJSON from '../src/ol/source/TileJSON.js';
const map = new Map({
layers: [
new TileLayer({
className: 'bw',
source: new OSM()
}),
new TileLayer({

View File

@@ -0,0 +1,7 @@
@media (min-width: 800px) {
.half {
padding: 0 10px;
width: 50%;
float: left;
}
}

View File

@@ -0,0 +1,16 @@
---
layout: example.html
title: Shared Views
shortdesc: Two maps with different renderers share view properties
docs: >
Two maps (one with the Canvas renderer, one with the WebGL renderer) share the same center, resolution, rotation and layers.
tags: "side-by-side, canvas, webgl"
---
<div class="half">
<h4>Canvas</h4>
<div id="canvasMap" class="map"></div>
</div>
<div class="half">
<h4>WebGL</h4>
<div id="webglMap" class="map"></div>
</div>

26
examples/side-by-side.js Normal file
View File

@@ -0,0 +1,26 @@
import Map from '../src/ol/Map.js';
import WebGLMap from '../src/ol/WebGLMap.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 layer = new TileLayer({
source: new OSM()
});
const view = new View({
center: [0, 0],
zoom: 1
});
const map1 = new Map({
target: 'canvasMap',
layers: [layer],
view: view
});
const map2 = new WebGLMap({
target: 'webglMap',
layers: [layer],
view: view
});

View File

@@ -1,9 +1,9 @@
---
layout: example.html
title: Sphere Mollweide
shortdesc: Example of a Sphere Mollweide map with a Graticule layer.
shortdesc: Example of a Sphere Mollweide map with a Graticule component.
docs: >
Example of a Sphere Mollweide map with a Graticule layer.
Example of a Sphere Mollweide map with a Graticule component.
tags: "graticule, Mollweide, projection, proj4js"
---
<div id="map" class="map"></div>

View File

@@ -1,4 +1,4 @@
import Graticule from '../src/ol/layer/Graticule.js';
import Graticule from '../src/ol/Graticule.js';
import Map from '../src/ol/Map.js';
import View from '../src/ol/View.js';
import GeoJSON from '../src/ol/format/GeoJSON.js';
@@ -30,13 +30,17 @@ const map = new Map({
url: 'data/geojson/countries-110m.geojson',
format: new GeoJSON()
})
}),
new Graticule()
})
],
target: 'map',
view: new View({
center: [0, 0],
projection: sphereMollweideProjection,
resolutions: [65536, 32768, 16384, 8192, 4096, 2048],
zoom: 0
})
});
new Graticule({
map: map
});

View File

@@ -0,0 +1,14 @@
---
layout: example.html
title: Symbols with WebGL
shortdesc: Using symbols in an atlas with WebGL.
docs: >
<p>When using symbol styles with WebGL, OpenLayers would render the symbol
on a temporary image and would create a WebGL texture for each image. For a
better performance, it is recommended to use atlas images (similar to
image sprites with CSS), so that the number of textures is reduced. OpenLayers
provides an <code>AtlasManager</code>, which when passed to the constructor
of a symbol style, will create atlases for the symbols.</p>
tags: "webgl, symbol, atlas, vector, point"
---
<div id="map" class="map"></div>

View File

@@ -0,0 +1,111 @@
import Feature from '../src/ol/Feature.js';
import Map from '../src/ol/WebGLMap.js';
import View from '../src/ol/View.js';
import Point from '../src/ol/geom/Point.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {AtlasManager, Circle as CircleStyle, Fill, RegularShape, Stroke, Style} from '../src/ol/style.js';
const atlasManager = new AtlasManager({
// we increase the initial size so that all symbols fit into
// a single atlas image
initialSize: 512
});
const symbolInfo = [{
opacity: 1.0,
scale: 1.0,
fillColor: 'rgba(255, 153, 0, 0.4)',
strokeColor: 'rgba(255, 204, 0, 0.2)'
}, {
opacity: 0.75,
scale: 1.25,
fillColor: 'rgba(70, 80, 224, 0.4)',
strokeColor: 'rgba(12, 21, 138, 0.2)'
}, {
opacity: 0.5,
scale: 1.5,
fillColor: 'rgba(66, 150, 79, 0.4)',
strokeColor: 'rgba(20, 99, 32, 0.2)'
}, {
opacity: 1.0,
scale: 1.0,
fillColor: 'rgba(176, 61, 35, 0.4)',
strokeColor: 'rgba(145, 43, 20, 0.2)'
}];
const radiuses = [3, 6, 9, 15, 19, 25];
const symbolCount = symbolInfo.length * radiuses.length * 2;
const symbols = [];
let i, j;
for (i = 0; i < symbolInfo.length; ++i) {
const info = symbolInfo[i];
for (j = 0; j < radiuses.length; ++j) {
// circle symbol
symbols.push(new CircleStyle({
opacity: info.opacity,
scale: info.scale,
radius: radiuses[j],
fill: new Fill({
color: info.fillColor
}),
stroke: new Stroke({
color: info.strokeColor,
width: 1
}),
// by passing the atlas manager to the symbol,
// the symbol will be added to an atlas
atlasManager: atlasManager
}));
// star symbol
symbols.push(new RegularShape({
points: 8,
opacity: info.opacity,
scale: info.scale,
radius: radiuses[j],
radius2: radiuses[j] * 0.7,
angle: 1.4,
fill: new Fill({
color: info.fillColor
}),
stroke: new Stroke({
color: info.strokeColor,
width: 1
}),
atlasManager: atlasManager
}));
}
}
const featureCount = 50000;
const features = new Array(featureCount);
let feature, geometry;
const e = 25000000;
for (i = 0; i < featureCount; ++i) {
geometry = new Point(
[2 * e * Math.random() - e, 2 * e * Math.random() - e]);
feature = new Feature(geometry);
feature.setStyle(
new Style({
image: symbols[i % symbolCount]
})
);
features[i] = feature;
}
const vectorSource = new VectorSource({
features: features
});
const vector = new VectorLayer({
source: vectorSource
});
const map = new Map({
layers: [vector],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
zoom: 4
})
});

View File

@@ -5,7 +5,6 @@ import {LineString, Point} from '../src/ol/geom.js';
import VectorLayer from '../src/ol/layer/Vector.js';
import VectorSource from '../src/ol/source/Vector.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
import {getVectorContext} from '../src/ol/render.js';
const count = 20000;
@@ -105,8 +104,8 @@ const style = new Style({
})
});
vector.on('postrender', function(evt) {
const vectorContext = getVectorContext(evt);
map.on('postcompose', function(evt) {
const vectorContext = evt.vectorContext;
vectorContext.setStyle(style);
if (point !== null) {
vectorContext.drawGeometry(point);

View File

@@ -1,63 +1,12 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<script>
var gaProperty = 'UA-2577926-1';
// Disable tracking if the opt-out cookie exists.
var disableStr = 'ga-disable-' + gaProperty;
if (document.cookie.indexOf(disableStr + '=true') > -1) {
window[disableStr] = true;
}
function gaOptout() {
document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
window[disableStr] = true;
}
function gaOptoutRevoke() {
document.cookie = disableStr + '=false; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
window[disableStr] = false;
}
</script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-2577926-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-2577926-1', { 'anonymize_ip': true });
</script>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js"></script>
<script src="https://unpkg.com/lz-string@1.4.4/libs/lz-string.min.js"></script>
<script>
window.addEventListener("load", function() {
window.cookieconsent.initialise({
'palette': {
'popup': {
'background': '#eaf7f7',
'text': '#5c7291'
},
'button': {
'background': '#56cbdb',
'text': '#ffffff'
}
},
'theme': 'edgeless',
'type': 'opt-out',
'onInitialise': function (status) {
if (!this.hasConsented()) {
gaOptout()
}
},
'onStatusChange': function(status, chosenBefore) {
if (!this.hasConsented()) {
gaOptout()
}
},
'onRevokeChoice': function() {
gaOptoutRevoke()
}
})
});
gtag('config', 'UA-2577926-1');
</script>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
@@ -100,14 +49,10 @@
</div>
<div class="row-fluid">
<a class="codepen-button pull-right"><i class="fa fa-codepen"></i> Edit</a>
<div class="span12">
<h4 id="title">{{ title }}</h4>
{{{ contents }}}
</div>
<form method="POST" id="codepen-form" target="_blank" action="https://codesandbox.io/api/v1/sandboxes/define">
<input id="codesandbox-params" type="hidden" name="parameters">
</form>
</div>
<div class="row-fluid">
@@ -118,37 +63,36 @@
</div>
<div class="row-fluid">
<div class="source-controls">
<a class="copy-button" id="copy-html-button" data-clipboard-target="#example-html-source"><i class="fa fa-clipboard"></i> Copy</a>
<div id="source-controls">
<a id="copy-button" data-clipboard-target="#example-source"><i class="fa fa-clipboard"></i> Copy</a>
<!-- <a id="codepen-button"><i class="fa fa-codepen"></i> Edit</a> -->
</div>
<pre><legend>index.html</legend><code id="example-html-source" class="language-markup">&lt;!DOCTYPE html&gt;
<form method="POST" id="codepen-form" target="_blank" action="https://codepen.io/pen/define/">
<textarea class="hidden" name="title">{{ title }}</textarea>
<textarea class="hidden" name="description">{{ shortdesc }}</textarea>
<textarea class="hidden" name="js">{{ js.source }}</textarea>
<textarea class="hidden" name="css">{{ css.source }}</textarea>
<textarea class="hidden" name="html">{{ contents }}</textarea>
<input type="hidden" name="data">
</form>
<pre><code id="example-source" class="language-markup">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{ title }}&lt;/title&gt;
&lt;link rel="stylesheet" href="https://openlayers.org/en/v{{ olVersion }}/css/ol.css" type="text/css"&gt;
&lt;!-- The line below is only needed for old environments like Internet Explorer and Android 4.x --&gt;
&lt;script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"&gt;&lt;/script&gt;{{#if extraHead.remote}}
&lt;script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"&gt;&lt;/script&gt;
{{#if extraHead.remote}}
{{ indent extraHead.remote spaces=4 }}{{/if}}{{#if css.source}}
&lt;style&gt;
{{ indent css.source spaces=6 }} &lt;/style&gt;{{/if}}
&lt;/head&gt;
&lt;body&gt;
{{ indent contents spaces=4 }} &lt;script src="index.js"&gt;&lt;/script&gt;
{{ indent contents spaces=4 }} &lt;script&gt;
{{ indent js.source spaces=6 }} &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</div>
<div class="row-fluid">
<div class="source-controls">
<a class="copy-button" id="copy-js-button" data-clipboard-target="#example-js-source"><i class="fa fa-clipboard"></i> Copy</a>
</div>
<pre><legend>index.js</legend><code id="example-js-source" class="language-js">import 'ol/ol.css';
{{ js.source }}</code></pre>
</div>
<div class="row-fluid">
<div class="source-controls">
<a class="copy-button" id="copy-pkg-button" data-clipboard-target="#example-pkg-source"><i class="fa fa-clipboard"></i> Copy</a>
</div>
<pre><legend>package.json</legend><code id="example-pkg-source" class="language-js">{{ pkgJson }}</code></pre>
</div>
</div>
<script src="./resources/common.js"></script>

View File

@@ -6,7 +6,7 @@ import TileJSON from '../src/ol/source/TileJSON.js';
/**
* Renders a progress bar.
* @param {HTMLElement} el The target element.
* @param {Element} el The target element.
* @constructor
*/
function Progress(el) {

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