simplified publishing script and added sample (build dir) npm module from the project

This commit is contained in:
darkscript 2018-02-17 18:16:06 +03:00
parent 77c3629704
commit 24b48bb277
137 changed files with 22964 additions and 25 deletions

View File

@ -18,7 +18,7 @@ This page describes what you need to know to contribute code to OpenLayers as a
## Contributor License Agreement
Your contribution will be under our [license](LICENCE.md)
Your contribution will be under our [license](LICENSE.md)
as per [GitHub's terms of service](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license).
The CeCILL licence is a french BSD licence.

5
build/.npmignore Normal file
View File

@ -0,0 +1,5 @@
# ignore examples
examples
img
# ignore doc pages
doc/doc-pages

29
build/CHANGELOG.md Normal file
View File

@ -0,0 +1,29 @@
# Change log
## v1.1.3 2018-02-07
This is the last v1 release.
- Next release (v2) will use ES6 module syntax [#33](https://github.com/Viglino/ol3-ext/issues/33).
- Switch to the `./dist/ol-ext.js` to keep on running on next version.
## v1.1.2 2017-12
**change project name ol-ext is now ol-ext**
- add doc-pages [#53](https://github.com/Viglino/ol3-ext/issues/53)
- see [#65](https://github.com/Viglino/ol3-ext/issues/65)
## v1.0.0 2016-11-12
see [#8](https://github.com/Viglino/ol3-ext/issues/8) and [#10](https://github.com/Viglino/ol3-ext/issues/10)
- `ol.control.Toggle` inherits from `ol.control.Button` (this means you have to add the ol.control.Button.js to your pages).
- Move subbar from `ol.control.Bar` to `ol.control.Toggle`.
Instead of:
```javascript
var c = new ol.control.Toggle ();
bar.addControl (c, subbar);
```
use:
```javascript
var c = new ol.control.Toggle ({ bar: subbar });
bar.addControl (c);
```
- add `autoActive` option to `ol.control.Toggle` to auto activate the control when inserted in a subbar
- add `autoDeactivate` option to `ol.control.Bar` to auto deactivate all controls in a subbar when desactivating it

32
build/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,32 @@
# Contributing to ol-ext
Thanks for your interest in contributing to ol-ext.
## Submitting Bug Reports or Asking Questions
Please use the [GitHub issue tracker](https://github.com/Viglino/ol-ext/issues).
Before creating a new issue, do a quick search to see if the problem has been reported already.
## Contributing Code
See [`DEVELOPING.md`](DEVELOPING.md) to learn how to get started developing.
Clone the repository and [pull requests](https://help.github.com/articles/using-pull-requests). Make sure
that your pull request follows our pull request guidelines below before submitting it.
This page describes what you need to know to contribute code to OpenLayers as a developer.
## Contributor License Agreement
Your contribution will be under our [license](LICENCE.md)
as per [GitHub's terms of service](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license).
The CeCILL licence is a french BSD licence.
## Pull request guidelines
Your pull request must:
* Follow the naming convention in the [DEVELOPING.md](DEVELOPING.md)
* Address a single issue or add a single item of functionality.
* Use clear commit messages.
* Be possible to merge automatically.

77
build/DEVELOPING.md Normal file
View File

@ -0,0 +1,77 @@
# Developing
## Setting up development environment
You will obviously start by [forking](https://github.com/openlayers/openlayers/fork) the OpenLayers repository.
### Install the dependencies
Go in the project directory and run the `npm install` that wil install the dependencies in the local node_modules folder.
### Creating the distribution
Since v.2 the extensions are provided as ES6 modules.
To be used in a web page you have to create the distribution.
Use the gulp command to create a distribution of the project into the `/dist` directory:
````
gulp
````
To recreate the distribution on `js` file change, use the watch task
````
gulp watch
````
## Adding new extensions
To ensure the correct translation beetween the modules and the distribution on ol classes:
- Export one class per file as default
- Use the naming convention
### Naming convention
To ensure the correct translation beetween the modules and the distribution on ol classes, we use the follownig naming convention.
In Openlayers classes just replace the `point` by a `underscore`.
- Thus the `ol.layer.Vector` class must be imported as `ol_layer_Vector`.
- A new control `ol.control.MyControl` must be declared as `ol_control_MyControl`
The file name must reflect the name of the extension and should be placed in the src directory corresponding to its namespace.
Thus `ol_control_MyControl`must be created in the `./src/control/MyControl.js` file and can be used in a webpack as:
````javascript
import ol_control_MyControl from 'ol-ext/control/MyControl';
````
Example:
````javascript
// Import ol classes
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
// Create my control
var ol_control_MyControl = function(options) {
ol_control_Control.call(this,options);
}
ol.inherits(ol_control_MyControl, ol_control_Control);
// Export my control
export default ol_control_MyControl
````
## Building the documentation:
The documentation use [gulp-jsdoc3](https://www.npmjs.com/package/gulp-jsdoc3) to create the doc.
1. install the gulp-jsdoc3 project at the root directory:
````
npm install gulp-jsdoc3
````
2. then run the gulp command to create the doc in the [doc/doc-pages](http://viglino.github.io/ol-ext/doc/doc-pages/) directory:
````
gulp doc
````

44
build/LICENCE.md Normal file
View File

@ -0,0 +1,44 @@
# LICENCE
ol-ext (c) 2016-2018 - Jean-Marc Viglino, IGN-France
[ol-ext](https://github.com/Viglino/ol-ext) is licenced under the French Opensource **BSD** compatible CeCILL-B FREE SOFTWARE LICENSE.
Some resources (mapping services and API) used in this sofware may have a specific license.
You must check before use.
Full text license in English: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
Full text license in French: http://www.cecill.info/licences/Licence_CeCILL-C_V1-fr.txt
## CeCILL-B FREE SOFTWARE LICENSE AGREEMENT :
This Agreement is an open source software license intended to give users
significant freedom to modify and redistribute the software licensed
hereunder.
The exercising of this freedom is conditional upon a strong obligation
of giving credits for everybody that distributes a software
incorporating a software ruled by the current license so as all
contributions to be properly identified and acknowledged.
In consideration of access to the source code and the rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the
suitability of the software as regards their requirements in conditions
enabling the security of their systems and/or data to be ensured and,
more generally, to use and operate it in the same conditions of
security. This Agreement may be freely reproduced and published,
provided it is not altered, and that no provisions are either added or
removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.

90
build/README.md Normal file
View File

@ -0,0 +1,90 @@
# ol-ext
*Cool extensions for [OpenLayers](https://github.com/openlayers/openlayers) (ol)*.
[ol-ext](https://github.com/Viglino/ol-ext) is a set of extensions, controls, interactions to use with Openlayers.
[View live examples online](http://viglino.github.io/ol-ext/) or the [API documentation](http://viglino.github.io/ol-ext/doc/doc-pages/).
### ! ol3-ext is now [ol-ext](https://github.com/Viglino/ol-ext) !
ol3-ext has been renamed to ol-ext and is [now available on NPM](https://www.npmjs.com/package/ol-ext): **update your bookmark and your code**.
**Keywords:** CSS popup,
Font Awesome symbol renderer,
charts for statistical map (pie/bar),
layer switcher,
wikipedia layer,
animations
> [
![Font style](img/map.style.font.jpg?raw=true)
![Charts](img/map.style.chart.jpg?raw=true)
![](img/map.style.pattern.jpg?raw=true)
![](img/map.style.photo.jpg?raw=true)
![](img/map.style.textpath.jpg?raw=true)
![](img/map.filter.colorize.jpg?raw=true)
![](img/map.control.compass.jpg?raw=true)
![](img/map.control.graticule.jpg?raw=true)
![](img/map.interaction.transform.jpg?raw=true)
![](img/map.control.editbar.jpg?raw=true)
![](img/map.switcher.image.jpg?raw=true)
![](img/map.control.profil.jpg?raw=true)
![](img/map.control.swipe.jpg?raw=true)
![](img/map.popup.anim.jpg?raw=true)
![](img/map.layer.hexbin.jpg?raw=true)
![](img/map.geom.cspline.jpg?raw=true)
![](img/map.cluster.convexhull.jpg?raw=true)
![](img/map.overlay.magnify.jpg?raw=true)
![](img/map.filter.lego.jpg?raw=true)
![](img/map.interaction.synchronize.jpg?raw=true)
](http://viglino.github.io/ol-ext/)
## Getting Started
## using ol-ext in a web page
* Just download the [build script](dist) in the dist directory of the project.
* If you just want to add a `<script>` tag to test things out, you can link directly to the builds from the github rawgit (not recommended in production):
````html
<!-- jQuery -->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<!-- Openlayers -->
<link rel="stylesheet" href="https://openlayers.org/en/master/css/ol.css" />
<script type="text/javascript" src="https://openlayers.org/en/latest/build/ol.js"></script>
<!-- OL-ext -->
<link rel="stylesheet" href="https://cdn.rawgit.com/Viglino/ol-ext/master/dist/ol-ext.min.css" />
<script type="text/javascript" src="https://cdn.rawgit.com/Viglino/ol-ext/master/dist/ol-ext.min.js"></script>
````
* Use npm [ol-ext package](https://www.npmjs.com/package/ol-ext) and link to the node_modules directory:
````
npm install ol-ext
````
## using ol-ext in a webpack
Visit the [this repository](https://github.com/darkscript/ol-ol-ext-webpack-example) for a good example of working with ol-ext npm version and bundler (webpack)
## Documentation
Check out the [hosted examples](http://viglino.github.io/ol-ext/) or the [API documentation](http://viglino.github.io/ol-ext/doc/doc-pages/).
## Contributing
Please see our [contributing guidelines](https://github.com/Viglino/ol-ext/blob/master/CONTRIBUTING.md) if you're interested in getting involved.
## Bugs
Please use the [GitHub issue tracker](https://github.com/Viglino/ol-ext/issues) for all bugs and feature requests. Before creating a new issue, do a quick search to see if the problem has been reported already.
## Licence
ol-ext is licenced under the French Opensource **BSD** compatible CeCILL-B FREE SOFTWARE LICENSE.
(c) 2016-2017 - Jean-Marc Viglino
Some resources (mapping services and API) used in this sofware may have a specific license.
You must check before use.
> [Full text license in English](http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt)
> [Full text license in French](http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt)
For convenience you can use the BSD licence instead when publish content to webpack.

11
build/composer.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "viglino/ol-ext",
"description": "Cool extensions for OpenLayers (ol)",
"license": "CeCILL-B",
"authors": [
{
"name": "Jean-Marc Viglino",
"email": "jean-marc.viglino@ign.fr"
}
]
}

263
build/control/Bar.css Normal file
View File

@ -0,0 +1,263 @@
/* Bar style */
.ol-control.ol-bar
{ left: 50%;
min-height: 1em;
min-width: 1em;
position: absolute;
top: 0.5em;
transform: translate(-50%,0);
-webkit-transform: translate(-50%,0);
}
/* Hide subbar when not inserted in a parent bar */
.ol-control.ol-toggle .ol-option-bar
{ display: none;
}
/* Default position for controls */
.ol-control.ol-bar .ol-bar
{ position: static;
}
.ol-control.ol-bar .ol-control
{ position: relative;
top: auto;
left:auto;
right:auto;
bottom: auto;
display: inline-block;
vertical-align: middle;
background: none;
padding: 0;
margin: 0;
transform: none;
-webkit-transform: none;
}
.ol-control.ol-bar .ol-bar
{ position: static;
}
.ol-control.ol-bar .ol-control button
{ margin:2px 1px;
}
/* Positionning */
.ol-control.ol-bar.ol-left
{ left: 0.5em;
top: 50%;
transform: translate(0px, -50%);
}
.ol-control.ol-bar.ol-left .ol-control
{ display: block;
}
.ol-control.ol-bar.ol-right
{ left: auto;
right: 0.5em;
top: 50%;
transform: translate(0px, -50%);
}
.ol-control.ol-bar.ol-right .ol-control
{ display: block;
}
.ol-control.ol-bar.ol-bottom
{ top: auto;
bottom: 0.5em;
}
.ol-control.ol-bar.ol-top.ol-left,
.ol-control.ol-bar.ol-top.ol-right
{ top: 4.5em;
transform:none;
}
.ol-touch .ol-control.ol-bar.ol-top.ol-left,
.ol-touch .ol-control.ol-bar.ol-top.ol-right
{ top: 5.5em;
}
.ol-control.ol-bar.ol-bottom.ol-left,
.ol-control.ol-bar.ol-bottom.ol-right
{ top: auto;
bottom: 0.5em;
transform:none;
}
/* Group buttons */
.ol-control.ol-bar.ol-group
{ margin: 1px 1px 1px 0;
}
.ol-control.ol-bar.ol-right .ol-group,
.ol-control.ol-bar.ol-left .ol-group
{ margin: 1px 1px 0 1px;
}
.ol-control.ol-bar.ol-group button
{ border-radius:0;
margin: 0 0 0 1px;
}
.ol-control.ol-bar.ol-right.ol-group button,
.ol-control.ol-bar.ol-left.ol-group button,
.ol-control.ol-bar.ol-right .ol-group button,
.ol-control.ol-bar.ol-left .ol-group button
{ margin: 0 0 1px 0;
}
.ol-control.ol-bar.ol-group .ol-control:first-child > button
{ border-radius: 5px 0 0 5px;
}
.ol-control.ol-bar.ol-group .ol-control:last-child > button
{ border-radius: 0 5px 5px 0;
}
.ol-control.ol-bar.ol-left.ol-group .ol-control:first-child > button,
.ol-control.ol-bar.ol-right.ol-group .ol-control:first-child > button,
.ol-control.ol-bar.ol-left .ol-group .ol-control:first-child > button,
.ol-control.ol-bar.ol-right .ol-group .ol-control:first-child > button
{ border-radius: 5px 5px 0 0;
}
.ol-control.ol-bar.ol-left.ol-group .ol-control:last-child > button,
.ol-control.ol-bar.ol-right.ol-group .ol-control:last-child > button,
.ol-control.ol-bar.ol-left .ol-group .ol-control:last-child > button,
.ol-control.ol-bar.ol-right .ol-group .ol-control:last-child > button
{ border-radius: 0 0 5px 5px;
}
/* */
.ol-control.ol-bar .ol-rotate
{ opacity:1;
visibility: visible;
}
.ol-control.ol-bar .ol-rotate button
{ display: block
}
/* Active buttons */
.ol-control.ol-bar .ol-toggle.ol-active > button
{ background: rgba(60, 136, 0, 0.7)
}
.ol-control.ol-bar .ol-toggle.ol-active button:hover
{ background: rgba(60, 136, 0, 0.7)
}
.ol-control.ol-toggle button:disabled
{ background: rgba(0,60,136,.3);
}
/* Subbar toolbar */
.ol-control.ol-bar .ol-control.ol-option-bar
{ display: none;
position:absolute;
top:100%;
left:0;
margin: 5px 0;
border-radius: 0;
background: rgba(255,255,255, 0.8);
/* border: 1px solid rgba(0, 60, 136, 0.5); */
box-shadow: 0 0 0 1px rgba(0, 60, 136, 0.5), 1px 1px 2px rgba(0, 0, 0, 0.5);
}
.ol-control.ol-bar .ol-option-bar:before
{ content: "";
border: 0.5em solid transparent;
border-color: transparent transparent rgba(0, 60, 136, 0.5);
position: absolute;
bottom: 100%;
left: 0.3em;
}
.ol-control.ol-bar .ol-option-bar .ol-control
{ display: table-cell;
}
.ol-control.ol-bar .ol-control .ol-bar
{ display: none;
}
.ol-control.ol-bar .ol-control.ol-active > .ol-option-bar
{ display: block;
}
.ol-control.ol-bar .ol-control.ol-collapsed ul
{ display: none;
}
.ol-control.ol-bar .ol-control.ol-text-button > button:hover,
.ol-control.ol-bar .ol-control.ol-text-button > button
{ background: none;
color: rgba(0, 60, 136, 0.5);
width: auto;
min-width: 1.375em;
margin: 0;
}
.ol-control.ol-bar .ol-control.ol-text-button
{ font-size:0.9em;
border-left: 1px solid rgba(0, 60, 136, 0.8);
border-radius: 0;
}
.ol-control.ol-bar .ol-control.ol-text-button:first-child
{ border-left:0;
}
.ol-control.ol-bar .ol-control.ol-text-button button
{ padding:0 0.3em;
font-weight: normal;
height:1.4em;
}
.ol-control.ol-bar .ol-control.ol-text-button button:hover
{ color: rgba(0, 60, 136, 1);
}
.ol-control.ol-bar.ol-bottom .ol-option-bar
{ top: auto;
bottom: 100%;
}
.ol-control.ol-bar.ol-bottom .ol-option-bar:before
{ border-color: rgba(0, 60, 136, 0.5) transparent transparent ;
bottom: auto;
top: 100%;
}
.ol-control.ol-bar.ol-left .ol-option-bar
{ left:100%;
top: 0;
bottom: auto;
margin: 0 5px;
}
.ol-control.ol-bar.ol-left .ol-option-bar:before
{ border-color: transparent rgba(0, 60, 136, 0.5) transparent transparent;
bottom: auto;
right: 100%;
left: auto;
top: 0.3em;
}
.ol-control.ol-bar.ol-right .ol-option-bar
{ right:100%;
left:auto;
top: 0;
bottom: auto;
margin: 0 5px;
}
.ol-control.ol-bar.ol-right .ol-option-bar:before
{ border-color: transparent transparent transparent rgba(0, 60, 136, 0.5);
bottom: auto;
left: 100%;
top: 0.3em;
}
.ol-control.ol-bar.ol-left .ol-option-bar .ol-option-bar,
.ol-control.ol-bar.ol-right .ol-option-bar .ol-option-bar
{ top: 100%;
bottom: auto;
left: 0.3em;
right: auto;
margin: 5px 0;
}
.ol-control.ol-bar.ol-right .ol-option-bar .ol-option-bar
{ right: 0.3em;
left: auto;
}
.ol-control.ol-bar.ol-left .ol-option-bar .ol-option-bar:before,
.ol-control.ol-bar.ol-right .ol-option-bar .ol-option-bar:before
{ border-color: transparent transparent rgba(0, 60, 136, 0.5);
bottom: 100%;
top: auto;
left: 0.3em;
right: auto;
}
.ol-control.ol-bar.ol-right .ol-option-bar .ol-option-bar:before
{ right: 0.3em;
left: auto;
}

181
build/control/Bar.js Normal file
View File

@ -0,0 +1,181 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** Control bar for OL3
* The control bar is a container for other controls. It can be used to create toolbars.
* Control bars can be nested and combined with ol.control.Toggle to handle activate/deactivate.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {String} options.className class of the control
* @param {bool} options.group is a group, default false
* @param {bool} options.toggleOne only one toggle control is active at a time, default false
* @param {bool} options.autoDeactivate used with subbar to deactivate all control when top level control deactivate, default false
* @param {Array<_ol_control_>} options.controls a list of control to add to the bar
*/
var ol_control_Bar = function(options)
{ if (!options) options={};
var element = $("<div>").addClass('ol-unselectable ol-control ol-bar');
if (options.className) element.addClass(options.className);
if (options.group) element.addClass('ol-group');
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
this.set('toggleOne', options.toggleOne);
this.set('autoDeactivate', options.autoDeactivate);
this.controls_ = [];
if (options.controls instanceof Array)
{ for (var i=0; i<options.controls.length; i++)
{ this.addControl(options.controls[i]);
}
}
};
ol.inherits(ol_control_Bar, ol_control_Control);
/** Set the control visibility
* @param {boolean} b
*/
ol_control_Bar.prototype.setVisible = function (val) {
if (val) $(this.element).show();
else $(this.element).hide();
}
/** Get the control visibility
* @return {boolean} b
*/
ol_control_Bar.prototype.getVisible = function ()
{ return ($(this.element).css('display') != 'none');
}
/**
* Set the map instance the control is associated with
* and add its controls associated to this map.
* @param {_ol_Map_} map The map instance.
*/
ol_control_Bar.prototype.setMap = function (map)
{ ol_control_Control.prototype.setMap.call(this, map);
for (var i=0; i<this.controls_.length; i++)
{ var c = this.controls_[i];
// map.addControl(c);
c.setMap(map);
}
};
/** Get controls in the panel
* @param {Array<_ol_control_>}
*/
ol_control_Bar.prototype.getControls = function ()
{ return this.controls_;
};
/** Set tool bar position
* @param {top|left|bottom|right} pos
*/
ol_control_Bar.prototype.setPosition = function (pos)
{ $(this.element).removeClass('ol-left ol-top ol-bottom ol-right');
pos=pos.split ('-');
for (var i=0; i<pos.length; i++)
{ switch (pos[i])
{ case 'top':
case 'left':
case 'bottom':
case 'right':
$(this.element).addClass ("ol-"+pos[i]);
break;
default: break;
}
}
};
/** Add a control to the bar
* @param {_ol_control_} c control to add
*/
ol_control_Bar.prototype.addControl = function (c)
{ this.controls_.push(c);
c.setTarget(this.element);
if (this.getMap())
{ this.getMap().addControl(c);
}
// Activate and toogleOne
c.on ('change:active', this.onActivateControl_, this);
if (c.getActive && c.getActive())
{ c.dispatchEvent({ type:'change:active', key:'active', oldValue:false, active:true });
}
};
/** Deativate all controls in a bar
* @param {_ol_control_} except a control
*/
ol_control_Bar.prototype.deactivateControls = function (except)
{ for (var i=0; i<this.controls_.length; i++)
{ if (this.controls_[i] !== except && this.controls_[i].setActive)
{ this.controls_[i].setActive(false);
}
}
};
ol_control_Bar.prototype.getActiveControls = function ()
{ var active = [];
for (var i=0, c; c=this.controls_[i]; i++)
{ if (c.getActive && c.getActive()) active.push(c);
}
return active;
}
/** Auto activate/deactivate controls in the bar
* @param {boolean} b activate/deactivate
*/
ol_control_Bar.prototype.setActive = function (b)
{ if (!b && this.get("autoDeactivate"))
{ this.deactivateControls();
}
if (b)
{ var ctrls = this.getControls();
for (var i=0, sb; (sb = ctrls[i]); i++)
{ if (sb.get("autoActivate")) sb.setActive(true);
}
}
}
/** Post-process an activated/deactivated control
* @param {ol.event} e :an object with a target {_ol_control_} and active flag {bool}
*/
ol_control_Bar.prototype.onActivateControl_ = function (e)
{ if (this.get('toggleOne'))
{ if (e.active)
{ var n;
var ctrl = e.target;
for (n=0; n<this.controls_.length; n++)
{ if (this.controls_[n]===ctrl) break;
}
// Not here!
if (n==this.controls_.length) return;
this.deactivateControls (this.controls_[n]);
}
else
{ // No one active > test auto activate
if (!this.getActiveControls().length)
{ for (var i=0, c; c=this.controls_[i]; i++)
{ if (c.get("autoActivate"))
{ c.setActive();
break;
}
}
}
}
}
};
export default ol_control_Bar

45
build/control/Button.js Normal file
View File

@ -0,0 +1,45 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** A simple push button control
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {String} options.className class of the control
* @param {String} options.title title of the control
* @param {String} options.html html to insert in the control
* @param {function} options.handleClick callback when control is clicked (or use change:active event)
*/
var ol_control_Button = function(options)
{ options = options || {};
var element = $("<div>").addClass((options.className||"") + ' ol-button ol-unselectable ol-control');
var self = this;
var bt = $("<button>").html(options.html || "")
.attr('type','button')
.attr('title', options.title)
.on("click", function(e)
{ if (e && e.preventDefault)
{ e.preventDefault();
e.stopPropagation();
}
if (options.handleClick) options.handleClick.call(self, e);
})
.appendTo(element);
// Try to get a title in the button content
if (!options.title) bt.attr("title", bt.children().first().attr('title'));
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
if (options.title) this.set("title", options.title);
};
ol.inherits(ol_control_Button, ol_control_Control);
export default ol_control_Button

View File

@ -0,0 +1,127 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Attribution from 'ol/control/attribution'
import ol_style_Style from 'ol/style/style'
import ol_color from 'ol/color'
import ol_control_ScaleLine from 'ol/control/scaleline'
/**
* @classdesc
* OpenLayers 3 Attribution Control integrated in the canvas (for jpeg/png export purposes).
* @see http://www.kreidefossilien.de/webgis/dokumentation/beispiele/export-map-to-png-with-scale
*
* @constructor
* @extends {ol_control_Attribution}
* @param {Object=} options extend the ol_control_Attribution options.
* @param {ol_style_Style} options.style option is usesd to draw the text.
*/
var ol_control_CanvasAttribution = function(options)
{ if (!options) options = {};
ol_control_Attribution.call(this, options);
// Draw in canvas
this.isCanvas_ = !!options.canvas;
// Get style options
if (!options) options={};
if (!options.style) options.style = new ol_style_Style();
this.setStyle (options.style);
}
ol.inherits(ol_control_CanvasAttribution, ol_control_Attribution);
/**
* Draw attribution on canvas
* @param {boolean} b draw the attribution on canvas.
*/
ol_control_CanvasAttribution.prototype.setCanvas = function (b)
{ this.isCanvas_ = b;
$(this.element).css("visibility", b ? "hidden":"visible");
if (this.map_) this.map_.renderSync();
};
/**
* Change the control style
* @param {ol_style_Style} style
*/
ol_control_CanvasAttribution.prototype.setStyle = function (style)
{ var text = style.getText();
this.font_ = text ? text.getFont() : "10px Arial";
var stroke = text ? text.getStroke() : null;
var fill = text ? text.getFill() : null;
this.fontStrokeStyle_ = stroke ? ol_color.asString(stroke.getColor()) : "#fff";
this.fontFillStyle_ = fill ? ol_color.asString(fill.getColor()) : "#000";
this.fontStrokeWidth_ = stroke ? stroke.getWidth() : 3;
if (this.getMap()) this.getMap().render();
};
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {ol.Map} map Map.
* @api stable
*/
ol_control_CanvasAttribution.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawAttribution_, this);
ol_control_ScaleLine.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Get change (new layer added or removed)
if (map) map.on('postcompose', this.drawAttribution_, this);
this.map_ = map;
this.setCanvas (this.isCanvas_);
}
/**
* Draw attribution in the final canvas
* @private
*/
ol_control_CanvasAttribution.prototype.drawAttribution_ = function(e)
{ var ctx = e.context;
if (!this.isCanvas_) return;
var text = "";
$("li", this.element).each (function()
{ if ($(this).css("display")!="none") text += (text ? " - ":"") + $(this).text();
});
// Get size of the scale div
var position = $(this.element).position();
// Retina device
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio,ratio);
// Position if transform:scale()
var container = $(this.getMap().getViewport()).parent();
var scx = container.outerWidth() / container.get(0).getBoundingClientRect().width;
var scy = container.outerHeight() / container.get(0).getBoundingClientRect().height;
position.left *= scx;
position.top *= scy;
position.right = position.left + $(this.element).outerWidth();
position.bottom = position.top + $(this.element).outerHeight();
// Draw scale text
ctx.beginPath();
ctx.strokeStyle = this.fontStrokeStyle_;
ctx.fillStyle = this.fontFillStyle_;
ctx.lineWidth = this.fontStrokeWidth_;
ctx.textAlign = "right";
ctx.textBaseline ="bottom";
ctx.font = this.font_;
ctx.strokeText(text, position.right, position.bottom);
ctx.fillText(text, position.right, position.bottom);
ctx.closePath();
ctx.restore();
};
export default ol_control_CanvasAttribution

View File

@ -0,0 +1,138 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_ScaleLine from 'ol/control/scaleline'
import ol_style_Style from 'ol/style/style'
import ol_color from 'ol/color'
/**
* @classdesc
* OpenLayers 3 Scale Line Control integrated in the canvas (for jpeg/png export purposes).
* @see http://www.kreidefossilien.de/webgis/dokumentation/beispiele/export-map-to-png-with-scale
*
* @constructor
* @extends {ol_control_ScaleLine}
* @param {Object=} options extend the ol_control_ScaleLine options.
* @param {ol_style_Style} options.style used to draw the scale line (default is black/white, 10px Arial).
*/
var ol_control_CanvasScaleLine = function(options)
{ ol_control_ScaleLine.call(this, options);
this.scaleHeight_ = 6;
// Get style options
if (!options) options={};
if (!options.style) options.style = new ol_style_Style();
this.setStyle(options.style);
}
ol.inherits(ol_control_CanvasScaleLine, ol_control_ScaleLine);
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_control_CanvasScaleLine.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawScale_, this);
ol_control_ScaleLine.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Add postcompose on the map
if (map) map.on('postcompose', this.drawScale_, this);
// Hide the default DOM element
this.$element = $(this.element).css("visibility","hidden");
this.olscale = $(".ol-scale-line-inner", this.element);
}
/**
* Change the control style
* @param {_ol_style_Style_} style
*/
ol_control_CanvasScaleLine.prototype.setStyle = function (style)
{ var stroke = style.getStroke();
this.strokeStyle_ = stroke ? ol_color.asString(stroke.getColor()) : "#000";
this.strokeWidth_ = stroke ? stroke.getWidth() : 2;
var fill = style.getFill();
this.fillStyle_ = fill ? ol_color.asString(fill.getColor()) : "#fff";
var text = style.getText();
this.font_ = text ? text.getFont() : "10px Arial";
stroke = text ? text.getStroke() : null;
fill = text ? text.getFill() : null;
this.fontStrokeStyle_ = stroke ? ol_color.asString(stroke.getColor()) : this.fillStyle_;
this.fontStrokeWidth_ = stroke ? stroke.getWidth() : 3;
this.fontFillStyle_ = fill ? ol_color.asString(fill.getColor()) : this.strokeStyle_;
// refresh
if (this.getMap()) this.getMap().render();
}
/**
* Draw attribution in the final canvas
* @private
*/
ol_control_CanvasScaleLine.prototype.drawScale_ = function(e)
{ if ( this.$element.css("display")==="none" ) return;
var ctx = e.context;
// Get size of the scale div
var scalewidth = this.olscale.width();
if (!scalewidth) return;
var text = this.olscale.text();
var position = this.$element.position();
// Retina device
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio,ratio);
// Position if transform:scale()
var container = $(this.getMap().getViewport()).parent();
var scx = container.outerWidth() / container.get(0).getBoundingClientRect().width;
var scy = container.outerHeight() / container.get(0).getBoundingClientRect().height;
position.left *= scx;
position.top *= scy;
// On top
position.top += this.$element.height() - this.scaleHeight_;
// Draw scale text
ctx.beginPath();
ctx.strokeStyle = this.fontStrokeStyle_;
ctx.fillStyle = this.fontFillStyle_;
ctx.lineWidth = this.fontStrokeWidth_;
ctx.textAlign = "center";
ctx.textBaseline ="bottom";
ctx.font = this.font_;
ctx.strokeText(text, position.left+scalewidth/2, position.top);
ctx.fillText(text, position.left+scalewidth/2, position.top);
ctx.closePath();
// Draw scale bar
position.top += 2;
ctx.lineWidth = this.strokeWidth_;
ctx.strokeStyle = this.strokeStyle_;
var max = 4;
var n = parseInt(text);
while (n%10 === 0) n/=10;
if (n%5 === 0) max = 5;
for (var i=0; i<max; i++)
{ ctx.beginPath();
ctx.fillStyle = i%2 ? this.fillStyle_ : this.strokeStyle_;
ctx.rect(position.left+i*scalewidth/max, position.top, scalewidth/max, this.scaleHeight_);
ctx.stroke();
ctx.fill();
ctx.closePath();
}
ctx.restore();
}
export default ol_control_CanvasScaleLine

View File

@ -0,0 +1,155 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_color from 'ol/color'
import ol_style_Style from 'ol/style/style'
/**
* OpenLayers 3 Title Control integrated in the canvas (for jpeg/png export purposes).
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options extend the ol.control options.
* @param {ol_style_Style} options.style style usesd to draw the title.
*/
var ol_control_CanvasTitle = function(options)
{ if (!options) options={};
// Get style options
if (!options.style) options.style = new ol_style_Style();
this.setStyle(options.style);
// Initialize parent
var elt = $("<div>").text(this.text_)
.addClass("ol-title ol-unselectable")
.css(
{ font: this.font_,
position: 'absolute',
top:0, left:0, right:0,
display: 'block',
visibility: 'hidden'
});
ol_control_Control.call(this,
{ element: elt.get(0),
target: options.target
});
}
ol.inherits(ol_control_CanvasTitle, ol_control_Control);
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_control_CanvasTitle.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawTitle_, this);
ol_control_Control.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Get change (new layer added or removed)
if (map) map.on('postcompose', this.drawTitle_, this);
}
/**
* Change the control style
* @param {ol_style_Style} style
*/
ol_control_CanvasTitle.prototype.setStyle = function (style)
{ var text = style.getText();
this.font_ = text ? text.getFont() || "20px Arial" : "20px Arial";
this.text_ = text ? text.getText() : "";
var stroke = text ? text.getStroke() : null;
var fill = text ? text.getFill() : null;
this.strokeStyle_ = stroke ? ol_color.asString(stroke.getColor()) : "#fff";
this.fillStyle_ = fill ? ol_color.asString(fill.getColor()) : "#000";
if (this.element)
{ $(this.element).text(this.text_).css ({font: this.font_});
}
// refresh
if (this.getMap()) this.getMap().render();
}
/**
* Set the map title
* @param {string} map title.
* @api stable
*/
ol_control_CanvasTitle.prototype.setTitle = function (title)
{ this.text_ = title;
$(this.element).text(title);
if (this.getMap()) this.getMap().renderSync();
}
/**
* Get the map title
* @param {string} map title.
* @api stable
*/
ol_control_CanvasTitle.prototype.getTitle = function (title)
{ return this.text_;
}
/**
* Set control visibility
* @param {bool} b
* @api stable
*/
ol_control_CanvasTitle.prototype.setVisible = function (b)
{ if (b) $(this.element).show();
else $(this.element).hide();
if (this.getMap()) this.getMap().renderSync();
}
/**
* Get control visibility
* @return {bool}
* @api stable
*/
ol_control_CanvasTitle.prototype.getVisible = function (b)
{ return ($(this.element).css('display') !== 'none');
}
/** Draw scale line in the final canvas
*/
ol_control_CanvasTitle.prototype.drawTitle_ = function(e)
{ if (!this.getVisible()) return;
var ctx = e.context;
// Retina device
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio,ratio);
var w = ctx.canvas.width/ratio;
var h = $(this.element).height();
var position = { top:0, left:w/2 };
ctx.beginPath();
ctx.fillStyle = this.strokeStyle_;
ctx.rect(0,0, w, h);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = this.fillStyle_;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = this.font_;
ctx.fillText(this.text_, position.left, position.top +h/2);
ctx.closePath();
ctx.restore();
}
export default ol_control_CanvasTitle

225
build/control/Cloud.js Normal file

File diff suppressed because one or more lines are too long

181
build/control/Compass.js Normal file
View File

@ -0,0 +1,181 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/**
* Draw a compass on the map. The position/size of the control is defined in the css.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options. The style {_ol_style_Stroke_} option is usesd to draw the text.
* @param {string} options.className class name for the control
* @param {Image} options.image an image, default use the src option or a default image
* @param {string} options.src image src, default use the image option or a default image
* @param {boolean} options.rotateVithView rotate vith view (false to show watermark), default true
* @param {_ol_style_Stroke_} options.style style to draw the lines, default draw no lines
*/
var ol_control_Compass = function(options)
{ var self = this;
if (!options) options = {};
// Initialize parent
var elt = document.createElement("div");
elt.className = "ol-compassctrl ol-unselectable ol-hidden" + (options.className ? " "+options.className : "");
elt.style.position = "absolute";
elt.style.visibility = "hidden";
ol_control_Control.call(this, { element: elt });
this.set('rotateVithView', options.rotateWithView!==false);
// Style to draw the lines
this.style = options.style;
// The image
if (options.image)
{ this.img_ = options.image;
}
else if (options.src)
{ this.img_ = new Image();
this.img_.onload = function(){ if (self.getMap()) self.getMap().renderSync(); }
this.img_.src = options.src;
}
else this.img_ = this.defaultCompass_($(this.element).width(), this.style ? this.style.getColor():"");
// 8 angles
this.da_ = [];
for (var i=0; i<8; i++) this.da_[i] = [ Math.cos(Math.PI*i/8), Math.sin(Math.PI*i/8) ];
};
ol.inherits(ol_control_Compass, ol_control_Control);
/**
* Remove the control from its current map and attach it to the new map.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_control_Compass.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawCompass_, this);
ol_control_Control.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Get change (new layer added or removed)
if (map) map.on('postcompose', this.drawCompass_, this);
};
/**
* Create a default image.
* @param {number} s the size of the compass
* @private
*/
ol_control_Compass.prototype.defaultCompass_ = function (s, color)
{ var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
var s = canvas.width = canvas.height;
var r = s/2;
var r2 = 0.22*r;
function draw (r, r2)
{ ctx.fillStyle = color ||"#963";
ctx.beginPath();
ctx.moveTo (0,0);
ctx.lineTo (r,0); ctx.lineTo (r2,r2); ctx.moveTo (0,0);
ctx.lineTo (-r,0); ctx.lineTo (-r2,-r2); ctx.moveTo (0,0);
ctx.lineTo (0,r); ctx.lineTo (-r2,r2); ctx.moveTo (0,0);
ctx.lineTo (0,-r); ctx.lineTo (r2,-r2); ctx.moveTo (0,0);
ctx.fill();
ctx.stroke();
};
function draw2 (r, r2)
{ ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "#fff";
ctx.beginPath();
ctx.moveTo (0,0);
ctx.lineTo (r,0); ctx.lineTo (r2,-r2); ctx.moveTo (0,0);
ctx.lineTo (-r,0); ctx.lineTo (-r2,r2); ctx.moveTo (0,0);
ctx.lineTo (0,r); ctx.lineTo (r2,r2); ctx.moveTo (0,0);
ctx.lineTo (0,-r); ctx.lineTo (-r2,-r2); ctx.moveTo (0,0);
ctx.fill();
ctx.globalCompositeOperation="source-over";
ctx.beginPath();
ctx.moveTo (0,0);
ctx.lineTo (r,0); ctx.lineTo (r2,-r2); ctx.moveTo (0,0);
ctx.lineTo (-r,0); ctx.lineTo (-r2,r2); ctx.moveTo (0,0);
ctx.lineTo (0,r); ctx.lineTo (r2,r2); ctx.moveTo (0,0);
ctx.lineTo (0,-r); ctx.lineTo (-r2,-r2); ctx.moveTo (0,0);
ctx.stroke();
};
ctx.translate(r,r);
ctx.strokeStyle = color || "#963";
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.arc (0,0, s*0.41, 0, 2*Math.PI);
ctx.arc (0,0, s*0.44, 0, 2*Math.PI);
ctx.stroke();
ctx.rotate(Math.PI/4)
draw (r*0.9, r2*0.8);
draw2 (r*0.9, r2*0.8);
ctx.rotate(-Math.PI/4)
draw (r, r2);
draw2 (r, r2);
return canvas;
};
/** Draw compass
* @param {ol.event} e postcompose event
* @private
*/
ol_control_Compass.prototype.drawCompass_ = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
// Retina device
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio,ratio);
var w = $(this.element).width();
var h = $(this.element).height();
var pos = $(this.element).position();
var compass = this.img_;
var rot = e.frameState.viewState.rotation;
ctx.beginPath();
ctx.translate(pos.left+w/2, pos.top+h/2);
if (this.get('rotateVithView')) ctx.rotate(rot);
/*
ctx.globalCompositeOperation = "multiply";
ctx.globalAlpha = this.opacity || 1;
*/
if (this.style)
{ ctx.beginPath();
ctx.strokeStyle = this.style.getColor();
ctx.lineWidth = this.style.getWidth();
var m = Math.max(canvas.width, canvas.height);
for (var i=0; i<8; i++)
{ ctx.moveTo (-this.da_[i][0]*m, -this.da_[i][1]*m);
ctx.lineTo (this.da_[i][0]*m, this.da_[i][1]*m);
}
ctx.stroke();
}
if (compass.width)
{ ctx.drawImage (compass, -w/2, -h/2, w, h);
}
ctx.closePath();
ctx.restore();
};
export default ol_control_Compass

47
build/control/Disable.js Normal file
View File

@ -0,0 +1,47 @@
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** A simple control to disable all actions on the map.
* The control will create an invisible div over the map.
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {String} options.class class of the control
* @param {String} options.html html code to insert in the control
* @param {bool} options.on the control is on
* @param {function} options.toggleFn callback when control is clicked
*/
var ol_control_Disable = function(options)
{ var options = options||{};
var element = $("<div>").addClass((options.calssName||"")+' ol-disable ol-unselectable ol-control');
element.css({ top:0, left:0, right:0, bottom:0, "z-index":10000, background:"none", display:"none" });
ol_control_Control.call(this,
{ element: element.get(0)
});
}
ol.inherits(ol_control_Disable, ol_control_Control);
/** Test if the control is on
* @return {bool}
* @api stable
*/
ol_control_Disable.prototype.isOn = function()
{ return $(this.element).hasClass("ol-disable");
}
/** Disable all action on the map
* @param {bool} b, default false
* @api stable
*/
ol_control_Disable.prototype.disableMap = function(b)
{ if (b)
{ $(this.element).addClass("ol-enable").show();
}
else
{ $(this.element).removeClass("ol-enable").hide();
}
}
export default ol_control_Disable

26
build/control/Gauge.css Normal file
View File

@ -0,0 +1,26 @@
.ol-gauge
{ top: 0.5em;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.ol-gauge > *
{ display: inline-block;
vertical-align: middle;
}
.ol-gauge > span
{
margin: 0 0.5em;
}
.ol-gauge > div
{ width: 200px;
border: 1px solid rgba(0,60,136,.5);
border-radius: 3px;
padding:1px;
}
.ol-gauge button
{ height: 0.8em;
margin:0;
max-width:100%;
}

57
build/control/Gauge.js Normal file
View File

@ -0,0 +1,57 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** A simple gauge control to display level information on the map.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {String} options.className class of the control
* @param {String} options.title title of the control
* @param {number} options.max maximum value, default 100;
* @param {number} options.val the value, default 0
*/
var ol_control_Gauge = function(options)
{ options = options || {};
var element = $("<div>").addClass((options.className||"") + ' ol-gauge ol-unselectable ol-control');
this.title_ = $("<span>").appendTo(element);
this.gauge_ = $("<button>").attr('type','button').appendTo($("<div>").appendTo(element)).width(0);
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
this.setTitle(options.title);
this.val(options.val);
this.set("max", options.max||100);
};
ol.inherits(ol_control_Gauge, ol_control_Control);
/** Set the control title
* @param {string} title
*/
ol_control_Gauge.prototype.setTitle = function(title)
{ this.title_.html(title||"");
if (!title) this.title_.hide();
else this.title_.show();
};
/** Set/get the gauge value
* @param {number|undefined} v the value or undefined to get it
* @return {number} the value
*/
ol_control_Gauge.prototype.val = function(v)
{ if (v!==undefined)
{ this.val_ = v;
this.gauge_.css("width", (v/this.get('max')*100)+"%");
}
return this.val_;
};
export default ol_control_Gauge

View File

@ -0,0 +1,79 @@
.ol-control.ol-bookmark
{ top: 0.5em;
left: 3em;
}
.ol-control.ol-bookmark button
{ position: relative;
}
.ol-control.ol-bookmark > button::before
{ content: "";
position: absolute;
border-width: 10px 5px 4px;
border-style: solid;
border-color: #fff;
border-bottom-color: transparent;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
height: 0;
}
.ol-control.ol-bookmark > div
{ display: none;
min-width: 5em;
}
.ol-control.ol-bookmark input
{ font-size: 0.9em;
margin: 0.1em 0 ;
padding: 0 0.5em;
}
.ol-control.ol-bookmark ul
{ margin:0;
padding: 0;
list-style: none;
min-width: 10em;
}
.ol-control.ol-bookmark li
{ color: rgba(0,60,136,0.8);
font-size: 0.9em;
padding: 0 0.2em 0 0.5em;
cursor: default;
clear:both;
}
.ol-control.ol-bookmark li:hover
{ background-color: rgba(0,60,136,.5);
color: #fff;
}
.ol-control.ol-bookmark > div button
{ width: 1em;
height: 0.8em;
float: right;
background-color: transparent;
cursor: pointer;
border-radius: 0;
}
.ol-control.ol-bookmark > div button:before
{ content: "\2A2F";
color: #936;
font-size: 1.2em;
line-height: 1em;
border-radius: 0;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.ol-bookmark ul li button,
.ol-bookmark input
{ display: none;
}
.ol-bookmark.ol-editable ul li button,
.ol-bookmark.ol-editable input
{ display: block;
}

View File

@ -0,0 +1,179 @@
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** Bookmark positions on ol maps.
*
* @constructor
* @extends {ol_control_Control}
* @fires add
* @fires remove
* @param {} options Geobookmark's options
* @param {string} options.className default ol-bookmark
* @param {string} options.placeholder input placeholder, default Add a new geomark...
* @param {bool} options.editable enable modification, default true
* @param {string} options.namespace a namespace to save the boolmark (if more than one on a page), default ol
* @param {Array<any>} options.marks a list of default bookmarks:
* @see [Geobookmark example](../../examples/map.control.geobookmark.html)
* @example
var bm = new GeoBookmark ({
marks: {
"Paris": {pos:_ol_proj_.transform([2.351828, 48.856578], 'EPSG:4326', 'EPSG:3857'), zoom:11, permanent: true },
"London": {pos:_ol_proj_.transform([-0.1275,51.507222], 'EPSG:4326', 'EPSG:3857'), zoom:12}
}
});
*/
var ol_control_GeoBookmark = function(options) {
options = options || {};
var self = this;
var element = document.createElement('div');
if (options.target) {
element.className = options.className || "ol-bookmark";
} else {
element.className = (options.className || "ol-bookmark") +
" ol-unselectable ol-control ol-collapsed";
element.addEventListener("mouseleave", function() {
if (input !== document.activeElement) {
menu.style.display = 'none';
};
});
// Show bookmarks on click
this.button = document.createElement('button');
this.button.setAttribute('type', 'button');
this.button.addEventListener('click', function(e) {
menu.style.display = (menu.style.display === '' || menu.style.display === 'none' ? 'block': 'none');
});
element.appendChild(this.button);
}
// The menu
var menu = document.createElement('div');
element.appendChild(menu);
var ul = document.createElement('ul');
menu.appendChild(ul);
var input = document.createElement('input');
input.setAttribute("placeholder", options.placeholder || "Add a new geomark...")
input.addEventListener("change", function(e) {
var title = this.value;
if (title) {
self.addBookmark(title);
this.value = '';
self.dispatchEvent({
type: "add",
name: title
});
}
menu.style.display = 'none';
});
input.addEventListener("blur", function() {
menu.style.display = 'none';
});
menu.appendChild(input);
// Init
ol_control_Control.call(this, {
element: element,
target: options.target
});
this.on("propertychange", function(e) {
if (e.key==='editable')
{ element.className = element.className.replace(" ol-editable","");
if (this.get('editable'))
{ element.className += " ol-editable";
}
}
console.log(e);
}), this;
this.set("namespace", options.namespace || 'ol');
this.set("editable", options.editable !== false);
// Set default bmark
this.setBookmarks(localStorage[this.get('namespace')+"@bookmark"] ? null:options.marks);
};
ol.inherits(ol_control_GeoBookmark, ol_control_Control);
/** Set bookmarks
* @param {} bmark a list of bookmarks, default retreave in the localstorage
* @example
bm.setBookmarks({
"Paris": {pos:_ol_proj_.transform([2.351828, 48.856578], 'EPSG:4326', 'EPSG:3857'), zoom:11, permanent: true },
"London": {pos:_ol_proj_.transform([-0.1275,51.507222], 'EPSG:4326', 'EPSG:3857'), zoom:12}
});
*/
ol_control_GeoBookmark.prototype.setBookmarks = function(bmark) {
if (!bmark) bmark = JSON.parse(localStorage[this.get('namespace')+"@bookmark"] || "{}");
var modify = this.get("editable");
var ul = this.element.querySelector("ul");
var menu = this.element.querySelector("div");
var self = this;
ul.innerHTML = '';
for (var b in bmark) {
var li = document.createElement('li');
li.textContent = b;
li.setAttribute('data-bookmark', JSON.stringify(bmark[b]));
li.addEventListener('click', function() {
var bm = JSON.parse(this.getAttribute("data-bookmark"));
self.getMap().getView().setCenter(bm.pos);
self.getMap().getView().setZoom(bm.zoom);
menu.style.display = 'none';
});
ul.appendChild(li);
if (modify && !bmark[b].permanent) {
var button = document.createElement('button');
button.setAttribute('data-name', b);
button.setAttribute("title", "Suppr.");
button.addEventListener('click', function(e) {
self.removeBookmark(this.getAttribute("data-name"));
self.dispatchEvent({ type: "remove", name: this.getAttribute("data-name") });
e.stopPropagation();
});
li.appendChild(button);
}
}
localStorage[this.get('namespace')+"@bookmark"] = JSON.stringify(bmark);
};
/** Get Geo bookmarks
* @return {any} a list of bookmarks : { BM1:{pos:ol.coordinates, zoom: integer}, BM2:{pos:ol.coordinates, zoom: integer} }
*/
ol_control_GeoBookmark.prototype.getBookmarks = function() {
return JSON.parse(localStorage[this.get('namespace')+"@bookmark"] || "{}");
};
/** Remove a Geo bookmark
* @param {string} name
*/
ol_control_GeoBookmark.prototype.removeBookmark = function(name) {
if (!name) {
return;
};
var bmark = this.getBookmarks();
delete bmark[name];
this.setBookmarks(bmark);
};
/** Add a new Geo bookmark (replace existing one if any)
* @param {string} name name of the bookmark (display in the menu)
* @param {_ol_coordinate_} position default current position
* @param {number} zoom default current map zoom
* @param {bool} permanent prevent from deletion, default false
*/
ol_control_GeoBookmark.prototype.addBookmark = function(name, position, zoom, permanent)
{
if (!name) return;
var bmark = this.getBookmarks();
// Don't override permanent bookmark
if (bmark[name] && bmark[name].permanent) return;
// Create or override
bmark[name] = {
pos: position || this.getMap().getView().getCenter(),
zoom: zoom || this.getMap().getView().getZoom(),
permanent: !!permanent
};
this.setBookmarks(bmark);
};
export default ol_control_GeoBookmark

124
build/control/Globe.css Normal file
View File

@ -0,0 +1,124 @@
.ol-control.ol-globe
{ position: absolute;
left: 0.5em;
bottom: 0.5em;
border-radius: 50%;
opacity: 0.7;
transform: scale(0.5);
transform-origin: 0 100%;
-webkit-transform: scale(0.5);
-webkit-transform-origin: 0 100%;
}
.ol-control.ol-globe:hover
{ opacity: 0.9;
}
.ol-control.ol-globe .panel
{ display:block;
width:170px;
height:170px;
background-color:#fff;
cursor: pointer;
border-radius: 50%;
overflow: hidden;
box-shadow: 0 0 10px 5px rgba(255, 255, 255, 0.5);
}
.ol-control.ol-globe .panel .ol-viewport
{ border-radius: 50%;
}
.ol-control.ol-globe .ol-pointer
{ display: block;
background-color: #fff;
width:10px;
height: 10px;
border:10px solid red;
position: absolute;
top: 50%;
left:50%;
transform: translate(-15px, -40px);
-webkit-transform: translate(-15px, -40px);
border-radius: 50%;
z-index:1;
transition: opacity 0.15s, top 0s, left 0s;
-webkit-transition: opacity 0.15s, top 0s, left 0s;
}
.ol-control.ol-globe .ol-pointer.hidden
{ opacity:0;
transition: opacity 0.15s, top 3s, left 5s;
-webkit-transition: opacity 0.15s, top 3s, left 5s;
}
.ol-control.ol-globe .ol-pointer::before
{ border-radius: 50%;
box-shadow: 6px 6px 10px 5px #000;
content: "";
display: block;
height: 0;
left: 0;
position: absolute;
top: 23px;
width: 0;
}
.ol-control.ol-globe .ol-pointer::after
{ content:"";
width:0;
height:0;
display: block;
position: absolute;
border-width: 20px 10px 0;
border-color: red transparent;
border-style: solid;
left: -50%;
top: 100%;
}
.ol-control.ol-globe .panel::before {
border-radius: 50%;
box-shadow: -20px -20px 80px 2px rgba(0, 0, 0, 0.7) inset;
content: "";
display: block;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
.ol-control.ol-globe .panel::after {
border-radius: 50%;
box-shadow: 0 0 20px 7px rgba(255, 255, 255, 1);
content: "";
display: block;
height: 0;
left: 23%;
position: absolute;
top: 20%;
transform: rotate(-40deg);
width: 20%;
z-index: 1;
}
.ol-control.ol-globe.ol-collapsed .panel
{ display:none;
}
.ol-control-top.ol-globe
{ bottom: auto;
top: 5em;
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
}
.ol-control-right.ol-globe
{ left: auto;
right: 0.5em;
transform-origin: 100% 100%;
-webkit-transform-origin: 100% 100%;
}
.ol-control-right.ol-control-top.ol-globe
{ left: auto;
right: 0.5em;
transform-origin: 100% 0;
-webkit-transform-origin: 100% 0;
}

191
build/control/Globe.js Normal file
View File

@ -0,0 +1,191 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_Map from 'ol/map'
import ol_Collection from 'ol/collection'
import ol_View from 'ol/view'
import ol_layer_Vector from 'ol/layer/vector'
import ol_style_Style from 'ol/style/style'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Fill from 'ol/style/fill'
import ol_style_Stroke from 'ol/style/stroke'
import ol_source_Vector from 'ol/source/vector'
//TODO: replace ol.animation.pan with new {ol_interaction_Interaction.pan}
//import ol_interaction_Interaction from 'ol/interaction/interaction'
/**
* OpenLayers 3 lobe Overview Control.
* The globe can rotate with map (follow.)
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {boolean} follow follow the map when center change, default false
* @param {top|bottom-left|right} align position as top-left, etc.
* @param {Array<ol.layer>} layers list of layers to display on the globe
* @param {ol.style.Style | Array.<ol.style.Style> | undefined} style style to draw the position on the map , default a marker
*/
var ol_control_Globe = function(opt_options)
{ var options = opt_options || {};
var self = this;
// API
var element;
if (options.target)
{ element = $("<div>");
this.panel_ = $(options.target);
}
else
{ element = $("<div>").addClass('ol-globe ol-unselectable ol-control');
if (/top/.test(options.align)) element.addClass('ol-control-top');
if (/right/.test(options.align)) element.addClass('ol-control-right');
this.panel_ = $("<div>").addClass("panel")
.appendTo(element);
this.pointer_ = $("<div>").addClass("ol-pointer")
.appendTo(element);
}
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
// http://openlayers.org/en/latest/examples/sphere-mollweide.html ???
// Create a globe map
this.ovmap_ = new ol_Map(
{ controls: new ol_Collection(),
interactions: new ol_Collection(),
target: this.panel_.get(0),
view: new ol_View
({ zoom: 0,
center: [0,0]
}),
layers: options.layers
});
setTimeout (function()
{ self.ovmap_.updateSize();
}, 0);
this.set('follow', options.follow || false);
// Cache extent
this.extentLayer = new ol_layer_Vector(
{ name: 'Cache extent',
source: new ol_source_Vector(),
style: options.style || [new ol_style_Style(
{ image: new ol_style_Circle(
{ fill: new ol_style_Fill({
color: 'rgba(255,0,0, 1)'
}),
stroke: new ol_style_Stroke(
{ width: 7,
color: 'rgba(255,0,0, 0.8)'
}),
radius: 5
})
}
)]
})
this.ovmap_.addLayer(this.extentLayer);
};
ol.inherits(ol_control_Globe, ol_control_Control);
/**
* Set the map instance the control associated with.
* @param {ol.Map} map The map instance.
*/
ol_control_Globe.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().getView().un('propertychange', this.setView, this);
ol_control_Control.prototype.setMap.call(this, map);
// Get change (new layer added or removed)
if (map)
{ map.getView().on('propertychange', this.setView, this);
this.setView();
}
};
/** Set the globe center with the map center
*/
ol_control_Globe.prototype.setView = function()
{ if (this.getMap() && this.get('follow'))
{ this.setCenter(this.getMap().getView().getCenter());
}
}
/** Get globe map
* @return {ol_Map}
*/
ol_control_Globe.prototype.getGlobe = function()
{ return this.ovmap_;
}
/** Show/hide the globe
*/
ol_control_Globe.prototype.show = function(b)
{ if (b!==false) $(this.element).removeClass("ol-collapsed");
else $(this.element).addClass("ol-collapsed");
this.ovmap_.updateSize();
}
/** Set position on the map
* @param {top|bottom-left|right} align
*/
ol_control_Globe.prototype.setPosition = function(align)
{ if (/top/.test(align)) $(this.element).addClass("ol-control-top");
else $(this.element).removeClass("ol-control-top");
if (/right/.test(align)) $(this.element).addClass("ol-control-right");
else $(this.element).removeClass("ol-control-right");
}
/** Set the globe center
* @param {_ol_coordinate_} center the point to center to
* @param {boolean} show true to show a pointer
*/
ol_control_Globe.prototype.setCenter = function (center, show)
{ var self = this;
this.pointer_.addClass("hidden");
if (center)
{ var map = this.ovmap_;
var p = map.getPixelFromCoordinate(center);
var h = $(this.element).height();
if (map.getView().animate)
{ setTimeout(function()
{ self.pointer_.css({ 'top': Math.min(Math.max(p[1],0),h) , 'left': "50%" } )
.removeClass("hidden");
}, 800);
map.getView().animate({ center: [center[0],0] });
}
//TODO: Old version (<3.20)
else
{ var pan = ol.animation.pan(
{ duration: 800,
source: map.getView().getCenter()
});
map.beforeRender(function(map, frameState)
{ var b = pan(map, frameState);
if (!b && show!==false)
{ self.pointer_
.css({ 'top': Math.min(Math.max(p[1],0),h) , 'left': "50%" } )
.removeClass("hidden");
}
return b;
});
map.getView().setCenter([center[0],0]);
}
}
};
export default ol_control_Globe

294
build/control/Graticule.js Normal file
View File

@ -0,0 +1,294 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_proj_Projection from 'ol/proj/projection'
import ol_style_Style from 'ol/style/style'
import ol_style_Stroke from 'ol/style/stroke'
import ol_style_Fill from 'ol/style/fill'
import ol_style_Text from 'ol/style/text'
import ol_proj from 'ol/proj'
/**
* Draw a graticule on the map.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} _ol_control_ options.
* - projection {ol.projectionLike} projection to use for the graticule, default EPSG:4326
* - maxResolution {number} max resolution to display the graticule
* - style {ol_style_Style} Style to use for drawing the graticule, default black.
* - step {number} step beetween lines (in proj units), default 1
* - stepCoord {number} show a coord every stepCoord, default 1
* - spacing {number} spacing beetween lines (in px), default 40px
* - borderWidth {number} width of the border (in px), default 5px
* - margin {number} margin of the border (in px), default 0px
*/
var ol_control_Graticule = function(options)
{ var self = this;
if (!options) options = {};
// Initialize parent
var elt = document.createElement("div");
elt.className = "ol-graticule ol-unselectable ol-hidden";
ol_control_Control.call(this, { element: elt });
this.set('projection', options.projection || 'EPSG:4326');
// Use to limit calculation
var p = new ol_proj_Projection({code:this.get('projection')});
var m = p.getMetersPerUnit();
this.fac = 1;
while (m/this.fac>10)
{ this.fac *= 10;
}
this.fac = 10000/this.fac;
this.set('maxResolution', options.maxResolution || Infinity);
this.set('step', options.step || 0.1);
this.set('stepCoord', options.stepCoord || 1);
this.set('spacing', options.spacing || 40);
this.set('margin', options.margin || 0);
this.set('borderWidth', options.borderWidth || 5);
this.set('stroke', options.stroke!==false);
this.formatCoord = options.formatCoord || function(c){return c;};
if (options.style instanceof ol_style_Style) this.style = options.style;
else this.style = new ol_style_Style(
{ stroke: new ol_style_Stroke({ color:"#000", width:1 }),
fill: new ol_style_Fill({ color: "#fff" }),
text: new ol_style_Text(
{ stroke: new ol_style_Stroke({ color:"#fff", width:2 }),
fill: new ol_style_Fill({ color:"#000" }),
})
});
};
ol.inherits(ol_control_Graticule, ol_control_Control);
/**
* Remove the control from its current map and attach it to the new map.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_control_Graticule.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawGraticule_, this);
ol_control_Control.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Get change (new layer added or removed)
if (map) map.on('postcompose', this.drawGraticule_, this);
};
ol_control_Graticule.prototype.setStyle = function (style)
{ this.style = style;
};
ol_control_Graticule.prototype.getStyle = function (style)
{ return style;
};
ol_control_Graticule.prototype.drawGraticule_ = function (e)
{ if (this.get('maxResolution')<e.frameState.viewState.resolution) return;
var ctx = e.context;
var canvas = ctx.canvas;
var ratio = e.frameState.pixelRatio;
var w = canvas.width/ratio;
var h = canvas.height/ratio;
var proj = this.get('projection');
var map = this.getMap();
var bbox =
[ map.getCoordinateFromPixel([0,0]),
map.getCoordinateFromPixel([w,0]),
map.getCoordinateFromPixel([w,h]),
map.getCoordinateFromPixel([0,h])
];
var xmax = -Infinity;
var xmin = Infinity;
var ymax = -Infinity;
var ymin = Infinity;
for (var i=0, c; c=bbox[i]; i++)
{ bbox[i] = ol_proj.transform (c, map.getView().getProjection(), proj);
xmax = Math.max (xmax, bbox[i][0]);
xmin = Math.min (xmin, bbox[i][0]);
ymax = Math.max (ymax, bbox[i][1]);
ymin = Math.min (ymin, bbox[i][1]);
}
var spacing = this.get('spacing');
var step = this.get('step');
var step2 = this.get('stepCoord');
var borderWidth = this.get('borderWidth');
var margin = this.get('margin');
// Limit max line draw
var ds = (xmax-xmin)/step*spacing;
if (ds>w)
{ var dt = Math.round((xmax-xmin)/w*spacing /step);
step *= dt;
if (step>this.fac) step = Math.round(step/this.fac)*this.fac;
}
xmin = (Math.floor(xmin/step))*step -step;
ymin = (Math.floor(ymin/step))*step -step;
xmax = (Math.floor(xmax/step))*step +2*step;
ymax = (Math.floor(ymax/step))*step +2*step;
var extent = ol.proj.get(proj).getExtent();
if (extent)
{ if (xmin < extent[0]) xmin = extent[0];
if (ymin < extent[1]) ymin = extent[1];
if (xmax > extent[2]) xmax = extent[2]+step;
if (ymax > extent[3]) ymax = extent[3]+step;
}
var hasLines = this.style.getStroke() && this.get("stroke");
var hasText = this.style.getText();
var hasBorder = this.style.getFill();
ctx.save();
ctx.scale(ratio,ratio);
ctx.beginPath();
ctx.rect(margin, margin, w-2*margin, h-2*margin);
ctx.clip();
ctx.beginPath();
var txt = {top:[],left:[],bottom:[], right:[]};
for (var x=xmin; x<xmax; x += step)
{ var p0 = ol_proj.transform ([x, ymin], proj, map.getView().getProjection());
p0 = map.getPixelFromCoordinate(p0);
if (hasLines) ctx.moveTo(p0[0], p0[1]);
var p = p0;
for (var y=ymin+step; y<=ymax; y+=step)
{ var p1 = ol_proj.transform ([x, y], proj, map.getView().getProjection());
p1 = map.getPixelFromCoordinate(p1);
if (hasLines) ctx.lineTo(p1[0], p1[1]);
if (p[1]>0 && p1[1]<0) txt.top.push([x, p]);
if (p[1]>h && p1[1]<h) txt.bottom.push([x,p]);
p = p1;
}
}
for (var y=ymin; y<ymax; y += step)
{ var p0 = ol_proj.transform ([xmin, y], proj, map.getView().getProjection());
p0 = map.getPixelFromCoordinate(p0);
if (hasLines) ctx.moveTo(p0[0], p0[1]);
var p = p0;
for (var x=xmin+step; x<=xmax; x+=step)
{ var p1 = ol_proj.transform ([x, y], proj, map.getView().getProjection());
p1 = map.getPixelFromCoordinate(p1);
if (hasLines) ctx.lineTo(p1[0], p1[1]);
if (p[0]<0 && p1[0]>0) txt.left.push([y,p]);
if (p[0]<w && p1[0]>w) txt.right.push([y,p]);
p = p1;
}
}
if (hasLines)
{ ctx.strokeStyle = this.style.getStroke().getColor();
ctx.lineWidth = this.style.getStroke().getWidth();
ctx.stroke();
}
// Draw text
if (hasText)
{
ctx.fillStyle = this.style.getText().getFill().getColor();
ctx.strokeStyle = this.style.getText().getStroke().getColor();
ctx.lineWidth = this.style.getText().getStroke().getWidth();
ctx.textAlign = 'center';
ctx.textBaseline = 'hanging';
var tf;
var offset = (hasBorder ? borderWidth : 0) + margin + 2;
for (var i=0, t; t = txt.top[i]; i++) if (!(Math.round(t[0]/this.get('step'))%step2))
{ tf = this.formatCoord(t[0]);
ctx.strokeText(tf, t[1][0], offset);
ctx.fillText(tf, t[1][0], offset);
}
ctx.textBaseline = 'alphabetic';
for (var i=0, t; t = txt.bottom[i]; i++) if (!(Math.round(t[0]/this.get('step'))%step2))
{ tf = this.formatCoord(t[0]);
ctx.strokeText(tf, t[1][0], h-offset);
ctx.fillText(tf, t[1][0], h-offset);
}
ctx.textBaseline = 'middle';
ctx.textAlign = 'left';
for (var i=0, t; t = txt.left[i]; i++) if (!(Math.round(t[0]/this.get('step'))%step2))
{ tf = this.formatCoord(t[0]);
ctx.strokeText(tf, offset, t[1][1]);
ctx.fillText(tf, offset, t[1][1]);
}
ctx.textAlign = 'right';
for (var i=0, t; t = txt.right[i]; i++) if (!(Math.round(t[0]/this.get('step'))%step2))
{ tf = this.formatCoord(t[0]);
ctx.strokeText(tf, w-offset, t[1][1]);
ctx.fillText(tf, w-offset, t[1][1]);
}
}
// Draw border
if (hasBorder)
{ var fillColor = this.style.getFill().getColor();
var color, stroke;
if (stroke = this.style.getStroke())
{ color = this.style.getStroke().getColor();
}
else
{ color = fillColor;
fillColor = "#fff";
}
ctx.strokeStyle = color;
ctx.lineWidth = stroke ? stroke.getWidth() : 1;
//
for (var i=1; i<txt.top.length; i++)
{ ctx.beginPath();
ctx.rect(txt.top[i-1][1][0], margin, txt.top[i][1][0]-txt.top[i-1][1][0], borderWidth);
ctx.fillStyle = Math.round(txt.top[i][0]/step)%2 ? color: fillColor;
ctx.fill();
ctx.stroke();
}
for (var i=1; i<txt.bottom.length; i++)
{ ctx.beginPath();
ctx.rect(txt.bottom[i-1][1][0], h-borderWidth-margin, txt.bottom[i][1][0]-txt.bottom[i-1][1][0], borderWidth);
ctx.fillStyle = Math.round(txt.bottom[i][0]/step)%2 ? color: fillColor;
ctx.fill();
ctx.stroke();
}
for (var i=1; i<txt.left.length; i++)
{ ctx.beginPath();
ctx.rect(margin, txt.left[i-1][1][1], borderWidth, txt.left[i][1][1]-txt.left[i-1][1][1]);
ctx.fillStyle = Math.round(txt.left[i][0]/step)%2 ? color: fillColor;
ctx.fill();
ctx.stroke();
}
for (var i=1; i<txt.right.length; i++)
{ ctx.beginPath();
ctx.rect(w-borderWidth-margin, txt.right[i-1][1][1], borderWidth, txt.right[i][1][1]-txt.right[i-1][1][1]);
ctx.fillStyle = Math.round(txt.right[i][0]/step)%2 ? color: fillColor;
ctx.fill();
ctx.stroke();
}
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(margin,margin, borderWidth, borderWidth);
ctx.rect(margin,h-borderWidth-margin, borderWidth,borderWidth);
ctx.rect(w-borderWidth-margin,margin, borderWidth, borderWidth);
ctx.rect(w-borderWidth-margin,h-borderWidth-margin, borderWidth,borderWidth);
ctx.fill();
}
ctx.restore();
};
export default ol_control_Graticule

View File

@ -0,0 +1,38 @@
.ol-gridreference
{ background: #fff;
border: 1px solid #000;
overflow: auto;
max-height: 100%;
top:0;
right:0;
}
.ol-gridreference input
{ width:100%;
}
.ol-gridreference ul
{ margin:0;
padding:0;
list-style: none;
}
.ol-gridreference li
{ padding: 0 0.5em;
cursor: pointer;
}
.ol-gridreference ul li:hover
{ background-color: #ccc;
}
.ol-gridreference li.ol-title,
.ol-gridreference li.ol-title:hover
{ background:rgba(0,60,136,.5);
color:#fff;
cursor:default;
}
.ol-gridreference ul li .ol-ref
{ margin-left: 0.5em;
}
.ol-gridreference ul li .ol-ref:before
{ content:"(";
}
.ol-gridreference ul li .ol-ref:after
{ content:")";
}

View File

@ -0,0 +1,309 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_style_Style from 'ol/style/style'
import ol_style_Stroke from 'ol/style/stroke'
import ol_style_Fill from 'ol/style/fill'
import ol_style_Text from 'ol/style/text'
import ol_extent from 'ol/extent'
/**
* Draw a grid reference on the map and add an index.
*
* @constructor
* @extends {ol_control_Control}
* @fires select
* @param {Object=} Control options.
* - style {ol_style_Style} Style to use for drawing the grid (stroke and text), default black.
* - maxResolution {number} max resolution to display the graticule
* - extent {ol.extent} extent of the grid, required
* - size {ol.size} number of lines and cols, required
* - margin {number} margin to display text (in px), default 0px
* - source {ol.source.Vector} source to use for the index, default none (use setIndex to reset the index)
* - property {string | function} a property to display in the index or a function that takes a feature and return the name to display in the index, default 'name'.
* - sortFeatures {function|undefined} sort function to sort 2 features in the index, default sort on property option
* - indexTitle {function|undefined} a function that takes a feature and return the title to display in the index, default the first letter of property option
* - filterLabel {string} label to display in the search bar, default 'filter'
*/
var ol_control_GridReference = function(options)
{ var self = this;
if (!options) options = {};
// Initialize parent
var elt = document.createElement("div");
elt.className = (!options.target ? "ol-control ":"") +"ol-gridreference ol-unselectable "+(options.className||"");
ol_control_Control.call(this,
{ element: elt,
target: options.target
});
if (typeof (options.property)=='function') this.getFeatureName = options.property;
if (typeof (options.sortFeatures)=='function') this.sortFeatures = options.sortFeatures;
if (typeof (options.indexTitle)=='function') this.indexTitle = options.indexTitle;
// Set index using the source
this.source_ = options.source;
if (options.source)
{ this.setIndex(options.source.getFeatures(), options);
// reload on ready
options.source.once('change',function(e)
{ if (options.source.getState() === 'ready')
{ this.setIndex(options.source.getFeatures(), options);
}
}, this);
};
// Options
this.set('maxResolution', options.maxResolution || Infinity);
this.set('extent', options.extent);
this.set('size', options.size);
this.set('margin', options.margin || 0);
this.set('property', options.property || 'name');
this.set('filterLabel', options.filterLabel || 'filter');
if (options.style instanceof ol_style_Style) this.style = options.style;
else this.style = new ol_style_Style(
{ stroke: new ol_style_Stroke({ color:"#000", width:1 }),
text: new ol_style_Text(
{ font: "bold 14px Arial",
stroke: new ol_style_Stroke({ color:"#fff", width:2 }),
fill: new ol_style_Fill({ color:"#000" }),
})
});
};
ol.inherits(ol_control_GridReference, ol_control_Control);
/** Returns the text to be displayed in the index
* @param {ol.Feature} f the feature
* @return {string} the text to be displayed in the index
* @api
*/
ol_control_GridReference.prototype.getFeatureName = function (f)
{ return f.get(this.get('property')||'name');
};
/** Sort function
* @param {ol.Feature} a first feature
* @param {ol.Feature} b second feature
* @return {Number} 0 if a==b, -1 if a<b, 1 if a>b
* @api
*/
ol_control_GridReference.prototype.sortFeatures = function (a,b)
{ return (this.getFeatureName(a) == this.getFeatureName(b)) ? 0 : (this.getFeatureName(a) < this.getFeatureName(b)) ? -1 : 1;
};
/** Get the feature title
* @param {ol.Feature} f
* @return the first letter of the eature name (getFeatureName)
* @api
*/
ol_control_GridReference.prototype.indexTitle = function (f)
{ return this.getFeatureName(f).charAt(0);
};
/** Display features in the index
* @param { Array<ol.Feature> | ol.Collection<ol.Feature> } features
*/
ol_control_GridReference.prototype.setIndex = function (features)
{ if (!this.getMap()) return;
var self = this;
if (features.getArray) features = features.getArray();
features.sort ( function(a,b) { return self.sortFeatures(a,b); } );
var elt = $(this.element).html("");
var search = $("<input>").attr('type', 'search')
.attr('placeholder', this.get('filterLabel') || 'filter')
.on('search keyup', function()
{ var v = $(this).val().replace(/^\*/,'');
// console.log(v)
var r = new RegExp (v, 'i');
$('li',ul).each(function()
{ var self = $(this);
if (self.hasClass('ol-title')) self.show();
else
{ if (r.test($('.ol-name',self).text())) self.show();
else self.hide();
}
});
$("li.ol-title", ul).each(function()
{ var nextVisible = $(this).nextAll("li:visible").first()
if (nextVisible.length && !nextVisible.hasClass('ol-title')) $(this).show();
else $(this).hide();
});
})
.appendTo(elt);
var ul = $("<ul>").appendTo(elt);
var r, title;
for (var i=0, f; f=features[i]; i++)
{ r = this.getReference(f.getGeometry().getFirstCoordinate());
if (r)
{ var name = this.getFeatureName(f);
var c = this.indexTitle(f);
if (c != title)
{ $("<li>").addClass('ol-title').text(c).appendTo(ul);
}
title = c;
$("<li>").append($("<span>").addClass("ol-name").text(name))
.append($("<span>").addClass("ol-ref").text(r))
.data ('feature', f)
.click(function()
{ self.dispatchEvent({ type:"select", feature:$(this).data('feature') });
})
.appendTo(ul);
}
}
};
/** Get reference for a coord
* @param {ol.coordinate} coords
* @return {string} the reference
*/
ol_control_GridReference.prototype.getReference = function (coords)
{ if (!this.getMap()) return;
var extent = this.get('extent');
var size = this.get('size');
var dx = Math.floor ( (coords[0] - extent[0]) / (extent[2]- extent[0]) * size[0] );
if (dx<0 || dx>=size[0]) return "";
var dy = Math.floor ( (extent[3] - coords[1]) / (extent[3]- extent[1]) * size[1] );
if (dy<0 || dy>=size[1]) return "";
return String.fromCharCode(65+dx)+dy;
};
/**
* Remove the control from its current map and attach it to the new map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_control_GridReference.prototype.setMap = function (map)
{ var oldmap = this.getMap();
if (oldmap) oldmap.un('postcompose', this.drawGrid_, this);
ol_control_Control.prototype.setMap.call(this, map);
if (oldmap) oldmap.renderSync();
// Get change (new layer added or removed)
if (map)
{ map.on('postcompose', this.drawGrid_, this);
if (this.source_) this.setIndex(this.source_.getFeatures());
}
};
/** Set style
* @param {ol_style_Style} style
*/
ol_control_GridReference.prototype.setStyle = function (style)
{ this.style = style;
};
/** Get style
* @return {ol_style_Style} style
*/
ol_control_GridReference.prototype.getStyle = function ()
{ return style;
};
/** Draw the grid
* @param {ol.event} e postcompose event
* @private
*/
ol_control_GridReference.prototype.drawGrid_ = function (e)
{ if (this.get('maxResolution')<e.frameState.viewState.resolution) return;
var ctx = e.context;
var canvas = ctx.canvas;
var ratio = e.frameState.pixelRatio;
var w = canvas.width/ratio;
var h = canvas.height/ratio;
var extent = this.get('extent');
var size = this.get('size');
var map = this.getMap();
var ex = ol_extent.boundingExtent([map.getPixelFromCoordinate([extent[0],extent[1]]), map.getPixelFromCoordinate([extent[2],extent[3]])]);
var p0 = [ex[0],ex[1]];
var p1 = [ex[2],ex[3]];
var dx = (p1[0]-p0[0])/size[0];
var dy = (p1[1]-p0[1])/size[1];
ctx.save();
var margin = this.get('margin');
ctx.scale(ratio,ratio);
ctx.strokeStyle = this.style.getStroke().getColor();
ctx.lineWidth = this.style.getStroke().getWidth();
// Draw grid
ctx.beginPath();
for (var i=0; i<=size[0]; i++)
{ ctx.moveTo(p0[0]+i*dx, p0[1]);
ctx.lineTo(p0[0]+i*dx, p1[1]);
}
for (var i=0; i<=size[1]; i++)
{ ctx.moveTo(p0[0], p0[1]+i*dy);
ctx.lineTo(p1[0], p0[1]+i*dy);
}
ctx.stroke();
// Draw text
ctx.font = this.style.getText().getFont();
ctx.fillStyle = this.style.getText().getFill().getColor();
ctx.strokeStyle = this.style.getText().getStroke().getColor();
var lw = ctx.lineWidth = this.style.getText().getStroke().getWidth();
var spacing = margin +lw;
ctx.textAlign = 'center';
var letter, x, y;
for (var i=0; i<size[0]; i++)
{ letter = String.fromCharCode(65+i);
x = p0[0]+i*dx+dx/2;
y = p0[1]-spacing;
if (y<0)
{ y = spacing;
ctx.textBaseline = 'hanging';
}
else ctx.textBaseline = 'alphabetic';
ctx.strokeText(letter, x, y);
ctx.fillText(letter, x, y);
y = p1[1]+spacing;
if (y>h)
{ y = h-spacing;
ctx.textBaseline = 'alphabetic';
}
else ctx.textBaseline = 'hanging';
ctx.strokeText(letter, x, y);
ctx.fillText(letter, x, y);
}
ctx.textBaseline = 'middle';
for (var i=0; i<size[0]; i++)
{ y = p0[1]+i*dy+dy/2;
ctx.textAlign = 'right';
x = p0[0] - spacing;
if (x<0)
{ x = spacing;
ctx.textAlign = 'left';
}
else ctx.textAlign = 'right';
ctx.strokeText(i, x, y);
ctx.fillText(i, x, y);
x = p1[0] + spacing;
if (x>w)
{ x = w-spacing;
ctx.textAlign = 'right';
}
else ctx.textAlign = 'left';
ctx.strokeText(i, x, y);
ctx.fillText(i, x, y);
}
ctx.restore();
};
export default ol_control_GridReference

View File

@ -0,0 +1,58 @@
.ol-control.ol-layerswitcher-popup
{ position: absolute;
right: 0.5em;
text-align: left;
top: 3em;
}
.ol-control.ol-layerswitcher-popup .panel
{ clear:both;
background:#fff;
}
.ol-layerswitcher-popup .panel
{ list-style: none;
padding: 0.25em;
margin:0;
overflow: hidden;
}
.ol-layerswitcher-popup .panel ul
{ list-style: none;
padding: 0 0 0 20px;
overflow: hidden;
}
.ol-layerswitcher-popup.ol-collapsed .panel
{ display:none;
}
.ol-layerswitcher-popup.ol-forceopen .panel
{ display:block;
}
.ol-layerswitcher-popup button
{ background-color: white;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACE1BMVEX///8A//8AgICA//8AVVVAQID///8rVVVJtttgv98nTmJ2xNgkW1ttyNsmWWZmzNZYxM4gWGgeU2JmzNNr0N1Rwc0eU2VXxdEhV2JqytQeVmMhVmNoydUfVGUgVGQfVGQfVmVqy9hqy9dWw9AfVWRpydVry9YhVmMgVGNUw9BrytchVWRexdGw294gVWQgVmUhVWPd4N6HoaZsy9cfVmQgVGRrytZsy9cgVWQgVWMgVWRsy9YfVWNsy9YgVWVty9YgVWVry9UgVWRsy9Zsy9UfVWRsy9YgVWVty9YgVWRty9Vsy9aM09sgVWRTws/AzM0gVWRtzNYgVWRuy9Zsy9cgVWRGcHxty9bb5ORbxdEgVWRty9bn6OZTws9mydRfxtLX3Nva5eRix9NFcXxOd4JPeINQeIMiVmVUws9Vws9Vw9BXw9BYxNBaxNBbxNBcxdJexdElWWgmWmhjyNRlx9IqXGtoipNpytVqytVryNNrytZsjZUuX210k5t1y9R2zNR3y9V4lp57zth9zdaAnKOGoaeK0NiNpquV09mesrag1tuitbmj1tuj19uktrqr2d2svcCu2d2xwMO63N+7x8nA3uDC3uDFz9DK4eHL4eLN4eIyYnDX5OM5Z3Tb397e4uDf4uHf5uXi5ePi5+Xj5+Xk5+Xm5+Xm6OY6aHXQ19fT4+NfhI1Ww89gx9Nhx9Nsy9ZWw9Dpj2abAAAAWnRSTlMAAQICAwQEBgcIDQ0ODhQZGiAiIyYpKywvNTs+QklPUlNUWWJjaGt0dnd+hIWFh4mNjZCSm6CpsbW2t7nDzNDT1dje5efr7PHy9PT29/j4+Pn5+vr8/f39/f6DPtKwAAABTklEQVR4Xr3QVWPbMBSAUTVFZmZmhhSXMjNvkhwqMzMzMzPDeD+xASvObKePPa+ffHVl8PlsnE0+qPpBuQjVJjno6pZpSKXYl7/bZyFaQxhf98hHDKEppwdWIW1frFnrxSOWHFfWesSEWC6R/P4zOFrix3TzDFLlXRTR8c0fEEJ1/itpo7SVO9Jdr1DVxZ0USyjZsEY5vZfiiAC0UoTGOrm9PZLuRl8X+Dq1HQtoFbJZbv61i+Poblh/97TC7n0neCcK0ETNUrz1/xPHf+DNAW9Ac6t8O8WH3Vp98f5lCaYKAOFZMLyHL4Y0fe319idMNgMMp+zWVSybUed/+/h7I4wRAG1W6XDy4XmjR9HnzvDRZXUAYDFOhC1S/Hh+fIXxen+eO+AKqbs+wAo30zDTDvDxKoJN88sjUzDFAvBzEUGFsnADoIvAJzoh2BZ8sner+Ke/vwECuQAAAABJRU5ErkJggg==");
background-position: center;
background-repeat: no-repeat;
float: right;
height: 38px;
width: 38px;
}
.ol-layerswitcher-popup li
{ color:#369;
padding:0.25em 1em;
font-family:"Trebuchet MS",Helvetica,sans-serif;
cursor:pointer;
}
.ol-layerswitcher-popup li.ol-header
{ display: none;
}
.ol-layerswitcher-popup li.select
{ background:rgba(0, 60, 136, 0.7);
color:#fff;
}
.ol-layerswitcher-popup li:hover
{ background:rgba(0, 60, 136, 0.9);
color:#fff;
}

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_LayerSwitcher from './LayerSwitcher'
/**
* OpenLayers 3 Layer Switcher Control.
* @require jQuery
*
* @constructor
* @extends {ol_control_LayerSwitcher}
* @param {Object=} options Control options.
*/
ol_control_LayerPopup = function(options)
{ options = options || {};
options.switcherClass="ol-layerswitcher-popup";
if (options.mouseover!==false) options.mouseover=true;
ol_control_LayerSwitcher.call(this, options);
};
ol.inherits(ol_control_LayerPopup, ol_control_LayerSwitcher);
/** Disable overflow
*/
ol_control_LayerPopup.prototype.overflow = function(){};
/** Render a list of layer
* @param {elt} element to render
* @layers {Array{ol.layer}} list of layer to show
* @api stable
*/
ol_control_LayerPopup.prototype.drawList = function(ul, layers)
{ var self=this;
var setVisibility = function(e)
{ e.preventDefault();
var l = $(this).data("layer");
self.switchLayerVisibility(l,layers);
};
layers.forEach(function(layer)
{ if (layer.get("displayInLayerSwitcher")!==false)
{ var d = $("<li>").text(layer.get("title") || layer.get("name"))
.data ('layer', layer)
.click (setVisibility)
.on ("touchstart", setVisibility)
.appendTo(ul);
if (self.testLayerVisibility(layer)) d.addClass("ol-layer-hidden");
if (layer.getVisible()) d.addClass("select");
}
});
};
export default ol_control_LayerPopup

View File

@ -0,0 +1,440 @@
.ol-control.ol-layerswitcher
{ position: absolute;
right: 0.5em;
text-align: left;
top: 3em;
max-height: calc(100% - 6em);
box-sizing: border-box;
overflow: hidden;
}
.ol-control.ol-layerswitcher .ol-switchertopdiv,
.ol-control.ol-layerswitcher .ol-switcherbottomdiv
{ display: block
}
.ol-control.ol-layerswitcher.ol-collapsed .ol-switchertopdiv,
.ol-control.ol-layerswitcher.ol-collapsed .ol-switcherbottomdiv
{ display: none;
}
.ol-layerswitcher.ol-forceopen.ol-collapsed .ol-switchertopdiv,
.ol-layerswitcher.ol-forceopen.ol-collapsed .ol-switcherbottomdiv
{ display: block;
}
.ol-control.ol-layerswitcher .ol-switchertopdiv,
.ol-control.ol-layerswitcher .ol-switcherbottomdiv
{ position: absolute;
top:0;
left:0;
right:0;
height: 45px;
background: #fff;
z-index:2;
opacity:1;
cursor: pointer;
border-top:2px solid transparent;
border-bottom:2px solid #369;
margin:0 2px;
box-sizing: border-box;
}
.ol-control.ol-layerswitcher .ol-switcherbottomdiv
{ top: auto;
bottom: 0;
height: 2em;
border-top:2px solid #369;
border-bottom:2px solid transparent;
}
.ol-control.ol-layerswitcher .ol-switchertopdiv:before,
.ol-control.ol-layerswitcher .ol-switcherbottomdiv:before
{ content:"";
position: absolute;
left:50%;
top:50%;
border:10px solid transparent;
width:0;
height:0;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
opacity:0.8;
}
.ol-control.ol-layerswitcher .ol-switchertopdiv:hover:before,
.ol-control.ol-layerswitcher .ol-switcherbottomdiv:hover:before
{ opacity:1;
}
.ol-control.ol-layerswitcher .ol-switchertopdiv:before
{ border-bottom-color: #369;
border-top: 0;
}
.ol-control.ol-layerswitcher .ol-switcherbottomdiv:before
{ border-top-color: #369;
border-bottom: 0;
}
.ol-control.ol-layerswitcher .panel
{ background-color: #fff;
border-radius: 0 0 2px 2px;
clear: both;
display: block; /* display:block to show panel on over */
}
.ol-layerswitcher .panel
{ list-style: none;
padding: 0.5em 0.5em 0;
margin:0;
overflow: hidden;
font-family: Tahoma,Geneva,sans-serif;
font-size:0.9em;
-webkit-transition: top 0.3s;
transition: top 0.3s;
position: relative;
top:0;
}
.ol-layerswitcher .panel ul
{ list-style: none;
padding: 0 0 0 20px;
overflow: hidden;
clear: both;
}
/** Customize checkbox
*/
.ol-layerswitcher input[type="radio"],
.ol-layerswitcher input[type="checkbox"]
{ display:none;
}
.ol-layerswitcher .panel li
{ -weblit-transition: -webkit-transform 0.2s linear;
transition: transform 0.2s linear;
clear: both;
display: block;
#border:1px solid transparent;
box-sizing: border-box;
}
/* drag and drop */
.ol-layerswitcher .panel li.drag
{ opacity: 0.5;
transform:scale(0.8);
-webkit-transform:scale(0.8);
}
.ol-dragover
{ background:rgba(51,102,153,0.5);
opacity:0.8;
}
.ol-layerswitcher .panel li.forbidden,
.forbidden .ol-layerswitcher-buttons div,
.forbidden .layerswitcher-opacity div
{ background:rgba(255,0,0,0.5);
color:#f00!important;
}
/* cursor management */
.ol-layerswitcher.drag,
.ol-layerswitcher.drag *
{ cursor:not-allowed!important;
cursor:no-drop!important;
}
.ol-layerswitcher.drag .panel li.dropover,
.ol-layerswitcher.drag .panel li.dropover *
{ cursor: pointer!important;
cursor: n-resize!important;
cursor: ns-resize!important;
cursor: grab!important;
cursor: grabbing!important;
}
.ol-layerswitcher .panel li.dropover
{ background: rgba(51, 102, 153, 0.5);
}
.ol-layerswitcher .panel li label
{ display: inline-block;
height: 1.4em;
max-width: 12em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 0.2em 0 1.7em;
position: relative;
}
.ol-layerswitcher [type="radio"] + label:before,
.ol-layerswitcher [type="checkbox"] + label:before,
.ol-layerswitcher [type="radio"]:checked + label:after,
.ol-layerswitcher [type="checkbox"]:checked + label:after
{ content: '';
position: absolute;
left: 0.1em; top: 0.1em;
width: 1.2em; height: 1.2em;
border: 2px solid #369;
background: #fff;
box-sizing:border-box;
}
.ol-layerswitcher [type="radio"] + label:before,
.ol-layerswitcher [type="radio"] + label:after
{ border-radius: 50%;
}
.ol-layerswitcher [type="radio"]:checked + label:after
{ background: #369 none repeat scroll 0 0;
margin: 0.3em;
width: 0.6em;
height: 0.6em;
}
.ol-layerswitcher [type="checkbox"]:checked + label:after
{ background: transparent;
border-width: 0 3px 3px 0;
border-style: solid;
border-color: #369;
width: 0.7em;
height: 1em;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
left: 0.55em;
top: -0.05em;
box-shadow: 1px 0px 1px 1px #fff;
}
.ol-layerswitcher .panel li.ol-layer-hidden
{ opacity: 0.6;
}
.ol-layerswitcher.ol-collapsed .panel
{ display:none;
}
.ol-layerswitcher.ol-forceopen .panel
{ display:block;
}
.ol-layerswitcher button
{ background-color: white;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACE1BMVEX///8A//8AgICA//8AVVVAQID///8rVVVJtttgv98nTmJ2xNgkW1ttyNsmWWZmzNZYxM4gWGgeU2JmzNNr0N1Rwc0eU2VXxdEhV2JqytQeVmMhVmNoydUfVGUgVGQfVGQfVmVqy9hqy9dWw9AfVWRpydVry9YhVmMgVGNUw9BrytchVWRexdGw294gVWQgVmUhVWPd4N6HoaZsy9cfVmQgVGRrytZsy9cgVWQgVWMgVWRsy9YfVWNsy9YgVWVty9YgVWVry9UgVWRsy9Zsy9UfVWRsy9YgVWVty9YgVWRty9Vsy9aM09sgVWRTws/AzM0gVWRtzNYgVWRuy9Zsy9cgVWRGcHxty9bb5ORbxdEgVWRty9bn6OZTws9mydRfxtLX3Nva5eRix9NFcXxOd4JPeINQeIMiVmVUws9Vws9Vw9BXw9BYxNBaxNBbxNBcxdJexdElWWgmWmhjyNRlx9IqXGtoipNpytVqytVryNNrytZsjZUuX210k5t1y9R2zNR3y9V4lp57zth9zdaAnKOGoaeK0NiNpquV09mesrag1tuitbmj1tuj19uktrqr2d2svcCu2d2xwMO63N+7x8nA3uDC3uDFz9DK4eHL4eLN4eIyYnDX5OM5Z3Tb397e4uDf4uHf5uXi5ePi5+Xj5+Xk5+Xm5+Xm6OY6aHXQ19fT4+NfhI1Ww89gx9Nhx9Nsy9ZWw9Dpj2abAAAAWnRSTlMAAQICAwQEBgcIDQ0ODhQZGiAiIyYpKywvNTs+QklPUlNUWWJjaGt0dnd+hIWFh4mNjZCSm6CpsbW2t7nDzNDT1dje5efr7PHy9PT29/j4+Pn5+vr8/f39/f6DPtKwAAABTklEQVR4Xr3QVWPbMBSAUTVFZmZmhhSXMjNvkhwqMzMzMzPDeD+xASvObKePPa+ffHVl8PlsnE0+qPpBuQjVJjno6pZpSKXYl7/bZyFaQxhf98hHDKEppwdWIW1frFnrxSOWHFfWesSEWC6R/P4zOFrix3TzDFLlXRTR8c0fEEJ1/itpo7SVO9Jdr1DVxZ0USyjZsEY5vZfiiAC0UoTGOrm9PZLuRl8X+Dq1HQtoFbJZbv61i+Poblh/97TC7n0neCcK0ETNUrz1/xPHf+DNAW9Ac6t8O8WH3Vp98f5lCaYKAOFZMLyHL4Y0fe319idMNgMMp+zWVSybUed/+/h7I4wRAG1W6XDy4XmjR9HnzvDRZXUAYDFOhC1S/Hh+fIXxen+eO+AKqbs+wAo30zDTDvDxKoJN88sjUzDFAvBzEUGFsnADoIvAJzoh2BZ8sner+Ke/vwECuQAAAABJRU5ErkJggg==");
background-position: center;
background-repeat: no-repeat;
float: right;
height: 38px;
width: 38px;
z-index: 10;
position: relative;
}
.ol-layerswitcher-buttons
{ display:block;
float: right;
text-align:right;
}
.ol-layerswitcher-buttons > div
{ display: inline-block;
position: relative;
cursor: pointer;
height:1em;
width:1em;
margin:2px;
}
.ol-layerswitcher .panel li > div
{ display: inline-block;
position: relative;
}
/* line break */
.ol-layerswitcher .ol-separator
{ display:block;
width:0;
height:0;
padding:0;
margin:0;
}
.ol-layerswitcher .layerup
{ float: right;
height:2.5em;
background-color: #369;
opacity: 0.5;
cursor: move;
cursor: ns-resize;
}
.ol-layerswitcher .layerup:before,
.ol-layerswitcher .layerup:after
{ border-color: #fff transparent;
border-style: solid;
border-width: 0.4em 0.4em 0;
content: "";
height: 0;
position: absolute;
bottom: 3px;
left: 0.1em;
width: 0;
}
.ol-layerswitcher .layerup:after
{ border-width: 0 0.4em 0.4em;
top:3px;
bottom: auto;
}
.ol-layerswitcher .layerInfo
{ background: #369;
border-radius: 100%;
}
.ol-layerswitcher .layerInfo:before
{ color: #fff;
content: "i";
display: block;
font-size: 0.8em;
font-weight: bold;
text-align: center;
width: 1.25em;
position:absolute;
left: 0;
top: 0;
}
.ol-layerswitcher .layerTrash
{ background: #369;
}
.ol-layerswitcher .layerTrash:before
{ color: #fff;
content: "\00d7";
font-size:1em;
top: 50%;
left: 0;
right: 0;
text-align: center;
line-height: 1em;
margin: -0.5em 0;
position: absolute;
}
.ol-layerswitcher .layerExtent
{ background: #369;
}
.ol-layerswitcher .layerExtent:before
{ border-right: 1px solid #fff;
border-bottom: 1px solid #fff;
content: "";
display: block;
position: absolute;
left: 6px;
right: 2px;
top: 6px;
bottom: 3px;
}
.ol-layerswitcher .layerExtent:after
{ border-left: 1px solid #fff;
border-top: 1px solid #fff;
content: "";
display: block;
position: absolute;
bottom: 6px;
left: 2px;
right: 6px;
top: 3px;
}
.ol-layerswitcher .expend-layers,
.ol-layerswitcher .collapse-layers
{ margin: 0 2px;
}
.ol-layerswitcher .expend-layers:before,
.ol-layerswitcher .collapse-layers:before
{ content:"";
position:absolute;
top:50%;
left:0;
margin-top:-2px;
height:4px;
width:100%;
background:#369;
}
.ol-layerswitcher .expend-layers:after
{ content:"";
position:absolute;
left:50%;
top:0;
margin-left:-2px;
width:4px;
height:100%;
background:#369;
}
/*
.ol-layerswitcher .collapse-layers:before
{ content:"";
position:absolute;
border:0.5em solid #369;
border-color: #369 transparent transparent;
margin-top:0.25em;
}
.ol-layerswitcher .expend-layers:before
{ content:"";
position:absolute;
border:0.5em solid #369;
border-color: transparent transparent transparent #369 ;
margin-left:0.25em;
}
*/
.ol-layerswitcher .layerswitcher-opacity
{ position:relative;
border: 1px solid #369;
height: 3px;
width: 120px;
margin:5px 1em 10px 7px;
box-sizing: border-box;
border-radius: 3px;
background: #69c;
background: -webkit-linear-gradient(left, rgba(0,60,136,0), rgba(0,60,136,0.6));
background: linear-gradient(to right, rgba(0,60,136,0), rgba(0,60,136,0.6));
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0,0,0,0.5);
}
.ol-layerswitcher .layerswitcher-opacity .layerswitcher-opacity-cursor,
.ol-layerswitcher .layerswitcher-opacity .layerswitcher-opacity-cursor:before
{ position: absolute;
width: 20px;
height: 20px;
top: 50%;
left: 50%;
background: rgba(0,60,136,0.5);
border-radius: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
z-index: 1;
}
.ol-layerswitcher .layerswitcher-opacity .layerswitcher-opacity-cursor:before
{ content: "";
position: absolute;
width: 50%;
height: 50%;
}
.ol-touch .ol-layerswitcher .layerswitcher-opacity .layerswitcher-opacity-cursor
{ width: 26px;
height: 26px;
}
.ol-layerswitcher .layerswitcher-opacity-label {
display:none;
position: absolute;
right: -2.5em;
bottom: 5px;
font-size: 0.8em;
}
.ol-layerswitcher .layerswitcher-opacity-label::after {
content:"%";
}
.ol-layerswitcher .layerswitcher-progress
{ display:block;
margin:-4px 1em 2px 7px;
width: 120px;
}
.ol-layerswitcher .layerswitcher-progress div
{ background-color: #369;
height:2px;
display:block;
width:0;
}

View File

@ -0,0 +1,691 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_layer_Tile from 'ol/layer/tile'
import ol_layer_Vector from 'ol/layer/vector'
import ol_layer_VectorTile from 'ol/layer/vectortile'
import ol_layer_Image from 'ol/layer/image'
import ol_layer_Heatmap from 'ol/layer/heatmap'
/**
* @classdesc OpenLayers 3 Layer Switcher Control.
* @require jQuery
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} Control options.
* @param {boolean} options.show_progress show a progress bar on tile layers, default false
* - mouseover {boolean} show the panel on mouseover, default false
* - reordering {boolean} allow layer reordering, default true
* - trash {boolean} add a trash button to delete the layer, default false
* - oninfo {function} callback on click on info button, if none no info button is shown
* - extent {boolean} add an extent button to zoom to the extent of the layer
* - onextent {function} callback when click on extent, default fits view to extent
*
* Layers attributes that control the switcher
* - allwaysOnTop {boolean} true to force layer stay on top of the others while reordering, default false
* - displayInLayerSwitcher {boolean} display in switcher, default true
* - noSwitcherDelete {boolean} to prevent layer deletion (w. trash option), default false
*/
var ol_control_LayerSwitcher = function(opt_options)
{ var options = opt_options || {};
var self = this;
this.dcount = 0;
this.show_progress = options.show_progress;
this.oninfo = (typeof (options.oninfo) == "function" ? options.oninfo: null);
this.onextent = (typeof (options.onextent) == "function" ? options.onextent: null);
this.hasextent = options.extent || options.onextent;
this.hastrash = options.trash;
this.reordering = (options.reordering!==false);
var element;
if (options.target)
{ element = $("<div>").addClass(options.switcherClass || "ol-layerswitcher");
}
else
{ element = $("<div>").addClass((options.switcherClass || 'ol-layerswitcher') +' ol-unselectable ol-control ol-collapsed');
this.button = $("<button>")
.attr('type','button')
.on("touchstart", function(e)
{ element.toggleClass("ol-collapsed");
e.preventDefault();
self.overflow();
})
.click (function()
{ element.toggleClass("ol-forceopen").addClass("ol-collapsed");
self.overflow();
})
.appendTo(element);
if (options.mouseover)
{ $(element).mouseleave (function(){ element.addClass("ol-collapsed"); })
.mouseover(function(){ element.removeClass("ol-collapsed"); });
}
this.topv = $("<div>").addClass("ol-switchertopdiv")
.click(function(){ self.overflow("+50%"); })
.appendTo(element);
this.botv = $("<div>").addClass("ol-switcherbottomdiv")
.click(function(){ self.overflow("-50%"); })
.appendTo(element);
}
this.panel_ = $("<ul>").addClass("panel")
.appendTo(element);
this.panel_.on ('mousewheel DOMMouseScroll onmousewheel', function(e)
{ if (self.overflow(Math.max(-1, Math.min(1, (e.originalEvent.wheelDelta || -e.originalEvent.detail)))))
{ e.stopPropagation();
e.preventDefault();
}
});
this.header_ = $("<li>").addClass("ol-header").appendTo(this.panel_);
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
// Enable jQuery dataTransfert
// $.event.props.push('dataTransfer');
this.target = options.target;
};
ol.inherits(ol_control_LayerSwitcher, ol_control_Control);
/** List of tips
*/
ol_control_LayerSwitcher.prototype.tip =
{ up: "up/down",
down: "down",
info: "informations...",
extent: "zoom to extent",
trash: "remove layer",
plus: "expand/shrink"
}
/**
* Set the map instance the control is associated with.
* @param {_ol_Map_} map The map instance.
*/
ol_control_LayerSwitcher.prototype.setMap = function(map)
{ ol_control_Control.prototype.setMap.call(this, map);
this.drawPanel();
if (this.map_)
{ this.map_.getLayerGroup().un('change', this.drawPanel, this);
this.map_.un('moveend', this.viewChange, this);
this.map_.un('change:size', this.overflow, this);
// console.log("remove");
}
this.map_ = map;
// Get change (new layer added or removed)
if (map)
{ map.getLayerGroup().on('change', this.drawPanel, this);
map.on('moveend', this.viewChange, this);
map.on('change:size', this.overflow, this);
}
};
/** Add a custom header
*/
ol_control_LayerSwitcher.prototype.setHeader = function(html)
{ this.header_.html(html);
};
/** Calculate overflow and add scrolls
* @param {Number} dir scroll direction -1|0|1|'+50%'|'-50%'
*/
ol_control_LayerSwitcher.prototype.overflow = function(dir)
{
if (this.button)
{ // Nothing to show
if (this.panel_.css('display')=='none')
{ $(this.element).css("height", "auto");
return;
}
// Calculate offset
var h = $(this.element).outerHeight();
var hp = this.panel_.outerHeight();
var dh = this.button.position().top + this.button.outerHeight(true);
var top = this.panel_.position().top-dh;
if (hp > h-dh)
{ // Bug IE: need to have an height defined
$(this.element).css("height", "100%");
switch (dir)
{ case 1: top += 2*$("li.visible .li-content",this.panel_).height(); break;
case -1: top -= 2*$("li.visible .li-content",this.panel_).height(); break;
case "+50%": top += Math.round(h/2); break;
case "-50%": top -= Math.round(h/2); break;
default: break;
}
// Scroll div
if (top+hp <= h-3*dh/2)
{ top = h-3*dh/2-hp;
this.botv.hide();
}
else
{ this.botv.css("display","");//show();
}
if (top >= 0)
{ top = 0;
this.topv.hide();
}
else
{ this.topv.css("display","");
}
// Scroll ?
this.panel_.css('top', top+"px");
return true;
}
else
{ $(this.element).css("height", "auto");
this.panel_.css('top', "0px");
this.botv.hide();
this.topv.hide();
return false;
}
}
else return false;
}
/**
* On view change hide layer depending on resolution / extent
* @param {ol.event} map The map instance.
* @private
*/
ol_control_LayerSwitcher.prototype.viewChange = function(e)
{
var map = this.map_;
var res = this.map_.getView().getResolution();
$("li", this.panel_).each(function()
{ var l = $(this).data('layer');
if (l)
{ if (l.getMaxResolution()<=res || l.getMinResolution()>=res) $(this).addClass("ol-layer-hidden");
else
{ var ex0 = l.getExtent();
if (ex0)
{ var ex = map.getView().calculateExtent(map.getSize());
if (!ol.extent.intersects(ex, ex0))
{ $(this).addClass("ol-layer-hidden");
}
else $(this).removeClass("ol-layer-hidden");
}
else $(this).removeClass("ol-layer-hidden");
}
}
});
}
/**
* Draw the panel control (prevent multiple draw due to layers manipulation on the map with a delay function)
*/
ol_control_LayerSwitcher.prototype.drawPanel = function(e)
{
if (!this.getMap()) return;
var self = this;
// Multiple event simultaneously / draw once => put drawing in the event queue
this.dcount++;
setTimeout (function(){ self.drawPanel_(); }, 0);
}
/** Delayed draw panel control
* @private
*/
ol_control_LayerSwitcher.prototype.drawPanel_ = function(e)
{ if (--this.dcount || this.dragging_) return;
$("li", this.panel_).not(".ol-header").remove();
this.drawList (this.panel_, this.getMap().getLayers());
}
/** Change layer visibility according to the baselayer option
* @param {ol.layer}
* @param {Array<ol.layer>} related layers
*/
ol_control_LayerSwitcher.prototype.switchLayerVisibility = function(l, layers)
{
if (!l.get('baseLayer')) l.setVisible(!l.getVisible());
else
{ if (!l.getVisible()) l.setVisible(true);
layers.forEach(function(li)
{ if (l!==li && li.get('baseLayer') && li.getVisible()) li.setVisible(false);
});
}
}
/** Check if layer is on the map (depending on zoom and extent)
* @param {ol.layer}
* @return {boolean}
*/
ol_control_LayerSwitcher.prototype.testLayerVisibility = function(layer)
{
if (this.map_)
{ var res = this.map_.getView().getResolution();
if (layer.getMaxResolution()<=res || layer.getMinResolution()>=res) return false;
else
{ var ex0 = layer.getExtent();
if (ex0)
{ var ex = this.map_.getView().calculateExtent(this.map_.getSize());
return ol.extent.intersects(ex, ex0);
}
return true;
}
}
return true;
};
/** Start ordering the list
* @param {event} e drag event
* @private
*/
ol_control_LayerSwitcher.prototype.dragOrdering_ = function(e)
{ var drag = e.data;
switch (e.type)
{ // Start ordering
case 'mousedown':
case 'touchstart':
{ e.stopPropagation();
e.preventDefault();
var pageY = e.pageY
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageY)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageY);
drag =
{ self: drag.self,
elt: $(e.currentTarget).closest("li"),
start: true,
element: drag.self.element,
panel: drag.self.panel_,
pageY: pageY
};
drag.elt.parent().addClass('drag');
$(document).on("mouseup mousemove touchend touchcancel touchmove", drag, drag.self.dragOrdering_);
break;
}
// Stop ordering
case 'touchcancel':
case 'touchend':
case 'mouseup':
{ if (drag.target)
{ // Get drag on parent
var drop = drag.layer;
var target = drag.target;
if (drop && target)
{ var collection ;
if (drag.group) collection = drag.group.getLayers();
else collection = drag.self.getMap().getLayers();
var layers = collection.getArray();
// Switch layers
for (var i=0; i<layers.length; i++)
{ if (layers[i]==drop)
{ collection.removeAt (i);
break;
}
}
for (var j=0; j<layers.length; j++)
{ if (layers[j]==target)
{ if (i>j) collection.insertAt (j,drop);
else collection.insertAt (j+1,drop);
break;
}
}
}
}
$("li",drag.elt.parent()).removeClass("dropover dropover-after dropover-before");
drag.elt.removeClass("drag");
drag.elt.parent().removeClass("drag");
$(drag.element).removeClass('drag');
if (drag.div) drag.div.remove();
$(document).off("mouseup mousemove touchend touchcancel touchmove", drag.self.dragOrdering_);
break;
}
// Ordering
case 'mousemove':
case 'touchmove':
{ // First drag (more than 2 px) => show drag element (ghost)
var pageY = e.pageY
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageY)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageY);
if (drag.start && Math.abs(drag.pageY - pageY) > 2)
{ drag.start = false;
drag.elt.addClass("drag");
drag.layer = drag.elt.data('layer');
drag.target = false;
drag.group = drag.elt.parent().parent().data('layer');
// Ghost div
drag.div = $("<li>").appendTo(drag.panel);
drag.div.css ({ position: "absolute", "z-index":10000, left:drag.elt.position().left, opacity:0.5 })
.html($(drag.elt).html())
.addClass("ol-dragover")
.width(drag.elt.outerWidth())
.height(drag.elt.height());
$(drag.element).addClass('drag');
}
if (!drag.start)
{ e.preventDefault();
e.stopPropagation();
// Ghost div
drag.div.css ({ top:pageY - drag.panel.offset().top + drag.panel.scrollTop() +5 });
var li;
if (e.pageX) li = $(e.target);
else li = $(document.elementFromPoint(e.originalEvent.touches[0].clientX, e.originalEvent.touches[0].clientY));
if (li.hasClass("ol-switcherbottomdiv"))
{ drag.self.overflow(-1);
console.log('bottom')
}
else if (li.hasClass("ol-switchertopdiv"))
{ drag.self.overflow(1);
}
if (!li.is("li")) li = li.closest("li");
if (!li.hasClass('dropover')) $("li", drag.elt.parent()).removeClass("dropover dropover-after dropover-before");
if (li.parent().hasClass('drag') && li.get(0) !== drag.elt.get(0))
{ var target = li.data("layer");
// Don't mix layer level
if (target && !target.get("allwaysOnTop") == !drag.layer.get("allwaysOnTop"))
{ li.addClass("dropover");
li.addClass((drag.elt.position().top < li.position().top)?"dropover-after":"dropover-before");
drag.target = target;
}
else
{ drag.target = false;
}
drag.div.show();
}
else
{ drag.target = false;
if (li.get(0) === drag.elt.get(0)) drag.div.hide();
else drag.div.show();
}
if (!drag.target) drag.div.addClass("forbidden");
else drag.div.removeClass("forbidden");
}
break;
}
default: break;
}
};
/** Change opacity on drag
* @param {event} e drag event
* @private
*/
ol_control_LayerSwitcher.prototype.dragOpacity_ = function(e)
{ var drag = e.data;
switch (e.type)
{ // Start opacity
case 'mousedown':
case 'touchstart':
{ e.stopPropagation();
e.preventDefault();
drag.start = e.pageX
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageX)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageX);
drag.elt = $(e.target);
drag.layer = drag.elt.closest("li").data('layer')
drag.self.dragging_ = true;
$(document).on("mouseup touchend mousemove touchmove touchcancel", drag, drag.self.dragOpacity_);
break;
}
// Stop opacity
case 'touchcancel':
case 'touchend':
case 'mouseup':
{ $(document).off("mouseup touchend mousemove touchmove touchcancel", drag.self.dragOpacity_);
drag.layer.setOpacity(drag.opacity);
drag.elt.parent().next().text(Math.round(drag.opacity*100));
drag.self.dragging_ = false;
drag = false;
break;
}
// Move opcaity
default:
{ var x = e.pageX
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageX)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageX);
var dx = Math.max ( 0, Math.min( 1, (x - drag.elt.parent().offset().left) / drag.elt.parent().width() ));
drag.elt.css("left", (dx*100)+"%");
drag.elt.parent().next().text(Math.round(drag.opacity*100));
drag.opacity = dx;
drag.layer.setOpacity(dx);
break;
}
}
}
/** Render a list of layer
* @param {elt} element to render
* @layers {Array{ol.layer}} list of layer to show
* @api stable
*/
ol_control_LayerSwitcher.prototype.drawList = function(ul, collection)
{ var self = this;
var layers = collection.getArray();
var setVisibility = function(e)
{ e.stopPropagation();
e.preventDefault();
var l = $(this).parent().parent().data("layer");
self.switchLayerVisibility(l,collection);
};
function moveLayer (l, layers, inc)
{
for (var i=0; i<layers.getLength(); i++)
{ if (layers.item(i) === l)
{ layers.remove(l);
layers.insertAt(i+inc, l);
return true;
}
if (layers.item(i).getLayers && moveLayer (l, layers.item(i).getLayers(), inc)) return true;
}
return false;
};
function moveLayerUp(e)
{ e.stopPropagation();
e.preventDefault();
moveLayer($(this).closest('li').data("layer"), self.map_.getLayers(), +1);
};
function moveLayerDown(e)
{ e.stopPropagation();
e.preventDefault();
moveLayer($(this).closest('li').data("layer"), self.map_.getLayers(), -1);
};
function onInfo(e)
{ e.stopPropagation();
e.preventDefault();
self.oninfo($(this).closest('li').data("layer"));
};
function zoomExtent(e)
{ e.stopPropagation();
e.preventDefault();
if (self.onextent) self.onextent($(this).closest('li').data("layer"));
else self.map_.getView().fit ($(this).closest('li').data("layer").getExtent(), self.map_.getSize());
};
function removeLayer(e)
{ e.stopPropagation();
e.preventDefault();
var li = $(this).closest("ul").parent();
if (li.data("layer"))
{ li.data("layer").getLayers().remove($(this).closest('li').data("layer"));
if (li.data("layer").getLayers().getLength()==0 && !li.data("layer").get('noSwitcherDelete'))
{ removeLayer.call($(".layerTrash", li), e);
}
}
else self.map_.removeLayer($(this).closest('li').data("layer"));
};
// Add the layer list
for (var i=layers.length-1; i>=0; i--)
{ var layer = layers[i];
if (layer.get("displayInLayerSwitcher")===false) continue;
var li = $("<li>").addClass((layer.getVisible()?"visible ":" ")+(layer.get('baseLayer')?"baselayer":""))
.data("layer",layer).appendTo(ul);
var layer_buttons = $("<div>").addClass("ol-layerswitcher-buttons").appendTo(li);
var d = $("<div>").addClass('li-content').appendTo(li);
if (!this.testLayerVisibility(layer)) d.addClass("ol-layer-hidden");
// Visibility
$("<input>")
.attr('type', layer.get('baseLayer') ? 'radio' : 'checkbox')
.attr("checked",layer.getVisible())
.on ('click', setVisibility)
.appendTo(d);
// Label
$("<label>").text(layer.get("title") || layer.get("name"))
.attr('title', layer.get("title") || layer.get("name"))
.on ('click', setVisibility)
.attr('unselectable', 'on')
.css('user-select', 'none')
.on('selectstart', false)
.appendTo(d);
// up/down
if (this.reordering)
{ if ( (i<layers.length-1 && (layer.get("allwaysOnTop") || !layers[i+1].get("allwaysOnTop")) )
|| (i>0 && (!layer.get("allwaysOnTop") || layers[i-1].get("allwaysOnTop")) ) )
{ $("<div>").addClass("layerup")
.on ("mousedown touchstart", {self:this}, this.dragOrdering_ )
.attr("title", this.tip.up)
.appendTo(layer_buttons);
}
}
// Show/hide sub layers
if (layer.getLayers)
{ var nb = 0;
layer.getLayers().forEach(function(l)
{ if (l.get('displayInLayerSwitcher')!==false) nb++;
});
if (nb)
{ $("<div>").addClass(layer.get("openInLayerSwitcher") ? "collapse-layers" : "expend-layers" )
.click(function()
{ var l = $(this).closest('li').data("layer");
l.set("openInLayerSwitcher", !l.get("openInLayerSwitcher") )
})
.attr("title", this.tip.plus)
.appendTo(layer_buttons);
}
}
// $("<div>").addClass("ol-separator").appendTo(layer_buttons);
// Info button
if (this.oninfo)
{ $("<div>").addClass("layerInfo")
.on ('click', onInfo)
.attr("title", this.tip.info)
.appendTo(layer_buttons);
}
// Layer remove
if (this.hastrash && !layer.get("noSwitcherDelete"))
{ $("<div>").addClass("layerTrash")
.on ('click', removeLayer)
.attr("title", this.tip.trash)
.appendTo(layer_buttons);
}
// Layer extent
if (this.hasextent && layers[i].getExtent())
{ var ex = layers[i].getExtent();
if (ex.length==4 && ex[0]<ex[2] && ex[1]<ex[3])
{ $("<div>").addClass("layerExtent")
.on ('click', zoomExtent)
.attr("title", this.tip.extent)
.appendTo(layer_buttons);
}
}
// Progress
if (this.show_progress && layer instanceof ol_layer_Tile)
{ var p = $("<div>")
.addClass("layerswitcher-progress")
.appendTo(d);
this.setprogress_(layer);
layer.layerswitcher_progress = $("<div>").appendTo(p);
}
// Opacity
var opacity = $("<div>").addClass("layerswitcher-opacity")
.on("click", function(e)
{ e.stopPropagation();
e.preventDefault();
var x = e.pageX
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageX)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageX);
var dx = Math.max ( 0, Math.min( 1, (x - $(this).offset().left) / $(this).width() ));
$(this).closest("li").data('layer').setOpacity(dx);
})
.appendTo(d);
$("<div>").addClass("layerswitcher-opacity-cursor")
.on("mousedown touchstart", { self: this }, self.dragOpacity_ )
.css ('left', (layer.getOpacity()*100)+"%")
.appendTo(opacity);
// Percent
$("<div>").addClass("layerswitcher-opacity-label")
.text(Math.round(layer.getOpacity()*100))
.appendTo(d);
// Layer group
if (layer.getLayers)
{ li.addClass('ol-layer-group');
if (layer.get("openInLayerSwitcher")===true)
{ this.drawList ($("<ul>").appendTo(li), layer.getLayers());
}
}
else if (layer instanceof ol_layer_Vector) li.addClass('ol-layer-vector');
else if (layer instanceof ol_layer_VectorTile) li.addClass('ol-layer-vector');
else if (layer instanceof ol_layer_Tile) li.addClass('ol-layer-tile');
else if (layer instanceof ol_layer_Image) li.addClass('ol-layer-image');
else if (layer instanceof ol_layer_Heatmap) li.addClass('ol-layer-heatmap');
}
if (ul==this.panel_) this.overflow();
};
/** Handle progress bar for a layer
* @private
*/
ol_control_LayerSwitcher.prototype.setprogress_ = function(layer)
{
if (!layer.layerswitcher_progress)
{ var loaded = 0;
var loading = 0;
function draw()
{ if (loading === loaded)
{ loading = loaded = 0;
layer.layerswitcher_progress.width(0);
}
else
{ layer.layerswitcher_progress.css('width', (loaded / loading * 100).toFixed(1) + '%');
}
}
layer.getSource().on('tileloadstart', function()
{ loading++;
draw();
});
layer.getSource().on('tileloadend', function()
{ loaded++;
draw();
});
layer.getSource().on('tileloaderror', function()
{ loaded++;
draw();
});
}
}
export default ol_control_LayerSwitcher

View File

@ -0,0 +1,100 @@
.ol-control.ol-layerswitcher-image
{ position: absolute;
right: 0.5em;
text-align: left;
top: 1em;
transition: all 0.2s ease 0s;
-webkit-transition: all 0.2s ease 0s;
}
.ol-control.ol-layerswitcher-image.ol-collapsed
{ top:3em;
transition: none;
-webkit-transition: none;
}
.ol-layerswitcher-image .panel
{ list-style: none;
padding: 0.25em;
margin:0;
overflow: hidden;
}
.ol-layerswitcher-image .panel ul
{ list-style: none;
padding: 0 0 0 20px;
overflow: hidden;
}
.ol-layerswitcher-image.ol-collapsed .panel
{ display:none;
}
.ol-layerswitcher-image.ol-forceopen .panel
{ display:block;
clear:both;
}
.ol-layerswitcher-image button
{ background-color: white;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACE1BMVEX///8A//8AgICA//8AVVVAQID///8rVVVJtttgv98nTmJ2xNgkW1ttyNsmWWZmzNZYxM4gWGgeU2JmzNNr0N1Rwc0eU2VXxdEhV2JqytQeVmMhVmNoydUfVGUgVGQfVGQfVmVqy9hqy9dWw9AfVWRpydVry9YhVmMgVGNUw9BrytchVWRexdGw294gVWQgVmUhVWPd4N6HoaZsy9cfVmQgVGRrytZsy9cgVWQgVWMgVWRsy9YfVWNsy9YgVWVty9YgVWVry9UgVWRsy9Zsy9UfVWRsy9YgVWVty9YgVWRty9Vsy9aM09sgVWRTws/AzM0gVWRtzNYgVWRuy9Zsy9cgVWRGcHxty9bb5ORbxdEgVWRty9bn6OZTws9mydRfxtLX3Nva5eRix9NFcXxOd4JPeINQeIMiVmVUws9Vws9Vw9BXw9BYxNBaxNBbxNBcxdJexdElWWgmWmhjyNRlx9IqXGtoipNpytVqytVryNNrytZsjZUuX210k5t1y9R2zNR3y9V4lp57zth9zdaAnKOGoaeK0NiNpquV09mesrag1tuitbmj1tuj19uktrqr2d2svcCu2d2xwMO63N+7x8nA3uDC3uDFz9DK4eHL4eLN4eIyYnDX5OM5Z3Tb397e4uDf4uHf5uXi5ePi5+Xj5+Xk5+Xm5+Xm6OY6aHXQ19fT4+NfhI1Ww89gx9Nhx9Nsy9ZWw9Dpj2abAAAAWnRSTlMAAQICAwQEBgcIDQ0ODhQZGiAiIyYpKywvNTs+QklPUlNUWWJjaGt0dnd+hIWFh4mNjZCSm6CpsbW2t7nDzNDT1dje5efr7PHy9PT29/j4+Pn5+vr8/f39/f6DPtKwAAABTklEQVR4Xr3QVWPbMBSAUTVFZmZmhhSXMjNvkhwqMzMzMzPDeD+xASvObKePPa+ffHVl8PlsnE0+qPpBuQjVJjno6pZpSKXYl7/bZyFaQxhf98hHDKEppwdWIW1frFnrxSOWHFfWesSEWC6R/P4zOFrix3TzDFLlXRTR8c0fEEJ1/itpo7SVO9Jdr1DVxZ0USyjZsEY5vZfiiAC0UoTGOrm9PZLuRl8X+Dq1HQtoFbJZbv61i+Poblh/97TC7n0neCcK0ETNUrz1/xPHf+DNAW9Ac6t8O8WH3Vp98f5lCaYKAOFZMLyHL4Y0fe319idMNgMMp+zWVSybUed/+/h7I4wRAG1W6XDy4XmjR9HnzvDRZXUAYDFOhC1S/Hh+fIXxen+eO+AKqbs+wAo30zDTDvDxKoJN88sjUzDFAvBzEUGFsnADoIvAJzoh2BZ8sner+Ke/vwECuQAAAABJRU5ErkJggg==");
background-position: center;
background-repeat: no-repeat;
float: right;
height: 38px;
width: 38px;
display:none;
}
.ol-layerswitcher-image.ol-collapsed button
{ display:block;
position:relative;
}
.ol-layerswitcher-image li
{ border-radius: 4px;
border: 3px solid transparent;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.5);
display: inline-block;
width: 64px;
height: 64px;
margin:2px;
position: relative;
background-color: #fff;
overflow: hidden;
vertical-align: middle;
cursor:pointer;
}
.ol-layerswitcher-image li.ol-layer-hidden
{ opacity: 0.5;
border-color:#555;
}
.ol-layerswitcher-image li.ol-header
{ display: none;
}
.ol-layerswitcher-image li img
{ position:absolute;
max-width:100%;
}
.ol-layerswitcher-image li.select
{ border: 3px solid red;
}
.ol-layerswitcher-image li p
{ display:none;
}
.ol-layerswitcher-image li:hover p
{ background-color: rgba(0, 0, 0, 0.5);
color: #fff;
bottom: 0;
display: block;
left: 0;
margin: 0;
overflow: hidden;
position: absolute;
right: 0;
text-align: center;
height:1.2em;
font-family:Verdana, Geneva, sans-serif;
font-size:0.8em;
}

View File

@ -0,0 +1,68 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_LayerSwitcher from './LayerSwitcher'
/**
* @classdesc OpenLayers 3 Layer Switcher Control.
* @require layer.getPreview
* @require jQuery
*
* @constructor
* @extends {ol_control_LayerSwitcher}
* @param {Object=} options Control options.
*/
var ol_control_LayerSwitcherImage = function(options)
{ options = options || {};
options.switcherClass="ol-layerswitcher-image";
if (options.mouseover!==false) options.mouseover=true;
ol_control_LayerSwitcher.call(this, options);
};
ol.inherits(ol_control_LayerSwitcherImage, ol_control_LayerSwitcher);
/** Render a list of layer
* @param {elt} element to render
* @layers {Array{ol.layer}} list of layer to show
* @api stable
*/
ol_control_LayerSwitcherImage.prototype.drawList = function(ul, layers)
{ var self = this;
var setVisibility = function(e)
{ e.preventDefault();
var l = $(this).data("layer");
self.switchLayerVisibility(l,layers);
if (e.type=="touchstart") $(self.element).addClass("ol-collapsed");
};
ul.css("height","auto");
layers.forEach(function(layer)
{ if (layer.get("displayInLayerSwitcher")!==false)
{ var prev = layer.getPreview ? layer.getPreview() : ["none"];
var d = $("<li>").addClass("ol-imgcontainer")
.data ('layer', layer)
.click (setVisibility)
.on ("touchstart", setVisibility);
if (layer.getVisible()) d.addClass("select");
for (var k=0; k<prev.length; k++)
{ $("<img>").attr('src', prev[k])
.appendTo(d);
}
$("<p>").text(layer.get("title") || layer.get("name")).appendTo(d);
if (self.testLayerVisibility(layer)) d.addClass("ol-layer-hidden");
d.appendTo(ul);
}
});
};
/** Disable overflow
*/
ol_control_LayerSwitcherImage.prototype.overflow = function(){};
export default ol_control_LayerSwitcherImage

117
build/control/Overlay.css Normal file
View File

@ -0,0 +1,117 @@
.ol-overlay
{ position: absolute;
top: 0;
left: 0;
width:100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
padding: 1em;
color: #fff;
box-sizing: border-box;
z-index: 1;
opacity: 0;
display: none;
cursor: default;
overflow: hidden;
-webkit-transition: all 0.5s;
transition: all 0.5s;
}
.ol-overlay.slide-up
{ transform: translateY(100%);
-webkit-transform: translateY(100%);
}
.ol-overlay.slide-down
{ -webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
.ol-overlay.slide-left
{ -webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
.ol-overlay.slide-right
{ -webkit-transform: translateX(100%);
transform: translateX(100%);
}
.ol-overlay.zoom
{ top: 50%;
left: 50%;
opacity:0.5;
-webkit-transform: translate(-50%,-50%) scale(0);
transform: translate(-50%,-50%) scale(0);
}
.ol-overlay.zoomout
{ -webkit-transform: scale(3);
transform: scale(3);
}
.ol-overlay.zoomrotate
{ top: 50%;
left: 50%;
opacity:0.5;
-webkit-transform: translate(-50%,-50%) scale(0) rotate(360deg);
transform: translate(-50%,-50%) scale(0) rotate(360deg);
}
.ol-overlay.stretch
{ top: 50%;
left: 50%;
opacity:0.5;
-webkit-transform: translate(-50%,-50%) scaleX(0);
transform: translate(-50%,-50%) scaleX(0) ;
}
.ol-overlay.stretchy
{ top: 50%;
left: 50%;
opacity:0.5;
-webkit-transform: translate(-50%,-50%) scaleY(0);
transform: translate(-50%,-50%) scaleY(0) ;
}
.ol-overlay.wipe
{ opacity: 1;
/* clip: must be set programmatically */
/* clip-path: use % but not crossplatform (IE) */
}
.ol-overlay.flip
{ -webkit-transform: perspective(600px) rotateY(180deg);
transform: perspective(600px) rotateY(180deg);
}
.ol-overlay.card
{ opacity: 0.5;
-webkit-transform: translate(-80%, 100%) rotate(-0.5turn);
transform: translate(-80%, 100%) rotate(-0.5turn);
}
.ol-overlay.book
{ -webkit-transform: perspective(600px) rotateY(-180deg) scaleX(0.6);
transform: perspective(600px) rotateY(-180deg) scaleX(0.6) ;
-webkit-transform-origin: 10% 50%;
transform-origin: 10% 50%;
}
.ol-overlay.book.visible
{ -webkit-transform-origin: 10% 50%;
transform-origin: 10% 50%;
}
.ol-overlay.ol-visible
{ opacity:1;
top: 0;
left: 0;
right: 0;
bottom: 0;
-webkit-transform: none;
transform: none;
}
.ol-overlay .ol-closebox
{ position: absolute;
top: 1em;
right: 1em;
width: 1em;
height: 1em;
cursor: pointer;
z-index:1;
}
.ol-overlay .ol-closebox:before
{ content: "\274c";
display: block;
text-align: center;
vertical-align: middle;
}

119
build/control/Overlay.js Normal file
View File

@ -0,0 +1,119 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/** Control overlay for OL3
* The overlay control is a control that display an overlay over the map
*
* @constructor
* @extends {ol_control_Control}
* @fire change:visible
* @param {Object=} options Control options.
* - className {String} class of the control
* - hideOnClick {bool} hide the control on click, default false
* - closeBox {bool} add a closeBox to the control, default false
*/
var ol_control_Overlay = function(options)
{ if (!options) options={};
var element = $("<div>").addClass('ol-unselectable ol-overlay');
if (options.className) element.addClass(options.className);
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
var self = this;
if (options.hideOnClick) element.click(function(){self.hide();});
this.set("closeBox", options.closeBox);
this._timeout = false;
this.setContent (options.content);
};
ol.inherits(ol_control_Overlay, ol_control_Control);
/** Set the content of the overlay
* @param {string} html the html to display in the control (or a jQuery object)
*/
ol_control_Overlay.prototype.setContent = function (html)
{ var self = this;
if (html)
{ var elt = $(this.element);
elt.html(html);
if (this.get("closeBox"))
{ var cb = $("<div>").addClass("ol-closebox")
.click(function(){self.hide();});
elt.prepend(cb);
}
};
};
/** Set the control visibility
* @param {string} html the html to display in the control (or a jQuery object)
* @param {ol.coordinate} coord coordinate of the top left corner of the control to start from
*/
ol_control_Overlay.prototype.show = function (html, coord)
{ var self = this;
var elt = $(this.element).show();
if (coord)
{ this.center_ = this.getMap().getPixelFromCoordinate(coord);
elt.css({"top":this.center_[1], "left":this.center_[0] });
}
else
{
//TODO: Do fix from hkollmann pull request
this.center_ = false;
elt.css({"top":"", "left":"" });
}
this.setContent(html);
if (this._timeout) clearTimeout(this._timeout);
this._timeout = setTimeout(function()
{ elt.addClass("ol-visible")
.css({ "top":"", "left":"" });
self.dispatchEvent({ type:'change:visible', visible:true, element: self.element });
}, 10);
self.dispatchEvent({ type:'change:visible', visible:false, element: self.element });
};
/** Set the control visibility hidden
*/
ol_control_Overlay.prototype.hide = function ()
{ var elt = $(this.element).removeClass("ol-visible");
if (this.center_)
{ elt.css({"top":this.center_[1], "left":this.center_[0] })
this.center_ = false;
}
if (this._timeout) clearTimeout(this._timeout);
this._timeout = setTimeout(function(){ elt.hide(); }, 500);
this.dispatchEvent({ type:'change:visible', visible:false, element: this.element });
};
/** Toggle control visibility
*/
ol_control_Overlay.prototype.toggle = function ()
{ if (this.getVisible()) this.hide();
else this.show();
}
/** Get the control visibility
* @return {boolean} b
*/
ol_control_Overlay.prototype.getVisible = function ()
{ return ($(this.element).css('display') != 'none');
};
/** Change class name
* @param {String} className
*/
ol_control_Overlay.prototype.setClass = function (className)
{ var vis = $(this.element).hasClass("ol-visible");
$(this.element).removeClass().addClass('ol-unselectable ol-overlay'+(vis?" ol-visible ":" ")+className);
};
export default ol_control_Overlay

View File

@ -0,0 +1,59 @@
.ol-control.ol-overview
{ position: absolute;
left: 0.5em;
text-align: left;
bottom: 0.5em;
}
.ol-control.ol-overview .panel
{ display:block;
width:150px;
height:150px;
margin:2px;
background-color:#fff;
border:1px solid #369;
cursor: pointer;
}
.ol-overview:not(.ol-collapsed) button
{ position:absolute;
bottom:2px;
left:2px;
z-index:2;
}
.ol-control.ol-overview.ol-collapsed .panel
{ display:none;
}
.ol-overview.ol-collapsed button:before
{ content:'\00bb';
}
.ol-overview button:before
{ content:'\00ab';
}
.ol-control-right.ol-overview
{ left: auto;
right: 0.5em;
}
.ol-control-right.ol-overview:not(.ol-collapsed) button
{ left:auto;
right:2px;
}
.ol-control-right.ol-overview.ol-collapsed button:before
{ content:'\00ab';
}
.ol-control-right.ol-overview button:before
{ content:'\00bb';
}
.ol-control-top.ol-overview
{ bottom: auto;
top: 5em;
}
.ol-control-top.ol-overview:not(.ol-collapsed) button
{ bottom:auto;
top:2px;
}

308
build/control/Overview.js Normal file
View File

@ -0,0 +1,308 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_geom_Polygon from 'ol/geom/polygon'
import ol_geom_Point from 'ol/geom/point'
import ol_interaction_Pointer from 'ol/interaction/pointer'
import ol_easing from 'ol/easing'
import ol_Map from 'ol/map'
import ol_Collection from 'ol/collection'
import ol_View from 'ol/view'
import ol_source_Vector from 'ol/source/vector'
import ol_style_Style from 'ol/style/style'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Fill from 'ol/style/fill'
import ol_style_Stroke from 'ol/style/stroke'
import ol_layer_Vector from 'ol/layer/vector'
import ol_Feature from 'ol/feature'
//TODO: replace ol.animation.pan with new {ol_interaction_Interaction.pan}
//import ol_interaction_Interaction from 'ol/interaction/interaction'
/**
* OpenLayers 3 Layer Overview Control.
* The overview can rotate with map.
* Zoom levels are configurable.
* Click on the overview will center the map.
* Change width/height of the overview trough css.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options Control options.
* @param {ol.ProjectionLike} options.projection The projection. Default is EPSG:3857 (Spherical Mercator).
* @param {Number} options.minZoom default 0
* @param {Number} options.maxZoom default 18
* @param {boolean} options.rotation enable rotation, default false
* @param {top|bottom-left|right} options.align position
* @param {Array<ol.layer>} options.layers list of layers
* @param {ol.style.Style | Array.<ol.style.Style> | undefined} options.style style to draw the map extent on the overveiw
* @param {bool|elastic} options.panAnimation use animation to center map on click, default true
*/
var ol_control_Overview = function(options)
{ options = options || {};
var self = this;
// API
this.minZoom = options.minZoom || 0;
this.maxZoom = options.maxZoom || 18;
this.rotation = options.rotation;
var element;
if (options.target)
{ element = $("<div>");
this.panel_ = $(options.target);
}
else
{ element = $("<div>").addClass('ol-overview ol-unselectable ol-control ol-collapsed');
if (/top/.test(options.align)) element.addClass('ol-control-top');
if (/right/.test(options.align)) element.addClass('ol-control-right');
$("<button>").on("touchstart", function(e){ self.toggleMap(); e.preventDefault(); })
.attr('type','button')
.click (function(){self.toggleMap()})
.appendTo(element);
this.panel_ = $("<div>").addClass("panel")
.appendTo(element);
}
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
// Create a overview map
this.ovmap_ = new ol_Map(
{ controls: new ol_Collection(),
interactions: new ol_Collection(),
target: this.panel_.get(0),
view: new ol_View
({ zoom: 14,
center: [270148, 6247782],
projection: options.projection
}),
layers: options.layers
});
this.oview_ = this.ovmap_.getView();
// Cache extent
this.extentLayer = new ol_layer_Vector(
{ name: 'Cache extent',
source: new ol_source_Vector(),
style: options.style || [new ol_style_Style(
{ image: new ol_style_Circle(
{ fill: new ol_style_Fill({
color: 'rgba(255,0,0, 1)'
}),
stroke: new ol_style_Stroke(
{ width: 7,
color: 'rgba(255,0,0, 0.8)'
}),
radius: 5
}),
stroke: new ol_style_Stroke(
{ width: 5,
color: "rgba(255,0,0,0.8)"
})
}
)]
})
this.ovmap_.addLayer(this.extentLayer);
/** Elastic bounce
* @param {Int} bounce number of bounce
* @param {Number} amplitude amplitude of the bounce [0,1]
* @return {Number}
*/
ol_easing.bounceFn = function (bounce, amplitude)
{ var a = (2*bounce+1) * Math.PI/2;
var b = amplitude>0 ? -1/amplitude : -100;
var c = - Math.cos(a) * Math.pow(2, b);
return function(t)
{ t = 1-Math.cos(t*Math.PI/2);
return 1 + Math.abs( Math.cos(a*t) ) * Math.pow(2, b*t) + c*t;
}
}
/** Elastic bounce
* @param {Int} bounce number of bounce
* @param {Number} amplitude amplitude of the bounce [0,1]
* @return {Number}
*/
ol_easing.elasticFn = function (bounce, amplitude)
{ var a = 3*bounce * Math.PI/2;
var b = amplitude>0 ? -1/amplitude : -100;
var c = Math.cos(a) * Math.pow(2, b);
return function(t)
{ t = 1-Math.cos(t*Math.PI/2);
return 1 - Math.cos(a*t) * Math.pow(2, b*t) + c*t;
}
}
// Click on the preview center the map
this.ovmap_.addInteraction (new ol_interaction_Pointer(
{ handleDownEvent: function(evt)
{ //TODO: Old version OL3
if (ol.animation)
{ var pan;
if (options.panAnimation !==false)
{ if (options.panAnimation=="elastic" || options.elasticPan)
{ pan = ol.animation.pan(
{ duration: 1000,
easing: ol_easing.elasticFn(2,0.3),
source: self.getMap().getView().getCenter()
});
}
else
{ pan = ol.animation.pan(
{ duration: 300,
source: self.getMap().getView().getCenter()
});
}
}
self.getMap().beforeRender(pan);
self.getMap().getView().setCenter(evt.coordinate);
}
else
{ if (options.panAnimation !==false)
{ if (options.panAnimation=="elastic" || options.elasticPan)
{ self.getMap().getView().animate(
{ center: evt.coordinate,
easing: ol_easing.elasticFn(2,0.3),
duration: 1000
});
}
else
{ self.getMap().getView().animate(
{ center: evt.coordinate,
duration: 300
});
}
}
else self.getMap().getView().setCenter(evt.coordinate);
}
return false;
}
}));
};
ol.inherits(ol_control_Overview, ol_control_Control);
/** Get overview map
* @return {ol.Map}
*/
ol_control_Overview.prototype.getOverviewMap = function()
{ return this.ovmap_;
}
/** Toggle overview map
*/
ol_control_Overview.prototype.toggleMap = function()
{ $(this.element).toggleClass("ol-collapsed");
this.ovmap_.updateSize();
}
/** Set overview map position
* @param {top|bottom-left|right}
*/
ol_control_Overview.prototype.setPosition = function(align)
{ if (/top/.test(align)) $(this.element).addClass("ol-control-top");
else $(this.element).removeClass("ol-control-top");
if (/right/.test(align)) $(this.element).addClass("ol-control-right");
else $(this.element).removeClass("ol-control-right");
}
/**
* Set the map instance the control associated with.
* @param {ol.Map} map The map instance.
*/
ol_control_Overview.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().getView().un('propertychange', this.setView, this);
}
ol_control_Control.prototype.setMap.call(this, map);
if (map)
{ map.getView().on('propertychange', this.setView, this);
this.setView();
}
};
/** Calculate the extent of the map and draw it on the overview
*/
ol_control_Overview.prototype.calcExtent_ = function(extent)
{ var map = this.getMap();
if (!map) return;
var source = this.extentLayer.getSource();
source.clear();
var f = new ol_Feature();
var size = map.getSize();
var resolution = map.getView().getResolution();
var rotation = map.getView().getRotation();
var center = map.getView().getCenter();
if (!resolution) return;
var dx = resolution * size[0] / 2;
var dy = resolution * size[1] / 2;
var res2 = this.oview_.getResolution();
if (dx/res2>5 || dy/res2>5)
{ var cos = Math.cos(rotation);
var sin = Math.sin(rotation);
var i, x, y;
extent=[[-dx,-dy],[-dx,dy],[dx,dy],[dx,-dy]];
for (i = 0; i < 4; ++i)
{ x = extent[i][0];
y = extent[i][1];
extent[i][0] = center[0] + x * cos - y * sin;
extent[i][1] = center[1] + x * sin + y * cos;
}
f.setGeometry (new ol_geom_Polygon( [ extent ]));
}
else
{ f.setGeometry (new ol_geom_Point( center ));
}
source.addFeature(f);
}
/**
* @private
*/
ol_control_Overview.prototype.setView = function(e)
{ if (!e)
{ // refresh all
this.setView({key:'rotation'});
this.setView({key:'resolution'});
this.setView({key:'center'});
return;
}
// Set the view params
switch (e.key)
{ case 'rotation':
if (this.rotation) this.oview_.setRotation(this.getMap().getView().getRotation());
else if (this.oview_.getRotation()) this.oview_.setRotation(0);
break;
case 'center':
{ var mapExtent = this.getMap().getView().calculateExtent(this.getMap().getSize());
var extent = this.oview_.calculateExtent(this.ovmap_.getSize());
if (mapExtent[0]<extent[0] || mapExtent[1]<extent[1]
|| mapExtent[2]>extent[2] || mapExtent[3]>extent[3])
{ this.oview_.setCenter(this.getMap().getView().getCenter());
}
break;
}
case 'resolution':
{ var z = Math.round(this.getMap().getView().getZoom()/2)*2-4;
z = Math.min ( this.maxZoom, Math.max(this.minZoom, z) );
this.oview_.setZoom(z);
break;
}
default: break;
}
this.calcExtent_();
}
export default ol_control_Overview

View File

@ -0,0 +1,14 @@
.ol-permalink
{ position: absolute;
top:0.5em;
right: 2.5em;
}
.ol-touch .ol-permalink
{ right: 3em;
}
.ol-permalink button
{ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcFBjYE1ZK03gAAAUlJREFUOMuVk71KA1EQhc/NaiP+gCRpFHwGBSFlCrFVfAsbwSJCBMv06QIGJOBziI3EYAgkjU8gIloIAasIn4WzMqx34zrN7J6de+6ZmbNSgQDSfADcATPgHbgCyvonSYv8KEzWdofegH3gwmG9Ikq67sAESFzNueHThTyiEIKAmr2OJCUhhO30Aou+5aUQU2Ik65K2JC1KegohPGfUBkmvksqShnntHEcGOs60NXHfjmKz6czZTsNqbhzW+muwY2ATWAWawCOwBgxcTfvnvCPxKx4Cy5bPgBWgauRpdL2ImNlGhp3MabETm8mh94nDk4yCNE5/KTGg7xxbyhYAG0AN2AEqURIDZ0a0Fxn+LXAPXDpzRqMk6cOedz1ubdYl1b6NHgZRJe72nuu/CdSBl+yKi/zZlTnbaeXOJIesClwDU+ATeEhtX5TkCwAWUyAsHH1QAAAAAElFTkSuQmCC');
background-position: center;
background-repeat: no-repeat;
}

246
build/control/Permalink.js Normal file
View File

@ -0,0 +1,246 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_proj from 'ol/proj'
/**
* Permalink Control.
*
* Add a `permalink`property to layers to be handled by the control (and added in the url).
* The layer's permalink property is used to name the layer in the url.
* The control must be added after all layer are inserted in the map to take them into acount.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} options
* @param {bool} options.urlReplace replace url or not, default true
* @param {integer} options.fixed number of digit in coords, default 6
* @param {bool} options.anchor use "#" instead of "?" in href
* @param {function} options.onclick a function called when control is clicked
*/
var ol_control_Permalink = function(opt_options)
{ var options = opt_options || {};
var self = this;
var button = document.createElement('button');
this.replaceState_ = (options.urlReplace!==false);
this.fixed_ = options.fixed || 6;
this.hash_ = options.anchor ? "#" : "?";
function linkto()
{ if (typeof(options.onclick) == 'function') options.onclick(self.getLink());
else self.setUrlReplace(!self.replaceState_);
}
button.addEventListener('click', linkto, false);
button.addEventListener('touchstart', linkto, false);
var element = document.createElement('div');
element.className = (options.className || "ol-permalink") + " ol-unselectable ol-control";
element.appendChild(button);
ol_control_Control.call(this,
{ element: element,
target: options.target
});
this.on ('change', this.viewChange_, this);
// Save search params
this.search_ = {};
var hash = document.location.hash || document.location.search;
if (hash)
{ hash = hash.replace(/(^#|^\?)/,"").split("&");
for (var i=0; i<hash.length; i++)
{ var t = hash[i].split("=");
switch(t[0])
{ case 'lon':
case 'lat':
case 'z':
case 'r':
case 'l': break;
default: this.search_[t[0]] = t[1];
}
}
}
// Decode permalink
this.setPosition();
};
ol.inherits(ol_control_Permalink, ol_control_Control);
/**
* Set the map instance the control associated with.
* @param {ol.Map} map The map instance.
*/
ol_control_Permalink.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().getLayerGroup().un('change', this.layerChange_, this);
this.getMap().un('moveend', this.viewChange_, this);
}
ol_control_Control.prototype.setMap.call(this, map);
// Get change
if (map)
{ map.getLayerGroup().on('change', this.layerChange_, this);
map.on('moveend', this.viewChange_, this);
this.setPosition();
}
};
/** Get layer given a permalink name (permalink propertie in the layer)
* @param {string} the permalink to search for
* @param {Array<ol.layer>|undefined} an array of layer to search in
* @return {ol.layer|false}
*/
ol_control_Permalink.prototype.getLayerByLink = function (id, layers)
{ if (!layers && this.getMap()) layers = this.getMap().getLayers().getArray();
for (var i=0; i<layers.length; i++)
{ if (layers[i].get('permalink') == id) return layers[i];
// Layer Group
if (layers[i].getLayers)
{ var li = this.getLayerByLink ( id, layers[i].getLayers().getArray() );
if (li) return li;
}
}
return false;
}
/** Set map position according to the current link
*/
ol_control_Permalink.prototype.setPosition = function()
{ var map = this.getMap();
if (!map) return;
var hash = document.location.hash || document.location.search;
if (!hash) return;
var param = {};
hash = hash.replace(/(^#|^\?)/,"").split("&");
for (var i=0; i<hash.length; i++)
{ var t = hash[i].split("=");
param[t[0]] = t[1];
}
var c = ol_proj.transform([Number(param.lon),Number(param.lat)], 'EPSG:4326', map.getView().getProjection());
if (c[0] && c[1]) map.getView().setCenter(c);
if (param.z) map.getView().setZoom(Number(param.z));
if (param.r) map.getView().setRotation(Number(param.r));
if (param.l)
{ var l = param.l.split("|");
// Reset layers
function resetLayers(layers)
{ if (!layers) layers = map.getLayers().getArray();
for (var i=0; i<layers.length; i++)
{ if (layers[i].get('permalink'))
{ layers[i].setVisible(false);
// console.log("hide "+layers[i].get('permalink'));
}
if (layers[i].getLayers)
{ resetLayers (layers[i].getLayers().getArray());
}
}
}
resetLayers();
for (var i=0; i<l.length; i++)
{ var t = l[i].split(":");
var li = this.getLayerByLink(t[0]);
var op = Number(t[1]);
if (li)
{ li.setOpacity(op);
li.setVisible(true);
}
}
}
}
/**
* Get the parameters added to the url. The object can be changed to add new values.
* @return {Object} a key value object added to the url as &key=value
* @api stable
*/
ol_control_Permalink.prototype.getUrlParams = function()
{ return this.search_;
}
/**
* Get the permalink
* @return {permalink}
*/
ol_control_Permalink.prototype.getLink = function()
{ var map = this.getMap();
var c = ol_proj.transform(map.getView().getCenter(), map.getView().getProjection(), 'EPSG:4326');
var z = map.getView().getZoom();
var r = map.getView().getRotation();
var l = this.layerStr_;
// Change anchor
var anchor = "lon="+c[0].toFixed(this.fixed_)+"&lat="+c[1].toFixed(this.fixed_)+"&z="+z+(r?"&r="+(Math.round(r*10000)/10000):"")+(l?"&l="+l:"");
for (var i in this.search_) anchor += "&"+i+"="+this.search_[i];
//return document.location.origin+document.location.pathname+this.hash_+anchor;
return document.location.protocol+"//"+document.location.host+document.location.pathname+this.hash_+anchor;
}
/**
* Enable / disable url replacement (replaceSate)
* @param {bool}
*/
ol_control_Permalink.prototype.setUrlReplace = function(replace)
{ try{
this.replaceState_ = replace;
if (!replace)
{ var s = "";
for (var i in this.search_)
{ s += (s==""?"?":"&") + i+"="+this.search_[i];
}
window.history.replaceState (null,null, document.location.origin+document.location.pathname+s);
}
else window.history.replaceState (null,null, this.getLink());
}catch(e){}
}
/**
* On view change refresh link
* @param {ol.event} The map instance.
* @private
*/
ol_control_Permalink.prototype.viewChange_ = function()
{ try{
if (this.replaceState_) window.history.replaceState (null,null, this.getLink());
}catch(e){}
}
/**
* Layer change refresh link
* @param {ol.event} The map instance.
* @private
*/
ol_control_Permalink.prototype.layerChange_ = function(e)
{ // Get layers
var l = "";
function getLayers(layers)
{ for (var i=0; i<layers.length; i++)
{ if (layers[i].getVisible() && layers[i].get("permalink"))
{ if (l) l += "|";
l += layers[i].get("permalink")+":"+layers[i].get("opacity");
}
// Layer Group
if (layers[i].getLayers) getLayers(layers[i].getLayers().getArray());
}
}
getLayers(this.getMap().getLayers().getArray());
this.layerStr_ = l;
this.viewChange_();
}
export default ol_control_Permalink

View File

@ -0,0 +1,11 @@
.pirate_back
{ /** Image Chris Fiedler - CC0 - https://pixabay.com/fr/papier-vieux-texture-parchemin-1074136/ */
/*TODO: check if the image relative path is good*/
background-image: url("piratecontrol.jpg");
}
.pirate_compass
{ background-image: url("piratecontrol.png");
}
.ol-pirate
{ display:none;
}

242
build/control/PirateMap.js Normal file
View File

@ -0,0 +1,242 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_color from 'ol/color'
/** ol_control_PirateMap adds an old map effect on a canvas renderer.
* It colors the map, adds a parchment texture and compass onto the map.
* @param {Object}
* - hue {ol.Color} color to set hue of the map, default #963
* - saturation {Number} saturation of the hue color, default 0.6
* - opacity {Number} opacity of the overimpose image, default 0.7
*/
var ol_control_PirateMap = function(options)
{
// deprecated
console.error("ol_control_PirateMap is deprecated. Use a combination of ol.filter.Texture + ol.controlCompass + ol.control.Clip.\n"
+"See http://viglino.github.io/ol-ext/examples/map.pirate.html")
options = options || {};
var self = this;
this.asset = {};
this.hue = (options.hue ? ol_color.asString(options.hue) : "#963");
this.saturation = options.saturation || 0.6;
this.opacity = options.opacity || 0.7;
// Get image in css
this.asset.back = new Image();
this.asset.back.onload = function(){ if (self.map_) self.map_.renderSync(); }
var i = $("<img>").addClass("pirate_back").appendTo("body");
this.asset.back.src = i.css("background-image").replace(/^url\(\"(.*)\"\)$/,"$1");
i.remove();
this.asset.compass = new Image();
this.asset.compass.onload = function(){ if (self.map_) self.map_.renderSync(); }
var i = $("<img>").addClass("pirate_compass").appendTo("body");
this.asset.compass.src = i.css("background-image").replace(/^url\(\"(.*)\"\)$/,"$1");
i.remove();
var div = document.createElement('div');
div.className = "ol-pirate ol-unselectable ol-control";
ol_control_Control.call(this,
{ element: div,
target: options.target
});
};
ol.inherits(ol_control_PirateMap, ol_control_Control);
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_control_PirateMap.prototype.setMap = function (map)
{ ol_control_Control.prototype.setMap.call(this, map);
if (this.map_)
{ this.map_.un('precompose', this.drawMask_, this);
this.map_.un('postcompose', this.drawPirate_, this);
}
if (map)
{ map.on('precompose', this.drawMask_, this);
map.on('postcompose', this.drawPirate_, this);
}
this.map_ = map;
};
(function() {
var crop = [[0.023, 0.957], [0, 0.463], [0.007, 0.42], [0.004, 0.397], [0.029, 0.383], [0.013, 0.383], [0.046, 0.367], [0.011, 0.371], [0.004, 0.349], [0.006, 0.297], [0.012, 0.265], [0.007, 0.246], [0.016, 0.191], [0.031, 0.191], [0.019, 0.171], [0.012, 0.1], [0.046, 0.001], [0.071, 0.012], [0.1, 0], [0.186, 0.01], [0.228, 0.008], [0.239, 0.022], [0.25, 0.009], [0.304, 0.002], [0.311, 0.027], [0.313, 0.007], [0.322, 0.064], [0.311, 0.101], [0.329, 0.055], [0.321, 0.018], [0.334, 0.01], [0.496, 0.009], [0.53, 0.019], [0.553, 0.01], [0.615, 0.014], [0.683, 0.03], [0.697, 0.019], [0.728, 0.027], [0.732, 0.066], [0.735, 0.012], [0.752, 0.006], [0.795, 0.014], [0.85, 0.007], [0.929, 0.013], [1, 0.204], [0.994, 0.324], [0.999, 0.393], [0.988, 0.464], [0.947, 0.46], [0.977, 0.47], [0.978, 0.479], [0.99, 0.489], [0.994, 0.572], [0.992, 0.669], [0.982, 0.673], [0.994, 0.689], [1, 0.716], [0.999, 0.81], [0.987, 0.816], [0.996, 0.83], [0.99, 0.894], [0.944, 1], [0.848, 0.993], [0.841, 0.97], [0.837, 0.993], [0.798, 0.981], [0.697, 0.98], [0.653, 0.986], [0.606, 0.981], [0.598, 0.968], [0.598, 0.941], [0.592, 0.982], [0.558, 0.988], [0.507, 0.983], [0.485, 0.988], [0.418, 0.978], [0.4, 0.969], [0.393, 0.98], [0.338, 0.984], [0.304, 0.977], [0.251, 0.984], [0.238, 0.979], [0.252, 0.915], [0.239, 0.969], [0.233, 0.953], [0.23, 0.984], [0.155, 0.971], [0.147, 0.957], [0.142, 0.974], [0.095, 0.976], [0.066, 0.98], [0.023, 0.957]];
ol_control_PirateMap.prototype.drawMask_ = function (event)
{
var ctx = event.context;
var canvas = ctx.canvas;
var w = canvas.width;
var h = canvas.height;
ctx.save();
/*
ctx.lineWidth = 5;
ctx.strokeStyle = "rgba(0,0,0,0.3)";
ctx.beginPath();
ctx.moveTo(w*crop[0][0]+2, h*crop[0][1]+2);
for (var i=1; i<crop.length; i++)
ctx.lineTo(w*crop[i][0]+2, h*crop[i][1]+2);
ctx.closePath();
ctx.stroke();
*/
ctx.beginPath();
ctx.moveTo(w*crop[0][0], h*crop[0][1]);
for (var i=1; i<crop.length; i++)
ctx.lineTo(w*crop[i][0], h*crop[i][1]);
ctx.clip();
};
/** Draw on the final canvas
* @private
*/
function drawlines(ctx, cx, cy, m)
{
ctx.moveTo (cx+m, cy);
ctx.lineTo(cx-m, cy);
ctx.moveTo (cx, cy+m);
ctx.lineTo(cx, cy-m);
ctx.moveTo (cx+m, cy+m);
ctx.lineTo(cx-m, cy-m);
ctx.moveTo (cx+m, cy-m);
ctx.lineTo(cx-m, cy+m);
ctx.moveTo (cx+m/2, cy-3*m/2);
ctx.lineTo(cx-m/2, cy+3*m/2);
ctx.moveTo (cx+m/2, cy+3*m/2);
ctx.lineTo(cx-m/2, cy-3*m/2);
ctx.moveTo (cx+3*m/2, cy+m/2);
ctx.lineTo(cx-3*m/2, cy-m/2);
ctx.moveTo (cx+3*m/2, cy-m/2);
ctx.lineTo(cx-3*m/2, cy+m/2);
}
function drawCompass(ctx, compass, cx, cy, rot, sc, m)
{ ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rot);
ctx.beginPath();
drawlines(ctx, 0, 0, m*1.5)
ctx.stroke();
if (sc)
{ ctx.globalAlpha = 1;
ctx.drawImage (compass, -compass.width/2*sc, -compass.height/2*sc, compass.width*sc, compass.height*sc);
}
ctx.restore();
}
ol_control_PirateMap.prototype.drawPirate_ = function (event)
{ if (!this.map_) return;
var ctx = event.context;
var canvas = ctx.canvas;
var ratio = event.frameState.pixelRatio;
var view = this.map_.getView();
var img = this.asset.back;
var compass = this.asset.compass;
var m = Math.max(canvas.width, canvas.height);
var res = view.getResolution()/ratio;
var rot = view.getRotation();
// Set back color hue
ctx.save();
//ctx.scale(ratio, ratio);
ctx.globalCompositeOperation = "color";
ctx.fillStyle = this.hue;
ctx.globalAlpha = this.saturation;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.restore();
// Draw back image
ctx.save();
var ext = event.frameState.extent;
var dx = ext[0]/res;
var dy = ext[1]/res;
dx = dx % img.width ;
dy = img.height - dy % img.height;
if (dx<0) dx += img.width;
if (dy<0) dy += img.height;
ctx.globalCompositeOperation = "multiply";
ctx.globalAlpha = this.opacity;
ctx.rotate(rot);
for (var i=-dx-m; i<m; i+=img.width)
for (var j=-dy-m; j<m; j+=img.height)
{ ctx.drawImage(img, i,j);
}
ctx.restore();
// Draw compass
ctx.save();
ctx.lineWidth = 1;
ctx.strokeStyle = this.hue;
ctx.globalCompositeOperation = "multiply";
ctx.globalAlpha = this.opacity;
drawCompass (ctx, compass, canvas.width*0.9, canvas.height*0.9, rot, ratio, m*1.5);
drawCompass (ctx, compass, compass.width/2 + canvas.width*0.05, canvas.height*0.5, rot, 0.5*ratio, m*1.5);
ctx.restore();
// Restore clip
ctx.restore();
/** /
ctx.save();
ctx.strokeStyle = "rgba(0,0,0,0.3)";
ctx.globalCompositeOperation = "multiply";
ctx.globalAlpha = 0.3;
var w=canvas.width;
var h=canvas.height;
for (var lw=3; lw>0; lw--)
{
ctx.beginPath();
ctx.lineWidth = 4*lw;
ctx.moveTo(w*crop[0][0]+2, h*crop[0][1]+2);
for (var i=1; i<crop.length; i++)
ctx.lineTo(w*crop[i][0]+2, h*crop[i][1]+2);
ctx.closePath();
ctx.stroke();
}
ctx.restore();
/**/
}
})();
export default ol_control_PirateMap

102
build/control/Profil.css Normal file
View File

@ -0,0 +1,102 @@
.ol-control.ol-profil
{ position: absolute;
top: 0.5em;
right: 3em;
text-align: right;
overflow: hidden;
}
.ol-profil .ol-inner
{ position: relative;
padding: 0.5em;
font-size: 0.8em;
}
.ol-control.ol-profil .ol-inner
{ display: block;
background-color: rgba(255,255,255,0.7);
margin: 2.3em 2px 2px;
}
.ol-control.ol-profil.ol-collapsed .ol-inner
{ display: none;
}
.ol-profil canvas
{ display: block;
}
.ol-profil button
{ display: block;
position: absolute;
right: 2px;
background-position: center;
background-repeat: no-repeat;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAPCAYAAAALWoRrAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AgXCR4dn7j9TAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAz0lEQVQ4y7WTMU4CURRFz0xIpLUBEhdAY2tJYW1jaWlsXYVxDWyBhWCFCYugYgnDFPMOhTMJGf3AwHiqn/uTk5v/3gfAH6b0RH7sMiIe1Ts162z+q2lVVbd1XqijLuJk0zzP1/VxCGyApLgsy+HJphGx8DeFOm6L1bn6eVQaEW+m2amTRqx+1fkqKY2Ie0+zUx/U7WGYfNMsy57PmMMN8A1MWsWeUoPyivV8PWtPOzL7D+lYHfUtBXgHGLTCJfBxodD6k9Dsm8BLE17LobQ39nJC61aLVoVsAAAAAElFTkSuQmCC');
}
.ol-profil.ol-collapsed button
{ position: static;
}
.ol-profil .ol-profilbar,
.ol-profil .ol-profilcursor
{ position:absolute;
pointer-events: none;
width: 1px;
display: none;
}
.ol-profil .ol-profilcursor
{ width: 0;
height: 0;
}
.ol-profil .ol-profilcursor:before
{ content:"";
pointer-events: none;
display: block;
margin: -2px;
width:5px;
height:5px;
}
.ol-profil .ol-profilbar,
.ol-profil .ol-profilcursor:before
{ background: red;
}
.ol-profil table
{ text-align: center;
}
.ol-profil table span
{ display: block;
}
.ol-profilpopup
{ background-color: rgba(255, 255, 255, 0.5);
margin: 0.5em;
padding: 0 0.5em;
position: absolute;
top:-1em;
white-space: nowrap;
}
.ol-profilpopup.ol-left
{ right:0;
}
.ol-profil table td
{ padding: 0 2px;
}
.ol-profil table .track-info
{ display: table-row;
}
.ol-profil table .point-info
{ display: none;
}
.ol-profil .over table .track-info
{ display: none;
}
.ol-profil .over table .point-info
{ display: table-row;
}
.ol-profil p
{ text-align: center;
margin:0;
}

377
build/control/Profile.js Normal file
View File

@ -0,0 +1,377 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_Sphere from 'ol/sphere'
import ol_proj from 'ol/proj'
/**
* @classdesc OpenLayers 3 Profil Control.
* Draw a profil of a feature (with a 3D geometry)
*
* @constructor
* @extends {ol_control_Control}
* @fires over, out, show
* @param {Object=} _ol_control_ opt_options.
*
*/
var ol_control_Profil = function(opt_options)
{ var options = opt_options || {};
this.info = options.info || ol_control_Profil.prototype.info;
var self = this;
var element;
if (options.target)
{ element = $("<div>").addClass(options.className || "ol-profil");
}
else
{ element = $("<div>").addClass((options.className || 'ol-profil') +' ol-unselectable ol-control ol-collapsed');
this.button = $("<button>")
.attr('type','button')
.on("click touchstart", function(e)
{ self.toggle();
e.preventDefault();
})
.appendTo(element);
}
var div = $("<div>").addClass("ol-inner").appendTo(element);
div = $("<div>").css("position","relative").appendTo(div);
var ratio = this.ratio = 2;
this.canvas_ = document.createElement('canvas');
this.canvas_.width = (options.width || 300)*ratio;
this.canvas_.height = (options.height || 150)*ratio;
$(this.canvas_).css({
"transform":"scale(0.5,0.5)", "transform-origin":"0 0",
"-ms-transform":"scale(0.5,0.5)", "-ms-transform-origin":"0 0",
"-webkit-transform":"scale(0.5,0.5)", "-webkit-transform-origin":"0 0",
"transform":"scale(0.5,0.5)", "transform-origin":"0 0"
});
$("<div>").appendTo(div)
.width (this.canvas_.width/ratio)
.height (this.canvas_.height/ratio)
.append(this.canvas_)
.on("click mousemove", function(e){ self.onMove(e); });
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
// Offset in px
this.margin_ = { top:10*ratio, left:40*ratio, bottom:30*ratio, right:10*ratio };
if (!this.info.ytitle) this.margin_.left -= 20*ratio;
if (!this.info.xtitle) this.margin_.bottom -= 20*ratio;
// Cursor
this.bar_ = $("<div>").addClass("ol-profilbar")
.css({top:(this.margin_.top/ratio)+"px", height:(this.canvas_.height-this.margin_.top-this.margin_.bottom)/ratio+"px" })
.appendTo(div);
this.cursor_ = $("<div>").addClass("ol-profilcursor")
.appendTo(div);
this.popup_ = $("<div>").addClass("ol-profilpopup")
.appendTo(this.cursor_);
// Track information
var t = $("<table cellpadding='0' cellspacing='0'>").appendTo(div).width(this.canvas_.width/ratio);
var tr = $("<tr>").addClass("track-info").appendTo(t);
$("<td>").html((this.info.zmin||"Zmin")+': <span class="zmin">').appendTo(tr);
$("<td>").html((this.info.zmax||"Zmax")+': <span class="zmax">').appendTo(tr);
$("<td>").html((this.info.distance||"Distance")+': <span class="dist">').appendTo(tr);
$("<td>").html((this.info.time||"Time")+': <span class="time">').appendTo(tr);
tr = $("<tr>").addClass("point-info").appendTo(t);
$("<td>").html((this.info.altitude||"Altitude")+': <span class="z">').appendTo(tr);
$("<td>").html((this.info.distance||"Distance")+': <span class="dist">').appendTo(tr);
$("<td>").html((this.info.time||"Time")+': <span class="time">').appendTo(tr);
// Array of data
this.tab_ = [];
// Show feature
if (options.feature)
{ this.setGeometry (options.feature);
}
};
ol.inherits(ol_control_Profil, ol_control_Control);
/** Custom infos list
* @api stable
*/
ol_control_Profil.prototype.info =
{ "zmin": "Zmin",
"zmax": "Zmax",
"ytitle": "Altitude (m)",
"xtitle": "Distance (km)",
"time": "Time",
"altitude": "Altitude",
"distance": "Distance"
};
/** Show popup info
* @param {string} info to display as a popup
* @api stable
*/
ol_control_Profil.prototype.popup = function(info)
{ this.popup_.html(info);
}
/** Mouse move over canvas
*/
ol_control_Profil.prototype.onMove = function(e)
{ if (!this.tab_.length) return;
var pos = $(this.canvas_).offset();
var dx = e.pageX -pos.left;
var dy = e.pageY -pos.top;
var ratio = this.ratio;
if (dx>this.margin_.left/ratio && dx<(this.canvas_.width-this.margin_.right)/ratio
&& dy>this.margin_.top/ratio && dy<(this.canvas_.height-this.margin_.bottom)/ratio)
{ this.bar_.css("left", dx+"px").show();
var d = (dx*ratio-this.margin_.left)/this.scale_[0];
var p0 = this.tab_[0];
for (var i=1, p; p=this.tab_[i]; i++)
{ if (p[0]>=d)
{ if (d < (p[0]+p0[0])/2) p = p0;
break;
}
}
if (p) this.cursor_.css({
left:dx+"px",
top:(this.canvas_.height-this.margin_.bottom+p[1]*this.scale_[1]+this.dy_)/ratio+"px"
}).show();
else this.cursor_.hide();
this.bar_.parent().addClass("over");
$(".point-info .z", this.element).text(p[1]+"m");
$(".point-info .dist", this.element).text((p[0]/1000).toFixed(1)+"km");
$(".point-info .time", this.element).text(p[2]);
if (dx>this.canvas_.width/ratio/2) this.popup_.addClass('ol-left');
else this.popup_.removeClass('ol-left');
this.dispatchEvent({ type:'over', click:e.type=="click", coord: p[3], time: p[2], distance: p[0] });
}
else
{ if (this.bar_.parent().hasClass("over"))
{ this.bar_.hide();
this.cursor_.hide();
this.bar_.parent().removeClass("over");
this.dispatchEvent({ type:'out' });
}
}
}
/** Show panel
* @api stable
*/
ol_control_Profil.prototype.show = function()
{ $(this.element).removeClass("ol-collapsed");
this.dispatchEvent({ type:'show', show: true });
}
/** Hide panel
* @api stable
*/
ol_control_Profil.prototype.hide = function()
{ $(this.element).addClass("ol-collapsed");
this.dispatchEvent({ type:'show', show: false });
}
/** Toggle panel
* @api stable
*/
ol_control_Profil.prototype.toggle = function()
{ var b = $(this.element).toggleClass("ol-collapsed").hasClass("ol-collapsed");
this.dispatchEvent({ type:'show', show: !b });
}
/** Is panel visible
*/
ol_control_Profil.prototype.isShown = function()
{ return (!$(this.element).hasClass("ol-collapsed"));
}
/**
* Set the geometry to draw the profil.
* @param {ol.Feature|ol.geom} f the feature.
* @param {Object=} options
* - projection {ol.ProjectionLike} feature projection, default projection of the map
* - zunit {m|km} default m
* - unit {m|km} default km
* - zmin {Number|undefined} default 0
* - zmax {Number|undefined} default max Z of the feature
* - graduation {Number|undefined} z graduation default 100
* - amplitude {integer|undefined} amplitude of the altitude, default zmax-zmin
* @api stable
*/
ol_control_Profil.prototype.setGeometry = function(g, options)
{ if (!options) options = {};
if (g instanceof ol.Feature) g = g.getGeometry();
var canvas = this.canvas_;
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0, w, h);
// No Z
if (!/Z/.test(g.getLayout())) return;
// No time
if(/M/.test(g.getLayout())) $(".time", this.element).parent().show();
else $(".time", this.element).parent().hide();
// Coords
var c = g.getCoordinates();
switch (g.getType())
{ case "LineString": break;
case "MultiLineString": c = c[0]; break;
default: return;
}
// Distance beetween 2 coords
var wgs84Sphere = new ol_Sphere(6378137);
var proj = options.projection || this.getMap().getView().getProjection();
function dist2d(p1,p2)
{ return wgs84Sphere.haversineDistance(
ol_proj.transform(p1, proj, 'EPSG:4326'),
ol_proj.transform(p2, proj, 'EPSG:4326'));
}
function getTime(t0, t1)
{ if (!t0 || !t1) return "-"
var dt = (t1-t0) / 60; // mn
var ti = Math.trunc(dt/60);
var mn = Math.trunc(dt-ti*60);
return ti+"h"+(mn<10?"0":"")+mn+"mn";
}
// Margin
ctx.setTransform(1, 0, 0, 1, this.margin_.left, h-this.margin_.bottom);
var ratio = this.ratio;
w -= this.margin_.right + this.margin_.left;
h -= this.margin_.top + this.margin_.bottom;
// Draw axes
ctx.strokeStyle = "#000";
ctx.lineWidth = 0.5*ratio;
ctx.beginPath();
ctx.moveTo(0,0); ctx.lineTo(0,-h);
ctx.moveTo(0,0); ctx.lineTo(w, 0);
ctx.stroke();
//
var zmin=Infinity, zmax=-Infinity;
var d, z, ti, t = this.tab_ = [];
for (var i=0, p; p=c[i]; i++)
{ z = p[2];
if (z<zmin) zmin=z;
if (z>zmax) zmax=z;
if (i==0) d = 0;
else d += dist2d(c[i-1], p);
ti = getTime(c[0][3],p[3]);
t.push ([d, z, ti, p]);
}
// Info
$(".track-info .zmin", this.element).text(zmin.toFixed(2)+"m");
$(".track-info .zmax", this.element).text(zmax.toFixed(2)+"m");
if (d>1000)
{ $(".track-info .dist", this.element).text((d/1000).toFixed(1)+"km");
}
else
{ $(".track-info .dist", this.element).text((d).toFixed(1)+"m");
}
$(".track-info .time", this.element).text(ti);
// Set graduation
var grad = options.graduation || 100;
while (true)
{ zmax = Math.ceil(zmax/grad)*grad;
zmin = Math.floor(zmin/grad)*grad;
var nbgrad = (zmax-zmin)/grad;
if (h/nbgrad < 15*ratio)
{ grad *= 2;
}
else break;
}
// Set amplitude
if (typeof(options.zmin)=='number' && zmin > options.zmin) zmin = options.zmin;
if (typeof(options.zmax)=='number' && zmax < options.zmax) zmax = options.zmax;
var amplitude = options.amplitude;
if (amplitude)
{ zmax = Math.max (zmin + amplitude, zmax);
}
// Scales lines
var scx = w/d;
var scy = -h/(zmax-zmin);
var dy = this.dy_ = -zmin*scy;
this.scale_ = [scx,scy];
// Draw
ctx.font = (10*ratio)+"px arial";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
ctx.fillStyle="#000";
// Scale Z
ctx.beginPath();
for (var i=zmin; i<=zmax; i+=grad)
{ if (options.zunit!="km") ctx.fillText(i, -4*ratio, i*scy+dy);
else ctx.fillText((i/1000).toFixed(1), -4*ratio, i*scy+dy);
ctx.moveTo (-2*ratio, i*scy+dy);
if (i!=0) ctx.lineTo (d*scx, i*scy+dy);
else ctx.lineTo (0, i*scy+dy);
}
// Scale X
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.setLineDash([ratio,3*ratio]);
var unit = options.unit ||"km";
var step;
if (d>1000)
{ step = Math.round(d/1000)*100;
if (step > 1000) step = Math.ceil(step/1000)*1000;
}
else
{ unit = "m";
if (d>100) step = Math.round(d/100)*10;
else if (d>10) step = Math.round(d/10);
else if (d>1) step = Math.round(d)/10;
else step = d;
}
for (var i=0; i<=d; i+=step)
{ var txt = (unit=="m") ? i : (i/1000);
//if (i+step>d) txt += " "+ (options.zunits || "km");
ctx.fillText(Math.round(txt*10)/10, i*scx, 4*ratio);
ctx.moveTo (i*scx, 2*ratio); ctx.lineTo (i*scx, 0);
}
ctx.font = (12*ratio)+"px arial";
ctx.fillText(this.info.xtitle.replace("(km)","("+unit+")"), w/2, 18*ratio);
ctx.save();
ctx.rotate(-Math.PI/2);
ctx.fillText(this.info.ytitle, h/2, -this.margin_.left);
ctx.restore();
ctx.stroke();
//
ctx.strokeStyle = "#369";
ctx.lineWidth = 1;
ctx.setLineDash([]);
ctx.beginPath();
for (var i=0, p; p=t[i]; i++)
{ if (i==0) ctx.moveTo(p[0]*scx,p[1]*scy+dy);
else ctx.lineTo(p[0]*scx,p[1]*scy+dy);
}
ctx.stroke();
};
/** Get profil image
* @param {string|undefined} type image format or 'canvas' to get the canvas image, default image/png.
* @param {Number|undefined} encoderOptions between 0 and 1 indicating image quality image/jpeg or image/webp, default 0.92.
* @return {string} requested data uri
* @api stable
*/
ol_control_Profil.prototype.getImage = function(type, encoderOptions)
{ if (type==="canvas") return this.canvas_;
return this.canvas_.toDataURL(type, encoderOptions);
}
export default ol_control_Profil

65
build/control/Search.css Normal file
View File

@ -0,0 +1,65 @@
.ol-search
{ top: 0.5em;
left: 3em;
}
.ol-touch .ol-search
{ left: 3.5em;
}
.ol-search button
{ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAABPUlEQVQoU41SwXHCQAzUHh58eoUOIBWEDkI6oAToIKkg7iAuwakgpAIowXRACcnrzp6BzchjMx4wE/S6kW5XK60gvQghzJIkmVoqSZI9gJ9+/fINS5Cc1HX9QXIlIr/tpwcRyb33b7cIGnAIYQdg4pxbjcfj0nJ1Xc+Px+PGObdN03Q9RIAQwgpAnqbp7FKmjQGgJLlU1d2V7BjjRkQO3vvXIXarkyxVNbsCm2QR2Q0V7XOMMReRmfd+OQQubN6hYgs22ZtbnRcAtiRfLueqqmpJ8ovko6oeBq0KIWQA3gFkzrlmMafTaUEyI/mpqmbhVTRWWbRdbClPbeobQNES5KPRqOxs7DBn8K1DsAOKMZYApiTXqlrcDe4d0XN7jWeCfzt351tVle2iGalTcBd4gGDvvZ/fDe4RmCOFLe8Pr7mvEP2N9PQAAAAASUVORK5CYII=");
background-repeat: no-repeat;
background-position: center center;
background-size: 1em;
top: 2px;
left: 2px;
float: left;
}
.ol-search input
{ display: inline-block;
border: 0;
margin: 1px 1px 1px 2px;
font-size: 1.14em;
padding-left: 0.3em;
height: 1.375em;
box-sizing: border-box;
transition: all 0.1s;
}
.ol-touch .ol-search input,
.ol-touch .ol-search ul
{ font-size: 1.5em;
}
.ol-control.ol-search.ol-collapsed ul,
.ol-control.ol-search.ol-collapsed input
{ display: none;
}
.ol-search ul
{ list-style: none;
padding: 0;
margin: 0;
display: block;
clear: both;
cursor: pointer;
max-width: 17em;
overflow-x: hidden;
}
/*
.ol-control.ol-search ul
{ position: absolute;
background: #fff;
box-shadow: 5px 5px 5px rgba(0,0,0,0.5);
}
*/
.ol-control.ol-search ul li
{ padding: 0.1em 0.5em;
}
.ol-search ul li
{ white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ol-search ul li.select,
.ol-search ul li:hover
{ background-color: rgba(0,60,136,.5);
color: #fff;
}

197
build/control/Search.js Normal file
View File

@ -0,0 +1,197 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/**
* Search Control.
* This is the base class for search controls. You can use it for simple custom search or as base to new class.
* @see ol_control_SearchFeature
* @see ol_control_SearchPhoton
*
* @constructor
* @extends {ol_control_Control}
* @fires select
* @fires change:input
* @param {Object=} options
* @param {string} options.className control class name
* @param {Element | string | undefined} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
* @param {string | undefined} options.label Text label to use for the search button, default "search"
* @param {string | undefined} options.placeholder placeholder, default "Search..."
* @param {number | undefined} options.typing a delay on each typing to start searching (ms) use -1 to prevent autocompletion, default 300.
* @param {integer | undefined} options.minLength minimum length to start searching, default 1
* @param {integer | undefined} options.maxItems maximum number of items to display in the autocomplete list, default 10
* @param {function} options.getTitle a function that takes a feature and return the name to display in the index.
* @param {function} options.autocomplete a function that take a search string and callback function to send an array
*/
var ol_control_Search = function(options)
{ var self = this;
if (!options) options = {};
if (options.typing == undefined) options.typing = 300;
var element;
if (options.target)
{ element = $("<div>").addClass((options.className||"")+ " ol-search");
}
else
{ element = $("<div>").addClass((options.className||"") + ' ol-search ol-unselectable ol-control ol-collapsed');
this.button = $("<button>")
.attr('type','button')
.attr('title',options.label||"search")
.click (function()
{ element.toggleClass("ol-collapsed");
if (!element.hasClass("ol-collapsed"))
{ $("input.search", element).focus();
$('li', element).removeClass('select');
}
})
.appendTo(element);
}
// Search input
var tout, cur="";
$("<input>").attr('type','search')
.addClass("search")
.attr('placeholder', options.placeholder||"Search...")
.on('change', function(e)
{ self.dispatchEvent({ type:"change:input", input:e, value:$(this).val() });
})
.on('keyup search cut paste input', function(e)
{ // console.log(e.type+" "+e.key)
var li = $("ul.autocomplete li.select", element);
var val = $(this).val();
// move up/down
if (e.key=='ArrowDown' || e.key=='ArrowUp' || e.key=='Down' || e.key=='Up')
{ li.removeClass('select');
li = (/Down/.test(e.key)) ? li.next() : li.prev();
if (li.length) li.addClass('select');
else $("ul.autocomplete li",element).first().addClass('select');
}
// Clear input
else if (e.type=='input' && !val)
{ self.drawList_();
}
// Select in the list
else if (li.length && (e.type=="search" || e.key =='Enter'))
{ if (element.hasClass("ol-control")) $(this).blur();
li.removeClass('select');
cur = val;
self.select(li.data('search'));
}
// Search / autocomplete
else if ( (e.type=="search" || e.key =='Enter')
|| (cur!=val && options.typing>=0))
{ // current search
cur = val;
if (cur)
{ // prevent searching on each typing
if (tout) clearTimeout(tout);
tout = setTimeout(function()
{ if (cur.length >= self.get("minLength"))
{ var s = self.autocomplete (cur, function(auto) { self.drawList_(auto); });
if (s) self.drawList_(s);
}
else self.drawList_();
}, options.typing);
}
else self.drawList_();
}
// Clear list selection
else
{ $("ul.autocomplete li", element).removeClass('select');
}
})
.blur(function()
{ setTimeout(function(){ element.addClass('ol-collapsed') }, 200);
})
.focus(function()
{ element.removeClass('ol-collapsed')
})
.appendTo(element);
// Autocomplete list
$("<ul>").addClass('autocomplete').appendTo(element);
ol_control_Control.call(this,
{ element: element.get(0),
target: options.target
});
if (typeof (options.getTitle)=='function') this.getTitle = options.getTitle;
if (typeof (options.autocomplete)=='function') this.autocomplete = options.autocomplete;
// Options
this.set('minLength', options.minLength || 1);
this.set('maxItems', options.maxItems || 10);
};
ol.inherits(ol_control_Search, ol_control_Control);
/** Returns the text to be displayed in the menu
* @param {any} f feature to be displayed
* @return {string} the text to be displayed in the index, default f.name
* @api
*/
ol_control_Search.prototype.getTitle = function (f)
{ return f.name || "No title";
};
/** Force search to refresh
*/
ol_control_Search.prototype.search = function ()
{ $("input.search", this.element).trigger('search');
};
/** Set the input value in the form (for initialisation purpose)
* @param {string} value
* @param {boolean} search to start a search
* @api
*/
ol_control_Search.prototype.setInput = function (value, search)
{ $("input.search",this.element).val(value);
if (search) $("input.search",this.element).trigger("keyup");
};
/** A ligne has been clicked in the menu > dispatch event
* @param {any} f the feature, as passed in the autocomplete
* @api
*/
ol_control_Search.prototype.select = function (f)
{ this.dispatchEvent({ type:"select", search:f });
};
/** Autocomplete function
* @param {string} s search string
* @param {function} cback a callback function that takes an array to display in the autocomplete field (for asynchronous search)
* @return {Array|false} an array of search solutions or false if the array is send with the cback argument
* @api
*/
ol_control_Search.prototype.autocomplete = function (s, cback)
{ cback ([]);
return false;
};
/** Draw the list
* @param {Array} auto an array of search result
*/
ol_control_Search.prototype.drawList_ = function (auto)
{ var ul = $("ul.autocomplete", this.element).html("");
if (!auto) return;
var self = this;
var max = Math.min (self.get("maxItems"),auto.length);
for (var i=0; i<max; i++)
{ if (!i || !self.equalFeatures(auto[i], auto[i-1])) {
$("<li>").html(self.getTitle(auto[i]))
.data('search', auto[i])
.click(function(e)
{ self.select($(this).data('search'));
})
.appendTo(ul);
}
}
};
ol_control_Search.prototype.equalFeatures = function (f1, f2) {
return false;
};
export default ol_control_Search

View File

@ -0,0 +1,60 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_proj from 'ol/proj'
import ol_control_SearchPhoton from "./SearchPhoton";
/**
* Search places using the French National Base Address (BAN) API.
*
* @constructor
* @extends {ol.control.Search}
* @fires select
* @param {Object=} Control options.
* @param {string} options.className control class name
* @param {Element | string | undefined} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
* @param {string | undefined} options.label Text label to use for the search button, default "search"
* @param {string | undefined} options.placeholder placeholder, default "Search..."
* @param {number | undefined} options.typing a delay on each typing to start searching (ms), default 500.
* @param {integer | undefined} options.minLength minimum length to start searching, default 3
* @param {integer | undefined} options.maxItems maximum number of items to display in the autocomplete list, default 10
*
* @param {string|undefined} options.url Url to BAN api, default "https://api-adresse.data.gouv.fr/search/"
* @param {boolean} options.position Search, with priority to geo position, default false
* @param {function} options.getTitle a function that takes a feature and return the text to display in the menu, default return label attribute
* @see {@link https://adresse.data.gouv.fr/api/}
*/
var ol_control_SearchBAN = function(options)
{ options = options || {};
options.typing = options.typing || 500;
options.url = options.url || "https://api-adresse.data.gouv.fr/search/";
ol.control.SearchPhoton.call(this, options);
};
ol.inherits(ol_control_SearchBAN, ol_control_SearchPhoton);
/** Returns the text to be displayed in the menu
* @param {ol.Feature} f the feature
* @return {string} the text to be displayed in the index
* @api
*/
ol_control_SearchBAN.prototype.getTitle = function (f) {
var p = f.properties;
return (p.label);
};
/** A ligne has been clicked in the menu > dispatch event
* @param {any} f the feature, as passed in the autocomplete
* @api
*/
ol_control_SearchBAN.prototype.select = function (f){
var c = f.geometry.coordinates;
// Add coordinate to the event
try {
c = ol_proj.transform (f.geometry.coordinates, 'EPSG:4326', this.getMap().getView().getProjection());
} catch(e) {};
this.dispatchEvent({ type:"select", search:f, coordinate: c });
};
export default ol_control_SearchBAN

View File

@ -0,0 +1,81 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Search from './Search'
/**
* Search features.
*
* @constructor
* @extends {ol_control_Search}
* @fires select
* @param {Object=} Control options.
* @param {string} options.className control class name
* @param {Element | string | undefined} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
* @param {string | undefined} options.label Text label to use for the search button, default "search"
* @param {string | undefined} options.placeholder placeholder, default "Search..."
* @param {number | undefined} options.typing a delay on each typing to start searching (ms), default 300.
* @param {integer | undefined} options.minLength minimum length to start searching, default 1
* @param {integer | undefined} options.maxItems maximum number of items to display in the autocomplete list, default 10
*
* @param {string | undefined} options.property a property to display in the index, default 'name'.
* @param {function} options.getTitle a function that takes a feature and return the name to display in the index, default return the property
* @param {function | undefined} options.getSearchString a function that take a feature and return a text to be used as search string, default geTitle() is used as search string
*/
var ol_control_SearchFeature = function(options)
{ if (!options) options = {};
ol_control_Search.call(this, options);
if (typeof(options.getSearchString)=="function") this.getSearchString = options.getSearchString;
this.set('property', options.property||'name');
this.source_ = options.source;
};
ol.inherits(ol_control_SearchFeature, ol_control_Search);
/** Returns the text to be displayed in the menu
* @param {ol.Feature} f the feature
* @return {string} the text to be displayed in the index
* @api
*/
ol_control_SearchFeature.prototype.getTitle = function (f)
{ return f.get(this.get('property')||'name');
};
/** Return the string to search in
* @param {ol.Feature} f the feature
* @return {string} the text to be used as search string
* @api
*/
ol_control_SearchFeature.prototype.getSearchString = function (f)
{ return this.getTitle(f);
}
/** Autocomplete function
* @param {string} s search string
* @param {int} max max
* @param {function} cback a callback function that takes an array of {name, feature} to display in the autocomplete fielad
* @api
*/
ol_control_SearchFeature.prototype.autocomplete = function (s, cback)
{ var result = [];
// regexp
s = s.replace(/^\*/,'');
var rex = new RegExp(s, 'i');
// The source
var features = this.source_.getFeatures();
var max = this.get('maxItems')
for (var i=0, f; f=features[i]; i++)
{ if (rex.test(this.getSearchString(f)))
{ result.push(f);
if ((--max)<=0) break;
}
}
return result;
};
export default ol_control_SearchFeature

View File

@ -0,0 +1,128 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_proj from 'ol/proj'
import ol_control_Search from './Search'
import ol_geom_Point from 'ol/geom/point'
/**
* Search places using the photon API.
*
* @constructor
* @extends {ol_control_Search}
* @fires select
* @param {Object=} Control options.
* @param {string} options.className control class name
* @param {Element | string | undefined} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
* @param {string | undefined} options.label Text label to use for the search button, default "search"
* @param {string | undefined} options.placeholder placeholder, default "Search..."
* @param {number | undefined} options.typing a delay on each typing to start searching (ms), default 1000.
* @param {integer | undefined} options.minLength minimum length to start searching, default 3
* @param {integer | undefined} options.maxItems maximum number of items to display in the autocomplete list, default 10
*
* @param {string|undefined} options.url Url to photon api, default "http://photon.komoot.de/api/"
* @param {string|undefined} options.lang Force preferred language, default none
* @param {boolean} options.position Search, with priority to geo position, default false
* @param {function} options.getTitle a function that takes a feature and return the name to display in the index, default return street + name + contry
*/
var ol_control_SearchPhoton = function(options)
{ options = options || {};
delete options.autocomplete;
options.minLength = options.minLength || 3;
options.typing = options.typing || 800;
ol_control_Search.call(this, options);
this.set('lang', options.lang);
this.set('position', options.position);
// Handle Mix Content Warning
// If the current connection is an https connection all other connections must be https either
var url = options.url || "http://photon.komoot.de/api/";
if (window.location.protocol === "https:") {
var parser = document.createElement('a');
parser.href = url;
parser.protocol = window.location.protocol;
url = parser.href;
}
this.set('url', url);
};
ol.inherits(ol_control_SearchPhoton, ol_control_Search);
/** Returns the text to be displayed in the menu
* @param {ol.Feature} f the feature
* @return {string} the text to be displayed in the index
* @api
*/
ol_control_SearchPhoton.prototype.getTitle = function (f)
{ var p = f.properties;
return (p.housenumber||"")
+ " "+(p.street || p.name || "")
+ "<i>"
+ " "+(p.postcode||"")
+ " "+(p.city||"")
+ " ("+p.country
+ ")</i>";
};
/** Autocomplete function11
* @param {string} s search string
* @param {function} cback a callback function that takes an array of {name, feature} to display in the autocomplete fielad
* @api
*/
ol_control_SearchPhoton.prototype.autocomplete = function (s, cback)
{ var data =
{ q: s,
lang: this.get('lang'),
limit: this.get('maxItems')
}
// Handle position proirity
if (this.get('position'))
{ var view = this.getMap().getView();
var pt = new ol_geom_Point(view.getCenter());
pt = (pt.transform (view.getProjection(), "EPSG:4326")).getCoordinates();
data.lon = pt[0];
data.lat = pt[1];
}
var url = this.get('url');
$.support.cors = true;
$.ajax(url,
{ dataType: "json",
//crossDomain: true,
data: data,
success: function(r) {
cback(r.features);
},
error: function() {
console.log(url, arguments);
}
});
};
/** Prevent same feature to be drawn twice: test equality
* @param {} f1 First feature to compare
* @param {} f2 Second feature to compare
* @return {boolean}
* @api
*/
ol_control_SearchPhoton.prototype.equalFeatures = function (f1, f2) {
return (this.getTitle(f1) === this.getTitle(f2)
&& f1.geometry.coordinates[0] === f2.geometry.coordinates[0]
&& f1.geometry.coordinates[1] === f2.geometry.coordinates[1]);
};
/** A ligne has been clicked in the menu > dispatch event
* @param {any} f the feature, as passed in the autocomplete
* @api
*/
ol_control_SearchPhoton.prototype.select = function (f)
{ var c = f.geometry.coordinates;
// Add coordinate to the event
try {
c = ol_proj.transform (f.geometry.coordinates, 'EPSG:4326', this.getMap().getView().getProjection());
} catch(e) {};
this.dispatchEvent({ type:"select", search:f, coordinate: c });
};
export default ol_control_SearchPhoton

59
build/control/Swipe.css Normal file
View File

@ -0,0 +1,59 @@
.ol-swipe
{ position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
}
.ol-swipe:before
{ content: "";
position: absolute;
top: -5000px;
bottom: -5000px;
left: 50%;
width: 4px;
background: #fff;
z-index:-1;
transform: translate(-2px, 0);
-webkit-transform: translate(-2px, 0);
}
.ol-swipe.horizontal:before
{ left: -5000px;
right: -5000px;
top: 50%;
bottom: auto;
width: auto;
height: 4px;
}
.ol-swipe,
.ol-swipe button
{ cursor: ew-resize;
}
.ol-swipe.horizontal,
.ol-swipe.horizontal button
{ cursor: ns-resize;
}
.ol-swipe:after,
.ol-swipe button:before,
.ol-swipe button:after
{ content: "";
position: absolute;
top: 25%;
bottom: 25%;
left: 50%;
width: 2px;
background: rgba(255,255,255,0.8);
transform: translate(-1px, 0);
-webkit-transform: translate(-1px, 0);
}
.ol-swipe button:after
{ transform: translateX(5px);
-webkit-transform: translateX(5px);
}
.ol-swipe button:before
{ transform: translateX(-7px);
-webkit-transform: translateX(-7px);
}

215
build/control/Swipe.js Normal file
View File

@ -0,0 +1,215 @@
/* Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
/**
* @classdesc OpenLayers 3 swipe Control.
*
* @constructor
* @extends {ol_control_Control}
* @param {Object=} Control opt_options.
* - layers {ol.layer} layer to swipe
* - rightLayer {ol.layer} layer to swipe on right side
* - className {string} control class name
* - position {number} position propertie of the swipe [0,1], default 0.5
* - orientation {vertical|horizontal} orientation propertie, default vertical
*/
var ol_control_Swipe = function(opt_options)
{ var options = opt_options || {};
var self = this;
var button = document.createElement('button');
var element = document.createElement('div');
element.className = (options.className || "ol-swipe") + " ol-unselectable ol-control";
element.appendChild(button);
$(element).on ("mousedown touchstart", this, this.move );
ol_control_Control.call(this,
{ element: element
});
this.layers = [];
if (options.layers) this.addLayer(options.layers, false);
if (options.rightLayers) this.addLayer(options.rightLayers, true);
this.on('propertychange', function()
{ if (this.getMap()) this.getMap().renderSync();
if (this.get('orientation') === "horizontal")
{ $(this.element).css("top", this.get('position')*100+"%");
$(this.element).css("left", "");
}
else
{ if (this.get('orientation') !== "vertical") this.set('orientation', "vertical");
$(this.element).css("left", this.get('position')*100+"%");
$(this.element).css("top", "");
}
$(this.element).removeClass("horizontal vertical");
$(this.element).addClass(this.get('orientation'));
}, this);
this.set('position', options.position || 0.5);
this.set('orientation', options.orientation || 'vertical');
};
ol.inherits(ol_control_Swipe, ol_control_Control);
/**
* Set the map instance the control associated with.
* @param {_ol_Map_} map The map instance.
*/
ol_control_Swipe.prototype.setMap = function(map)
{
if (this.getMap())
{ for (var i=0; i<this.layers.length; i++)
{ var l = this.layers[i];
if (l.right) l.layer.un('precompose', this.precomposeRight, this);
else l.layer.un('precompose', this.precomposeLeft, this);
l.layer.un('postcompose', this.postcompose, this);
}
this.getMap().renderSync();
}
ol_control_Control.prototype.setMap.call(this, map);
if (map)
{ for (var i=0; i<this.layers.length; i++)
{ var l = this.layers[i];
if (l.right) l.layer.on('precompose', this.precomposeRight, this);
else l.layer.on('precompose', this.precomposeLeft, this);
l.layer.on('postcompose', this.postcompose, this);
}
map.renderSync();
}
};
/** @private
*/
ol_control_Swipe.prototype.isLayer_ = function(layer)
{ for (var k=0; k<this.layers.length; k++)
{ if (this.layers[k].layer === layer) return k;
}
return -1;
};
/** Add a layer to clip
* @param {ol.layer|Array<ol.layer>} layer to clip
* @param {bool} add layer in the right part of the map, default left.
*/
ol_control_Swipe.prototype.addLayer = function(layers, right)
{ if (!(layers instanceof Array)) layers = [layers];
for (var i=0; i<layers.length; i++)
{var l = layers[i];
if (this.isLayer_(l)<0)
{ this.layers.push({ layer:l, right:right });
if (this.getMap())
{ if (right) l.on('precompose', this.precomposeRight, this);
else l.on('precompose', this.precomposeLeft, this);
l.on('postcompose', this.postcompose, this);
this.getMap().renderSync();
}
}
}
};
/** Remove a layer to clip
* @param {ol.layer|Array<ol.layer>} layer to clip
*/
ol_control_Swipe.prototype.removeLayer = function(layers)
{ if (!(layers instanceof Array)) layers = [layers];
for (var i=0; i<layers.length; i++)
{ var k = this.isLayer_(layers[i]);
if (k >=0 && this.getMap())
{ if (this.layers[k].right) layers[i].un('precompose', this.precomposeRight, this);
else layers[i].un('precompose', this.precomposeLeft, this);
layers[i].un('postcompose', this.postcompose, this);
this.layers.splice(k,1);
this.getMap().renderSync();
}
}
};
/** @private
*/
ol_control_Swipe.prototype.move = function(e)
{ var self = e.data;
switch (e.type)
{ case 'touchcancel':
case 'touchend':
case 'mouseup':
{ self.isMoving = false;
$(document).off ("mouseup mousemove touchend touchcancel touchmove", self.move );
break;
}
case 'mousedown':
case 'touchstart':
{ self.isMoving = true;
$(document).on ("mouseup mousemove touchend touchcancel touchmove", self, self.move );
}
case 'mousemove':
case 'touchmove':
{ if (self.isMoving)
{ if (self.get('orientation') === "vertical")
{ var pageX = e.pageX
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageX)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageX);
if (!pageX) break;
pageX -= $(self.getMap().getTargetElement()).offset().left;
var l = self.getMap().getSize()[0];
l = Math.min(Math.max(0, 1-(l-pageX)/l), 1);
self.set('position', l);
}
else
{ var pageY = e.pageY
|| (e.originalEvent.touches && e.originalEvent.touches.length && e.originalEvent.touches[0].pageY)
|| (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length && e.originalEvent.changedTouches[0].pageY);
if (!pageY) break;
pageY -= $(self.getMap().getTargetElement()).offset().top;
var l = self.getMap().getSize()[1];
l = Math.min(Math.max(0, 1-(l-pageY)/l), 1);
self.set('position', l);
}
}
break;
}
default: break;
}
};
/** @private
*/
ol_control_Swipe.prototype.precomposeLeft = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
ctx.save();
ctx.beginPath();
if (this.get('orientation') === "vertical") ctx.rect (0,0, canvas.width*this.get('position'), canvas.height);
else ctx.rect (0,0, canvas.width, canvas.height*this.get('position'));
ctx.clip();
};
/** @private
*/
ol_control_Swipe.prototype.precomposeRight = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
ctx.save();
ctx.beginPath();
if (this.get('orientation') === "vertical") ctx.rect (canvas.width*this.get('position'), 0, canvas.width, canvas.height);
else ctx.rect (0,canvas.height*this.get('position'), canvas.width, canvas.height);
ctx.clip();
};
/** @private
*/
ol_control_Swipe.prototype.postcompose = function(e)
{ e.context.restore();
};
export default ol_control_Swipe

153
build/control/Target.js Normal file
View File

@ -0,0 +1,153 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Control from 'ol/control/control'
import ol_style_RegularShape from 'ol/style/regularshape'
import ol_geom_Point from 'ol/geom/point'
import ol_Map from 'ol/map'
/** ol_control_Target draw a target at the center of the map.
* @constructor
* @param {Object} options
* - style {ol.style.Style|Array<ol.style.Style>} ol.style.Stroke: draw a cross on the map, ol.style.Image: draw the image on the map
* - composite {string} composite operation : difference|multiply|xor|screen|overlay|darken|lighter|lighten|...
*/
var ol_control_Target = function(options)
{ options = options || {};
this.style = options.style ||
[ new ol.style.Style({ image: new ol_style_RegularShape ({ points: 4, radius: 11, radius1: 0, radius2: 0, snapToPixel:true, stroke: new ol.style.Stroke({ color: "#fff", width:3 }) }) }),
new ol.style.Style({ image: new ol_style_RegularShape ({ points: 4, radius: 11, radius1: 0, radius2: 0, snapToPixel:true, stroke: new ol.style.Stroke({ color: "#000", width:1 }) }) })
];
if (!(this.style instanceof Array)) this.style = [this.style];
this.composite = options.composite || '';
var div = document.createElement('div');
div.className = "ol-target ol-unselectable ol-control";
ol_control_Control.call(this,
{ element: div,
target: options.target
});
this.setVisible(options.visible!==false);
};
ol.inherits(ol_control_Target, ol_control_Control);
/**
* Remove the control from its current map and attach it to the new map.
* Subclasses may set up event handlers to get notified about changes to
* the map here.
* @param {ol.Map} map Map.
* @api stable
*/
ol_control_Target.prototype.setMap = function (map)
{ if (this.getMap())
{ this.getMap().un('postcompose', this.drawTarget_, this);
if (this.getVisible()) this.getMap().renderSync();
}
ol_control_Control.prototype.setMap.call(this, map);
if (map)
{ map.on('postcompose', this.drawTarget_, this);
}
};
/** Set the control visibility
* @paraam {boolean} b
*/
ol_control_Target.prototype.setVisible = function (b)
{ this.set("visible",b);
if (this.getMap()) this.getMap().renderSync();
};
/** Get the control visibility
* @return {boolean} b
*/
ol_control_Target.prototype.getVisible = function ()
{ return this.get("visible");
};
/** Draw the target
* @private
*/
ol_control_Target.prototype.drawTarget_ = function (e)
{ if (!this.getMap() || !this.getVisible()) return;
var ctx = e.context;
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.scale(ratio,ratio);
var cx = ctx.canvas.width/(2*ratio);
var cy = ctx.canvas.height/(2*ratio);
var geom = new ol_geom_Point (this.getMap().getCoordinateFromPixel([cx,cy]));
if (this.composite) ctx.globalCompositeOperation = this.composite;
for (var i=0; i<this.style.length; i++)
{ var style = this.style[i];
if (style instanceof ol.style.Style)
{ var sc=0;
// OL < v4.3 : setImageStyle don't check retina
var imgs = ol_Map.prototype.getFeaturesAtPixel ? false : style.getImage();
if (imgs)
{ sc = imgs.getScale();
imgs.setScale(ratio*sc);
}
e.vectorContext.setStyle(style);
e.vectorContext.drawGeometry(geom);
if (imgs) imgs.setScale(sc);
}
}
/*
for (var i=0; i<this.style.length; i++)
{ var style = this.style[i];
if (style.stroke instanceof ol.style.Stroke)
{ ctx.lineWidth = style.stroke.getWidth();
ctx.strokeStyle = ol.color.asString(style.stroke.getColor());
var m = style.radius || 10;
var dx = cx + ctx.lineWidth/2;
var dy = cy + ctx.lineWidth/2;
ctx.beginPath();
ctx.moveTo (dx-m, dy);
ctx.lineTo (dx+m, dy);
ctx.moveTo (dx, dy-m);
ctx.lineTo( dx, dy+m);
ctx.stroke();
}
else if (style instanceof ol.style.Image)
{ var img = style.getImage();
ctx.drawImage(img, cx-img.width/2, cy-img.height/2);
}
else if (style instanceof ol.style.Text)
{ ctx.font = style.getFont();
ctx.textBaseline = "middle";
ctx.textAlign = "center";
var fill = style.getFill();
if (fill)
{ ctx.fillStyle = ol.color.asString(fill.getColor());
ctx.fillText(style.getText(), cx, cy);
}
var stroke = style.getStroke();
if (stroke)
{ ctx.lineWidth = stroke.getWidth();
ctx.strokeStyle = ol.color.asString(stroke.getColor());
ctx.strokeText(style.getText(), cx, cy);
}
}
}
*/
ctx.restore();
};
export default ol_control_Target

View File

@ -0,0 +1,26 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Button from "./Button";
/** A simple push button control drawn as text
* @constructor
* @extends {ol_control_Button}
* @param {Object=} options Control options.
* @param {String} options.className class of the control
* @param {String} options.title title of the control
* @param {String} options.html html to insert in the control
* @param {function} options.handleClick callback when control is clicked (or use change:active event)
*/
var ol_control_TextButton = function(options)
{ options = options || {};
options.className = (options.className||"") + " ol-text-button";
ol_control_Button.call(this, options);
};
ol.inherits(ol_control_TextButton, ol_control_Button);
export default ol_control_TextButton

151
build/control/Toggle.js Normal file
View File

@ -0,0 +1,151 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_control_Button from './Button'
import ol_control_Control from 'ol/control/control'
/** A simple toggle control
* The control can be created with an interaction to control its activation.
*
* @constructor
* @extends {ol_control_Control}
* @fires change:active, change:disable
* @param {Object=} options Control options.
* className {String} class of the control
* title {String} title of the control
* html {String} html to insert in the control
* interaction {ol.interaction} interaction associated with the control
* active {bool} the control is created active, default false
* disable {bool} the control is created disabled, default false
* bar {ol.control.Bar} a subbar associated with the control (drawn when active if control is nested in a ol.control.Bar)
* autoActive {bool} the control will activate when shown in an ol.control.Bar, default false
* onToggle {function} callback when control is clicked (or use change:active event)
*/
var ol_control_Toggle = function(options)
{ options = options || {};
var self = this;
this.interaction_ = options.interaction;
if (this.interaction_)
{ this.interaction_.on("change:active", function(e)
{ self.setActive(!e.oldValue);
});
}
if (options.toggleFn) options.onToggle = options.toggleFn; // compat old version
options.handleClick = function()
{ self.toggle();
if (options.onToggle) options.onToggle.call(self, self.getActive());
};
options.className = (options.className||"") + " ol-toggle";
ol_control_Button.call(this, options);
this.set("title", options.title);
this.set ("autoActivate", options.autoActivate);
if (options.bar)
{ this.subbar_ = options.bar;
this.subbar_.setTarget(this.element);
$(this.subbar_.element).addClass("ol-option-bar");
}
this.setActive (options.active);
this.setDisable (options.disable);
};
ol.inherits(ol_control_Toggle, ol_control_Button);
/**
* Set the map instance the control is associated with
* and add interaction attached to it to this map.
* @param {_ol_Map_} map The map instance.
*/
ol_control_Toggle.prototype.setMap = function(map)
{ if (!map && this.getMap())
{ if (this.interaction_)
{ this.getMap().removeInteraction (this.interaction_);
}
if (this.subbar_) this.getMap().removeControl (this.subbar_);
}
ol_control_Control.prototype.setMap.call(this, map);
if (map)
{ if (this.interaction_) map.addInteraction (this.interaction_);
if (this.subbar_) map.addControl (this.subbar_);
}
};
/** Get the subbar associated with a control
* @return {ol_control_Bar}
*/
ol_control_Toggle.prototype.getSubBar = function ()
{ return this.subbar_;
};
/**
* Test if the control is disabled.
* @return {bool}.
* @api stable
*/
ol_control_Toggle.prototype.getDisable = function()
{ return $("button", this.element).prop("disabled");
};
/** Disable the control. If disable, the control will be deactivated too.
* @param {bool} b disable (or enable) the control, default false (enable)
*/
ol_control_Toggle.prototype.setDisable = function(b)
{ if (this.getDisable()==b) return;
$("button", this.element).prop("disabled", b);
if (b && this.getActive()) this.setActive(false);
this.dispatchEvent({ type:'change:disable', key:'disable', oldValue:!b, disable:b });
};
/**
* Test if the control is active.
* @return {bool}.
* @api stable
*/
ol_control_Toggle.prototype.getActive = function()
{ return $(this.element).hasClass("ol-active");
};
/** Toggle control state active/deactive
*/
ol_control_Toggle.prototype.toggle = function()
{ if (this.getActive()) this.setActive(false);
else this.setActive(true);
};
/** Change control state
* @param {bool} b activate or deactivate the control, default false
*/
ol_control_Toggle.prototype.setActive = function(b)
{ if (this.getActive()==b) return;
if (b) $(this.element).addClass("ol-active");
else $(this.element).removeClass("ol-active");
if (this.interaction_) this.interaction_.setActive (b);
if (this.subbar_) this.subbar_.setActive(b);
this.dispatchEvent({ type:'change:active', key:'active', oldValue:!b, active:b });
};
/** Set the control interaction
* @param {_ol_interaction_} i interaction to associate with the control
*/
ol_control_Toggle.prototype.setInteraction = function(i)
{ this.interaction_ = i;
};
/** Get the control interaction
* @return {_ol_interaction_} interaction associated with the control
*/
ol_control_Toggle.prototype.getInteraction = function()
{ return this.interaction_;
};
export default ol_control_Toggle

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,45 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Bounce animation:
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationBounceOptions} options
* @param {Integer} options.bounce number of bounce, default 3
* @param {Integer} options.amplitude bounce amplitude,default 40
* @param {ol.easing} options.easing easing used for decaying amplitude, use function(){return 0} for no decay, default ol.easing.linear
* @param {Integer} options.duration duration in ms, default 1000
*/
var ol_featureAnimation_Bounce = function(options)
{ options = options || {};
ol_featureAnimation.call(this, options);
this.amplitude_ = options.amplitude || 40;
this.bounce_ = -Math.PI*(options.bounce || 3);
}
ol.inherits(ol_featureAnimation_Bounce, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Bounce.prototype.animate = function (e)
{ // Animate
var flashGeom = e.geom.clone();
/*
var t = this.easing_(e.elapsed)
t = Math.abs(Math.sin(this.bounce_*t)) * this.amplitude_ * (1-t) * e.frameState.viewState.resolution;
*/
var t = Math.abs(Math.sin(this.bounce_*e.elapsed)) * this.amplitude_ * (1-this.easing_(e.elapsed)) * e.frameState.viewState.resolution;
flashGeom.translate(0, t);
this.drawGeom_(e, flashGeom, e.geom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Bounce

View File

@ -0,0 +1,51 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Drop animation: drop a feature on the map
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationDropOptions} options
* @param {Number} options.speed speed of the feature if 0 the duration parameter will be used instead, default 0
* @param {Number} options.side top or bottom, default top
*/
var ol_featureAnimation_Drop = function(options)
{ options = options || {};
this.speed_ = options.speed || 0;
ol_featureAnimation.call(this, options);
this.side_ = options.side || 'top';
}
ol.inherits(ol_featureAnimation_Drop, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Drop.prototype.animate = function (e)
{ // First time > calculate duration / speed
if (!e.time)
{ var angle = e.frameState.viewState.rotation;
var s = e.frameState.size[1] * e.frameState.viewState.resolution;
if (this.side_!='top') s *= -1;
this.dx = -Math.sin(angle)*s;
this.dy = Math.cos(angle)*s;
if (this.speed_)
{ this.duration_ = s/this.speed_/e.frameState.viewState.resolution;
}
}
// Animate
var flashGeom = e.geom.clone();
flashGeom.translate(
this.dx*(1-this.easing_(e.elapsed)),
this.dy*(1-this.easing_(e.elapsed))
);
this.drawGeom_(e, flashGeom, e.geom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Drop

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Fade animation: feature fade in
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationOptions} options
*/
var ol_featureAnimation_Fade = function(options)
{ options = options || {};
this.speed_ = options.speed || 0;
ol_featureAnimation.call(this, options);
}
ol.inherits(ol_featureAnimation_Fade, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Fade.prototype.animate = function (e)
{ e.context.globalAlpha = this.easing_(e.elapsed);
this.drawGeom_(e, e.geom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Fade

View File

@ -0,0 +1,231 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_Object from 'ol/object'
import ol_easing from 'ol/easing'
import ol_Map from 'ol/map'
import ol_layer_Vector from 'ol/layer/vector'
import ol_extent from 'ol/extent'
import ol_Observable from 'ol/observable'
/** Feature animation base class
* Use the {@link _ol_Map_#animateFeature} or {@link _ol_layer_Vector_#animateFeature} to animate a feature
* on postcompose in a map or a layer
* @constructor
* @fires animationstart|animationend
* @param {ol_featureAnimationOptions} options
* @param {Number} options.duration duration of the animation in ms, default 1000
* @param {bool} options.revers revers the animation direction
* @param {Number} options.repeat number of time to repeat the animation, default 0
* @param {oo.style.Style} options.hiddenStyle a style to display the feature when playing the animation
* to be used to make the feature selectable when playing animation
* (@see {@link ../examples/map.featureanimation.select.html}), default the feature
* will be hidden when playing (and niot selectable)
* @param {ol_easing_Function} options.fade an easing function used to fade in the feature, default none
* @param {ol_easing_Function} options.easing an easing function for the animation, default ol_easing.linear
*/
var ol_featureAnimation = function(options)
{ options = options || {};
this.duration_ = typeof (options.duration)=='number' ? (options.duration>=0 ? options.duration : 0) : 1000;
this.fade_ = typeof(options.fade) == 'function' ? options.fade : null;
this.repeat_ = Number(options.repeat);
var easing = typeof(options.easing) =='function' ? options.easing : ol_easing.linear;
if (options.revers) this.easing_ = function(t) { return (1 - easing(t)); };
else this.easing_ = easing;
this.hiddenStyle = options.hiddenStyle;
ol_Object.call(this);
};
ol.inherits(ol_featureAnimation, ol_Object);
/** Draw a geometry
* @param {olx.animateFeatureEvent} e
* @param {ol.geom} geom geometry for shadow
* @param {ol.geom} shadow geometry for shadow (ie. style with zIndex = -1)
* @private
*/
ol_featureAnimation.prototype.drawGeom_ = function (e, geom, shadow)
{ if (this.fade_)
{ e.context.globalAlpha = this.fade_(1-e.elapsed);
}
var style = e.style;
for (var i=0; i<style.length; i++)
{ var sc=0;
// OL < v4.3 : setImageStyle doesn't check retina
var imgs = ol_Map.prototype.getFeaturesAtPixel ? false : style[i].getImage();
if (imgs)
{ sc = imgs.getScale();
imgs.setScale(e.frameState.pixelRatio*sc);
}
// Prevent crach if the style is not ready (image not loaded)
try{
e.vectorContext.setStyle(style[i]);
if (style[i].getZIndex()<0) e.vectorContext.drawGeometry(shadow||geom);
else e.vectorContext.drawGeometry(geom);
} catch(e) {};
if (imgs) imgs.setScale(sc);
}
};
/** Function to perform manipulations onpostcompose.
* This function is called with an ol_featureAnimationEvent argument.
* The function will be overridden by the child implementation.
* Return true to keep this function for the next frame, false to remove it.
* @param {ol_featureAnimationEvent} e
* @return {bool} true to continue animation.
* @api
*/
ol_featureAnimation.prototype.animate = function (e)
{ return false;
};
/** An animation controler object an object to control animation with start, stop and isPlaying function.
* To be used with {@link olx.Map#animateFeature} or {@link ol.layer.Vector#animateFeature}
* @typedef {Object} ol.animationControler
* @property {function} start - start animation.
* @property {function} stop - stop animation option arguments can be passed in animationend event.
* @property {function} isPlaying - return true if animation is playing.
*/
/** Animate feature on a map
* @function
* @fires animationstart, animationend
* @param {ol.Feature} feature Feature to animate
* @param {ol_featureAnimation|Array<ol_featureAnimation>} fanim the animation to play
* @return {olx.animationControler} an object to control animation with start, stop and isPlaying function
*/
ol_Map.prototype.animateFeature =
/** Animate feature on a vector layer
* @fires animationstart, animationend
* @param {ol.Feature} feature Feature to animate
* @param {ol_featureAnimation|Array<ol_featureAnimation>} fanim the animation to play
* @return {olx.animationControler} an object to control animation with start, stop and isPlaying function
*/
ol_layer_Vector.prototype.animateFeature = function(feature, fanim)
{ var self = this;
var listenerKey;
// Save style
var style = feature.getStyle();
var flashStyle = style || (this.getStyleFunction ? this.getStyleFunction()(feature) : null);
if (!flashStyle) flashStyle=[];
if (!(flashStyle instanceof Array)) flashStyle = [flashStyle];
// Hide feature while animating
feature.setStyle(fanim.hiddenStyle || []);
// Structure pass for animating
var event =
{ // Frame context
vectorContext: null,
frameState: null,
start: 0,
time: 0,
elapsed: 0,
extent: false,
// Feature information
feature: feature,
geom: feature.getGeometry(),
typeGeom: feature.getGeometry().getType(),
bbox: feature.getGeometry().getExtent(),
coord: ol_extent.getCenter(feature.getGeometry().getExtent()),
style: flashStyle
};
if (!(fanim instanceof Array)) fanim = [fanim];
// Remove null animations
for (var i=fanim.length-1; i>=0; i--)
{ if (fanim[i].duration_===0) fanim.splice(i,1);
}
var nb=0, step = 0;
function animate(e)
{ event.vectorContext = e.vectorContext;
event.frameState = e.frameState;
if (!event.extent)
{ event.extent = e.frameState.extent;
event.start = e.frameState.time;
event.context = e.context;
}
event.time = e.frameState.time - event.start;
event.elapsed = event.time / fanim[step].duration_;
if (event.elapsed > 1) event.elapsed = 1;
// Stop animation?
if (!fanim[step].animate(event))
{ nb++;
// Repeat animation
if (nb < fanim[step].repeat_)
{ event.extent = false;
}
// newt step
else if (step < fanim.length-1)
{ fanim[step].dispatchEvent({ type:'animationend', feature: feature });
step++;
nb=0;
event.extent = false;
}
// the end
else
{ stop();
}
}
// tell OL3 to continue postcompose animation
e.frameState.animate = true;
}
// Stop animation
function stop(options)
{ ol_Observable.unByKey(listenerKey);
listenerKey = null;
feature.setStyle(style);
// Send event
var event = { type:'animationend', feature: feature };
if (options)
{ for (var i in options) if (options.hasOwnProperty(i))
{ event[i] = options[i];
}
}
fanim[step].dispatchEvent(event);
self.dispatchEvent(event);
}
// Launch animation
function start(options)
{ if (fanim.length && !listenerKey)
{ listenerKey = self.on('postcompose', animate, self);
// map or layer?
if (self.renderSync) self.renderSync();
else self.changed();
// Send event
var event = { type:'animationstart', feature: feature };
if (options)
{ for (var i in options) if (options.hasOwnProperty(i))
{ event[i] = options[i];
}
}
fanim[step].dispatchEvent(event);
self.dispatchEvent(event);
}
}
start();
// Return animation controler
return {
start: start,
stop: stop,
isPlaying: function() { return (!!listenerKey); }
};
};
export default ol_featureAnimation

View File

@ -0,0 +1,29 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Do nothing for a given duration
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationShowOptions} options
*
*/
var ol_featureAnimation_None = function(options)
{ ol_featureAnimation.call(this, options);
};
ol.inherits(ol_featureAnimation_None, ol_featureAnimation);
/** Animate: do nothing during the laps time
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_None.prototype.animate = function (e)
{
return (e.time <= this.duration_);
};
export default ol_featureAnimation_None

View File

@ -0,0 +1,18 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Do nothing
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationShowOptions} options
*/
var ol_featureAnimation_Null = function(options)
{ ol_featureAnimation.call(this, { duration:0 });
};
ol.inherits(ol_featureAnimation_Null, ol_featureAnimation);

View File

@ -0,0 +1,65 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Path animation: feature follow a path
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationPathOptions} options
* @param {Number} options.speed speed of the feature, if 0 the duration parameter will be used instead, default 0
* @param {ol.geom.LineString|ol.Feature} options.path the path to follow
*/
var ol_featureAnimation_Path = function(options)
{ options = options || {};
ol_featureAnimation.call(this, options);
this.speed_ = options.speed || 0;
this.path_ = options.path;
if (this.path_ && this.path_.getGeometry) this.path_ = this.path_.getGeometry();
if (this.path_ && this.path_.getLineString) this.path_ = this.path_.getLineString();
if (this.path_.getLength)
{ this.dist_ = this.path_.getLength()
if (this.path_ && this.path_.getCoordinates) this.path_ = this.path_.getCoordinates();
}
else this.dist_ = 0;
if (this.speed_>0) this.duration_ = this.dist_/this.speed_;
}
ol.inherits(ol_featureAnimation_Path, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Path.prototype.animate = function (e)
{ // First time
if (!e.time)
{ if (!this.dist_) return false;
}
var dmax = this.dist_*this.easing_(e.elapsed);
var p0, p, dx,dy, dl, d = 0;
p = this.path_[0];
// Linear interpol
for (var i = 1; i<this.path_.length; i++)
{ p0 = p;
p = this.path_[i];
dx = p[0]-p0[0];
dy = p[1]-p0[1];
dl = Math.sqrt(dx*dx+dy*dy);
if (dl && d+dl>=dmax)
{ var s = (dmax-d)/dl;
p = [ p0[0] + (p[0]-p0[0])*s, p0[1] + (p[1]-p0[1])*s];
break;
}
d += dl;
}
e.geom.setCoordinates(p);
// Animate
this.drawGeom_(e, e.geom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Path

View File

@ -0,0 +1,48 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Shakee animation:
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationShakeOptions} options
* @param {Integer} options.bounce number o bounds, default 6
* @param {Integer} options.amplitude amplitude of the animation, default 40
* @param {bool} options.horizontal shake horizontally default false (vertical)
*/
var ol_featureAnimation_Shake = function(options)
{ options = options || {};
ol_featureAnimation.call(this, options);
// this.easing_ = options.easing_ || function(t){return (0.5+t)*t -0.5*t ;};
this.amplitude_ = options.amplitude || 40;
this.bounce_ = -Math.PI*(options.bounce || 6);
this.horizontal_ = options.horizontal;
}
ol.inherits(ol_featureAnimation_Shake, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Shake.prototype.animate = function (e)
{ // Animate
var flashGeom = e.geom.clone();
var shadow = e.geom.clone();
var t = this.easing_(e.elapsed)
t = Math.sin(this.bounce_*t) * this.amplitude_ * (1-t) * e.frameState.viewState.resolution;
if (this.horizontal_)
{ flashGeom.translate(t, 0);
shadow.translate(t, 0);
}
else flashGeom.translate(0, t);
this.drawGeom_(e, flashGeom, shadow);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Shake

View File

@ -0,0 +1,29 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Show an object for a given duration
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationOptions} options
*/
var ol_featureAnimation_Show = function(options)
{ ol_featureAnimation.call(this, options);
}
ol.inherits(ol_featureAnimation_Show, ol_featureAnimation);
/** Animate: just show the object during the laps time
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Show.prototype.animate = function (e)
{
this.drawGeom_(e, e.geom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Show

View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Slice animation: feature enter from left
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationSlideOptions} options
* @param {Number} options.speed speed of the animation, if 0 the duration parameter will be used instead, default 0
*/
var ol_featureAnimation_Slide = function(options)
{ options = options || {};
this.speed_ = options.speed || 0;
ol_featureAnimation.call(this, options);
this.side_ = options.side || 'left';
}
ol.inherits(ol_featureAnimation_Slide, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Slide.prototype.animate = function (e)
{ // First time > calculate duration / speed
if (!e.time)
{ if (this.side_=='left') this.dx = (e.extent[0]-e.bbox[2])
else this.dx = (e.extent[2]-e.bbox[0])
if (this.speed_) this.duration_ = Math.abs(this.dx)/this.speed_/e.frameState.viewState.resolution;
}
// Animate
var flashGeom = e.geom.clone();
flashGeom.translate(this.dx*(1-this.easing_(e.elapsed)), 0);
this.drawGeom_(e, flashGeom);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Slide

View File

@ -0,0 +1,41 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Teleport a feature at a given place
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationOptions} options
*/
var ol_featureAnimation_Teleport = function(options)
{ ol_featureAnimation.call(this, options);
}
ol.inherits(ol_featureAnimation_Teleport, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Teleport.prototype.animate = function (e)
{ var sc = this.easing_(e.elapsed);
if (sc)
{ e.context.save()
var ratio = e.frameState.pixelRatio;
e.context.globalAlpha = sc;
e.context.scale(sc,1/sc);
var m = e.frameState.coordinateToPixelTransform;
var dx = (1/sc-1) * ratio * (m[0]*e.coord[0] + m[1]*e.coord[1] +m[4]);
var dy = (sc-1) * ratio * (m[2]*e.coord[0] + m[3]*e.coord[1] +m[5]);
e.context.translate(dx,dy);
this.drawGeom_(e, e.geom);
e.context.restore()
}
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Teleport

View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Slice animation: feature enter from left
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationThrowOptions} options
* @param {left|right} options.side side of the animation, default left
*/
var ol_featureAnimation_Throw = function(options)
{ options = options || {};
ol_featureAnimation.call(this, options);
this.speed_ = options.speed || 0;
this.side_ = options.side || 'left';
}
ol.inherits(ol_featureAnimation_Throw, ol_featureAnimation);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Throw.prototype.animate = function (e)
{ // First time > calculate duration / speed
if (!e.time && this.speed_)
{ var dx, dy;
if (this.side_=='left')
{ dx = this.dx = e.extent[0]-e.bbox[2];
dy = this.dy = e.extent[3]-e.bbox[1];
}
else
{ dx = this.dx = e.extent[2]-e.bbox[0];
dy = this.dy = e.extent[3]-e.bbox[1];
}
this.duration_ = Math.sqrt(dx*dx+dy*dy)/this.speed_/e.frameState.viewState.resolution;
}
// Animate
var flashGeom = e.geom.clone();
var shadow = e.geom.clone();
flashGeom.translate(this.dx*(1-this.easing_(e.elapsed)),
this.dy*Math.cos(Math.PI/2*this.easing_(e.elapsed)));
shadow.translate(this.dx*(1-this.easing_(e.elapsed)), 0);
this.drawGeom_(e, flashGeom, shadow);
return (e.time <= this.duration_);
}
export default ol_featureAnimation_Throw

View File

@ -0,0 +1,86 @@
/*
Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL license (http://www.cecill.info/).
*/
import ol from 'ol'
import ol_featureAnimation from './FeatureAnimation'
/** Zoom animation: feature zoom in (for points)
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationZoomOptions} options
* @param {bool} options.zoomOut to zoom out
*/
var ol_featureAnimation_Zoom = function(options)
{ options = options || {};
ol_featureAnimation.call(this, options);
this.set('zoomout', options.zoomOut);
}
ol.inherits(ol_featureAnimation_Zoom, ol_featureAnimation);
/** Zoom animation: feature zoom out (for points)
* @constructor
* @extends {ol_featureAnimation}
* @param {ol_featureAnimationZoomOptions} options
*/
var ol_featureAnimation_ZoomOut = function(options)
{ options = options || {};
options.zoomOut = true;
ol_featureAnimation_Zoom.call(this, options);
}
ol.inherits(ol_featureAnimation_ZoomOut, ol_featureAnimation_Zoom);
/** Animate
* @param {ol_featureAnimationEvent} e
*/
ol_featureAnimation_Zoom.prototype.animate = function (e)
{ var fac = this.easing_(e.elapsed);
if (fac)
{ if (this.get('zoomout')) fac = 1/fac;
var style = e.style;
var imgs, sc=[]
for (var i=0; i<style.length; i++)
{ imgs = style[i].getImage();
if (imgs)
{ sc[i] = imgs.getScale();
imgs.setScale(sc[i]*fac);
}
}
e.context.save()
var ratio = e.frameState.pixelRatio;
var m = e.frameState.coordinateToPixelTransform;
var dx = (1/fac-1)* ratio * (m[0]*e.coord[0] + m[1]*e.coord[1] +m[4]);
var dy = (1/fac-1)* ratio * (m[2]*e.coord[0] + m[3]*e.coord[1] +m[5]);
e.context.scale(fac,fac);
e.context.translate(dx,dy);
this.drawGeom_(e, e.geom);
e.context.restore()
for (var i=0; i<style.length; i++)
{ imgs = style[i].getImage();
if (imgs) imgs.setScale(sc[i]);
}
}
/*
var sc = this.easing_(e.elapsed);
if (sc)
{ e.context.save()
console.log(e)
var ratio = e.frameState.pixelRatio;
var m = e.frameState.coordinateToPixelTransform;
var dx = (1/(sc)-1)* ratio * (m[0]*e.coord[0] + m[1]*e.coord[1] +m[4]);
var dy = (1/(sc)-1)*ratio * (m[2]*e.coord[0] + m[3]*e.coord[1] +m[5]);
e.context.scale(sc,sc);
e.context.translate(dx,dy);
this.drawGeom_(e, e.geom);
e.context.restore()
}
*/
return (e.time <= this.duration_);
}
export {ol_featureAnimation_Zoom, ol_featureAnimation_ZoomOut}

140
build/filter/Base.js Normal file
View File

@ -0,0 +1,140 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_layer_Base from 'ol/layer/base'
import ol_Object from 'ol/object'
import ol_Map from 'ol/map'
var ol_filter = {};
/**
* @classdesc
* Abstract base class; normally only used for creating subclasses and not instantiated in apps.
* Used to create filters
* Use {@link _ol_Map_#addFilter}, {@link _ol_Map_#removeFilter} or {@link _ol_Map_#getFilters} to handle filters on a map.
* Use {@link ol_layer_Base#addFilter}, {@link ol_layer_Base#removeFilter} or {@link ol_layer_Base#getFilters}
* to handle filters on layers.
*
* @constructor
* @extends {ol.Object}
* @param {} options Extend {@link _ol_control_Control_} options.
* @param {bool} options.active
*/
var ol_filter_Base = function(options)
{ ol_Object.call(this);
if (options && options.active===false) this.set('active', false);
else this.set('active', true);
};
ol.inherits(ol_filter_Base, ol_Object);
/** Activate / deactivate filter
* @param {bool} b
*/
ol_filter_Base.prototype.setActive = function (b)
{ this.set('active', b===true);
};
/** Get filter active
* @return {bool}
*/
ol_filter_Base.prototype.getActive = function (b)
{ return this.get('active');
};
(function(){
/** Internal function
* @scoop {ol.filter} this the filter
* @private
*/
function precompose_(e)
{ if (this.get('active')) this.precompose(e);
}
/** Internal function
* @scoop {ol.filter} this the filter
* @private
*/
function postcompose_(e)
{ if (this.get('active')) this.postcompose(e);
}
/** Force filter redraw / Internal function
* @scoop {ol.map||ol.layer} this: the map or layer the filter is added to
* @private
*/
function filterRedraw_(e)
{ if (this.renderSync) this.renderSync();
else this.changed();
}
/** Add a filter to an ol object
* @scoop {ol.map||ol.layer} this: the map or layer the filter is added to
* @private
*/
function addFilter_(filter)
{ if (!this.filters_) this.filters_ = [];
this.filters_.push(filter);
if (filter.precompose) this.on('precompose', precompose_, filter);
if (filter.postcompose) this.on('postcompose', postcompose_, filter);
filter.on('propertychange', filterRedraw_, this);
filterRedraw_.call (this);
};
/** Remove a filter to an ol object
* @scoop {ol.map||ol.layer} this: the map or layer the filter is added to
* @private
*/
function removeFilter_(filter)
{ if (!this.filters_) this.filters_ = [];
for (var i=this.filters_.length-1; i>=0; i--)
{ if (this.filters_[i]===filter) this.filters_.splice(i,1);
}
if (filter.precompose) this.un('precompose', precompose_, filter);
if (filter.postcompose) this.un('postcompose', postcompose_, filter);
filter.un('propertychange', filterRedraw_, this);
filterRedraw_.call (this);
};
/** Add a filter to an ol.Map
* @param {ol.filter}
*/
ol_Map.prototype.addFilter = function (filter)
{ addFilter_.call (this, filter);
};
/** Remove a filter to an ol.Map
* @param {ol.filter}
*/
ol_Map.prototype.removeFilter = function (filter)
{ removeFilter_.call (this, filter);
};
/** Get filters associated with an ol.Map
* @return {Array<ol.filter>}
*/
ol_Map.prototype.getFilters = function ()
{ return this.filters_;
};
/** Add a filter to an ol.Layer
* @param {ol.filter}
*/
ol_layer_Base.prototype.addFilter = function (filter)
{ addFilter_.call (this, filter);
};
/** Remove a filter to an ol.Layer
* @param {ol.filter}
*/
ol_layer_Base.prototype.removeFilter = function (filter)
{ removeFilter_.call (this, filter);
};
/** Get filters associated with an ol.Map
* @return {Array<ol.filter>}
*/
ol_layer_Base.prototype.getFilters = function ()
{ return this.filters_;
};
})();
export default ol_filter_Base

118
build/filter/Clip.js Normal file
View File

@ -0,0 +1,118 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
/** Clip layer or map
* @constructor
* @requires ol.filter
* @extends {ol_filter_Base}
* @param {ol_filter_ClipOptions} options
* - coords {Array<ol.Coordinate>}
* - extent {ol.Extent}
* - units {%|px} coords units percent or pixel
* - keepAspectRatio {boolean} keep aspect ratio
* - color {string} backgroundcolor
*/
var ol_filter_Clip = function(options)
{ options = options || {};
ol_filter_Base.call(this, options);
this.set("coords", options.coords);
this.set("units", options.units);
this.set("keepAspectRatio", options.keepAspectRatio);
this.set("extent", options.extent || [0,0,1,1]);
this.set("color", options.color);
if (!options.extent && options.units!="%" && options.coords)
{ var xmin = Infinity;
var ymin = Infinity;
var xmax = -Infinity;
var ymax = -Infinity;
for (var i=0, p; p=options.coords[i]; i++)
{ if (xmin > p[0]) xmin = p[0];
if (xmax < p[0]) xmax = p[0];
if (ymin > p[1]) ymin = p[1];
if (ymax < p[1]) ymax = p[1];
}
options.extent = [xmin,ymin,xmax,ymax];
}
}
ol.inherits(ol_filter_Clip, ol_filter_Base);
ol_filter_Clip.prototype.clipPath_ = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
var coords = this.get("coords");
if (!coords) return;
var ex = this.get('extent');
var scx = 1, scy = 1;
if (this.get("units")=="%")
{ scx = canvas.width/(ex[2]-ex[0]);
scy = canvas.height/(ex[3]-ex[1]);
}
if (this.get("keepAspectRatio"))
{ scx = scy = Math.min (scx, scy);
}
var pos = this.get('position');
var dx=0, dy=0;
if (/left/.test(pos))
{ dx = -ex[0]*scx;
}
else if (/center/.test(pos))
{ dx = canvas.width/2 - (ex[2]-ex[0])*scx/2;
}
else if (/right/.test(pos))
{ dx = canvas.width - (ex[2]-ex[0])*scx;
}
var fx = function(x) { return x*scx + dx };
if (/top/.test(pos))
{ dy = -ex[1]*scy;
}
else if (/middle/.test(pos))
{ dy = canvas.height/2 - (ex[3]-ex[1])*scy/2;
}
else if (/bottom/.test(pos))
{ dy = canvas.height - (ex[3]-ex[1])*scy;
}
var fy = function(y) { return y*scy + dy; };
ctx.moveTo ( fx(coords[0][0]), fy(coords[0][1]) );
for (var i=1; p=coords[i]; i++)
{ ctx.lineTo ( fx(p[0]), fy(p[1]) );
}
ctx.lineTo ( fx(coords[0][0]), fy(coords[0][1]) );
};
ol_filter_Clip.prototype.precompose = function(e)
{ if (!this.get("color"))
{ e.context.save();
e.context.beginPath();
this.clipPath_(e);
e.context.clip();
}
}
ol_filter_Clip.prototype.postcompose = function(e)
{ if (this.get("color"))
{ var ctx = e.context;
var canvas = e.context.canvas;
ctx.save();
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(0,canvas.height);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(canvas.width, 0);
ctx.lineTo(0, 0);
this.clipPath_(e);
ctx.fillStyle = this.get("color");
ctx.fill("evenodd");
};
e.context.restore();
}
export default ol_filter_Clip

113
build/filter/Colorize.js Normal file
View File

@ -0,0 +1,113 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
import ol_color from 'ol/color'
/** Colorize map or layer
* @constructor
* @requires ol.filter
* @extends {ol_filter_Base}
* @author Thomas Tilak https://github.com/thhomas
* @author Jean-Marc Viglino https://github.com/viglino
* @param {ol_filter_ColorizeOptions} options
* - feature {ol.Feature} feature to mask with
* - color {Array<integer>} style to fill with
* - inner {bool} mask inner, default false
*/
var ol_filter_Colorize = function(options)
{ ol_filter_Base.call(this, options);
this.setFilter(options);
}
ol.inherits(ol_filter_Colorize, ol_filter_Base);
ol_filter_Colorize.prototype.setFilter = function(options)
{ options = options || {};
switch (options)
{ case "grayscale": options = { operation:'hue', red:0, green:0, blue:0, value:1 }; break;
case "invert": options = { operation:'difference', red:255, green:255, blue:255, value:1 }; break;
case "sepia": options = { operation:'color', red:153, green:102, blue:51, value:0.6 }; break;
default: break;
}
var color = options.color ? ol_color.asArray(options.color) : [ options.red, options.green, options.blue, options.value];
this.set('color', ol_color.asString(color))
this.set ('value', color[3]||1);
switch (options.operation)
{ case 'color':
case 'hue':
case 'difference':
case 'color-dodge':
case 'enhance':
this.set ('operation', options.operation);
break;
case 'saturation':
var v = 255*(options.value || 0);
this.set('color', ol_color.asString([0,0,v,v||1]));
this.set ('operation', options.operation);
break;
case 'luminosity':
var v = 255*(options.value || 0);
this.set('color', ol_color.asString([v,v,v,255]));
//this.set ('operation', 'luminosity')
this.set ('operation', 'hard-light');
break;
case 'contrast':
var v = 255*(options.value || 0);
this.set('color', ol_color.asString([v,v,v,255]));
this.set('operation', 'soft-light');
break;
default:
this.set ('operation', 'color');
break;
}
}
ol_filter_Colorize.prototype.setValue = function(v)
{ this.set ('value', v);
var c = ol_color.asArray(this.get("color"));
c[3] = v;
this.set("color", ol_color.asString(c));
}
ol_filter_Colorize.prototype.setColor = function(c)
{ c = ol_color.asArray(c);
if (c)
{ c[3] = this.get("value");
this.set("color", ol_color.asString(c));
}
}
ol_filter_Colorize.prototype.precompose = function(e)
{}
ol_filter_Colorize.prototype.postcompose = function(e)
{ // Set back color hue
var ctx = e.context;
var canvas = ctx.canvas;
ctx.save();
if (this.get('operation')=='enhance')
{ var v = this.get('value');
if (v)
{ var w = canvas.width;
var h = canvas.height;
ctx.globalCompositeOperation = 'color-burn'
ctx.globalAlpha = v;
ctx.drawImage (canvas, 0, 0, w, h);
ctx.drawImage (canvas, 0, 0, w, h);
ctx.drawImage (canvas, 0, 0, w, h);
}
}
else
{ ctx.globalCompositeOperation = this.get('operation');
ctx.fillStyle = this.get('color');
ctx.fillRect(0,0,canvas.width,canvas.height);
}
ctx.restore();
}
export default ol_filter_Colorize

40
build/filter/Composite.js Normal file
View File

@ -0,0 +1,40 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
/** Colorize map or layer
* @constructor
* @requires ol.filter
* @extends {ol_filter_Base}
* @param {ol_filter_CompositeOptions} options
* - operation {string} composite operation
*/
var ol_filter_Composite = function(options)
{ ol_filter_Base.call(this, options);
this.set("operation", options.operation || "source-over");
}
ol.inherits(ol_filter_Composite, ol_filter_Base);
/** Change the current operation
* @param {string} operation composite function
*/
ol_filter_Composite.prototype.setOperation = function(operation)
{ this.set('operation', operation || "source-over");
}
ol_filter_Composite.prototype.precompose = function(e)
{ var ctx = e.context;
ctx.save();
ctx.globalCompositeOperation = this.get('operation');
}
ol_filter_Composite.prototype.postcompose = function(e)
{ e.context.restore();
}
export default ol_filter_Composite

37
build/filter/Crop.js Normal file
View File

@ -0,0 +1,37 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Mask from './Mask'
/** Crop drawing using an ol.Feature
* @constructor
* @requires ol.filter
* @requires ol_filter_Mask
* @extends {ol_filter_Mask}
* @param {ol_filter_CropOptions}
* - feature {_ol_Feature_} feature to crop with
* - inner {bool} crop inner, default false
*/
var ol_filter_Crop = function(options)
{ options = options || {};
ol_filter_Mask.call(this, options);
}
ol.inherits(ol_filter_Crop, ol_filter_Mask);
ol_filter_Crop.prototype.precompose = function(e)
{ if (!this.feature_) return;
var ctx = e.context;
ctx.save();
this.drawFeaturePath_(e, this.get("inner"));
ctx.clip("evenodd");
}
ol_filter_Crop.prototype.postcompose = function(e)
{ if (this.feature_) e.context.restore();
}
export default ol_filter_Crop

115
build/filter/Fold.js Normal file
View File

@ -0,0 +1,115 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
/** Fold filer map
* @constructor
* @requires ol_filter
* @extends {ol_filter_Base}
* @param {ol_filter_FoldOptions}
* - fold {Array<int>} number of fold (horizontal and vertical)
* - margin {Number} margin in px, default 8
* - padding {Number} padding in px, default 8
* - fsize {integer|Array<integer>} fold size in px, default 8,10
*/
var ol_filter_Fold = function(options)
{ options = options || {};
ol_filter_Base.call(this, options);
this.set("fold", options.fold || [8,4]);
this.set("margin", options.margin || 8);
this.set("padding", options.padding || 8);
if (typeof options.fsize == "number") options.fsize = [options.fsize,options.fsize];
this.set("fsize", options.fsize || [8,10]);
}
ol.inherits(ol_filter_Fold, ol_filter_Base);
ol_filter_Fold.prototype.drawLine_ = function(ctx, d, m)
{ var canvas = ctx.canvas;
var fold = this.get("fold");
var w = canvas.width;
var h = canvas.height;
ctx.beginPath();
ctx.moveTo ( m, m );
for (var i=1; i<=fold[0]; i++)
{ x = i*w/fold[0] - (i==fold[0] ? m : 0);
y = d[1]*(i%2) +m;
ctx.lineTo ( x, y );
}
for (var i=1; i<=fold[1]; i++)
{ x = w - d[0]*(i%2) - m;
y = i*h/fold[1] - (i==fold[1] ? d[0]*(fold[0]%2) + m : 0);
ctx.lineTo ( x, y );
}
for (var i=fold[0]; i>0; i--)
{ x = i*w/fold[0] - (i==fold[0] ? d[0]*(fold[1]%2) + m : 0);
y = h - d[1]*(i%2) -m;
ctx.lineTo ( x, y );
}
for (var i=fold[1]; i>0; i--)
{ x = d[0]*(i%2) + m;
y = i*h/fold[1] - (i==fold[1] ? m : 0);
ctx.lineTo ( x, y );
}
ctx.closePath();
}
ol_filter_Fold.prototype.precompose = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
var fold = this.get("fold");
var w = canvas.width;
var h = canvas.height;
ctx.save();
ctx.shadowColor = "rgba(0,0,0,0.3)";
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 3;
this.drawLine_(ctx, this.get("fsize"), this.get("margin"));
ctx.fillStyle="#fff";
ctx.fill();
ctx.strokeStyle = "rgba(0,0,0,0.1)";
ctx.stroke();
ctx.restore();
ctx.save();
this.drawLine_(ctx, this.get("fsize"), this.get("margin") + this.get("padding"));
ctx.clip();
}
ol_filter_Fold.prototype.postcompose = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
ctx.restore();
ctx.save();
this.drawLine_(ctx, this.get("fsize"), this.get("margin"));
ctx.clip();
var fold = this.get("fold");
var w = canvas.width/fold[0];
var h = canvas.height/fold[1];
var grd = ctx.createRadialGradient(5*w/8,5*w/8,w/4,w/2,w/2,w);
grd.addColorStop(0,"transparent");
grd.addColorStop(1,"rgba(0,0,0,0.2)");
ctx.fillStyle = grd;
ctx.scale (1,h/w);
for (var i=0; i<fold[0]; i++) for (var j=0; j<fold[1]; j++)
{ ctx.save()
ctx.translate(i*w, j*w);
ctx.fillRect(0,0,w,w);
ctx.restore()
}
ctx.restore();
}
export default ol_filter_Fold

159
build/filter/Lego.js Normal file
View File

@ -0,0 +1,159 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
/** Make a map or layer look like made of a set of Lego bricks.
* @constructor
* @requires ol_filter
* @extends {ol_filter_Base}
* @param {ol_filter_LegoOptions}
* - brickSize {Number} size of te brick, default 30
* - crossOrigin {null | string | undefined} crossOrigin attribute for loaded images.
*/
var ol_filter_Lego = function(options)
{ if (!options) options = {};
ol_filter_Base.call(this, options);
var img = new Image();
// Default image
img.src = this.img[options.img] || this.img.ol3;
img.crossOrigin = options.crossOrigin || null;
// and pattern
this.pattern =
{ canvas: document.createElement('canvas')
};
this.setBrick (options.brickSize, img);
this.internal_ = document.createElement('canvas');
}
ol.inherits(ol_filter_Lego, ol_filter_Base);
/** Image definition
*/
ol_filter_Lego.prototype.img =
{ brick: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAAD10AAA9dAah0GUAAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAGAElEQVRo3sWZy4tkVx3HP+fcc29Vd1dP17TdTcbJPDKPMGR0kVEZkuBCF0EE9Z8QXLhxMUsRF4oLwYWQTSCgSxUXroQhoiEuskgEUUQh+BhHOpkZO11dr3vvefxc3FPlNHNvPbrD1Dl016XoqvM539/znFbcZo3VjbFmxcMA3Mg2fSoAiQJDov7/B1o9+aEgkycv4PBSPU9eHeDEixNwOAFXPYvFia0+rcnQEeBr218cfLIwCqW1UWillEYphUKpCmCCIQAiCEhAJIggTiSISBAfggTvJZTifQghWO+89cOQexuOXN8Pwz/9ff9X/xF0uEA7AmTsjLp/2xZQCgXHlj0OEBEAeRwGkep3qN6pfibDB3DBixMnvdCXt8J3FZowNYFSjgv71RtPaehjD0alalVOqCtHU3qlAGrVAGbidCtUYLUAiV6dCUx8XV4BhUKjY0AJgUB4LE8sA7CkCRSalFYnE72WiBrLSCKCp6TALZNRDEDCwgAKQ/vyRidN9c32K1sbqlCP/C+P9kXJI597PA7HkGJRCLNUGCY767udF9e+9dz1S5ueoRzIEZa1OxcK9td+/fAHvYH0LY6MkgHFIuYwS0ifXe1+qXvn1vk99QfzCwokToUylPrre1/de/vMnf9+5MsSg2HMELegAsl86duvnP3e8y/f1r83v8Li1RO7k/9c2t/avHnt27xpyhRDguEIuxDA3OXXX93+8a0rz6ZvcKgadqUEL73wx+9sb5//WWKTGCOHsxEWM0H71e2ffmF3lPyEkZppVyVYefCw/9a5f3epSvsWh7MMsUgeaL20/dpLu4fJXZUvFCgi46/8i5RNFCCc4bA5JuZ7f/Kp7g9fuLSdvLnY8lEHxz8ItOPcaN7gPAB1tvPl7udupT9nvGSmLLlHSosWLdbJTgpgLna+eVv9hiO1ZIpFOGBEFmejBnrO/tc/0znXTf+sHMuPwD0MrSnETID6/SXPrH/junp3Xiw3atCjxJCRktKu10DHzrZ+pOvpc5cP/6T8CWtt4BATZ4tkBoCvTz8tbTb8TnHiYi/0pgCmPufMUkB1ss9vtU7Trgt9EgyGhIS0zgjRB6RukaSdfHpLPly2xTg2chQJmgRN2qiAa3DBtu5kYXgqAIFYEzTJDAVCnQIqaA+O0wyFjj8q1oY6AB/qd5nLw9JvcpqOOcFMT5dqlg/UAoy5exS2TgGg6DxhkHofqHVCGYf3ho/S904DcHZ6jpZ6lWMY1iogCDxsn8oDduP3BEI9QvSBWgU8YRDeGezsyEk1SNlD8HF51wjQoEAgHNkffXBw+XfJiZbXXCTBT2fZaAJfn4iEEt+z73bTk92jZTxPwOFxVCeGRif0tt4HCtxB+f0P7l//rTlBAN6gjcNicThcfU2NCnjf0NU43L59vf2XZf1A8wzX8JRTgLw+Ckx17SahIZGOyMri7dHalXf6DJdYfovPAgVlRLAzAXwI0gCQU5La8m6SXeH9pi+pWf5lUooIUFKSN6V0A1AE39RyeAYYEpvYNjf4OwP8XNuf50UycnKKKURjSTMALkjzzgpyEhI0LW7ygHvYRh00G7zARQL5dBYU9JtLWvQB52e0VX0MOl5anmOP+3yIjZldpteZijZXuIbBxZ1PAEbkc05GVspZtnX04hlHEDKucpUePYbklCgyNjjDLp9AERhjKSNAQc6IwSzPMQClt37OIeOQ7vQWxJPSZSf2OZMyK1h8jHsbNSgY0Z/tNRWA2HmuVXLIZsxnliw2mROAyR2Rjwmn8vyC0XynrUwQ3PzGs6QX06rDRgD9GIDEjF9pUFLSXyRsowLFIp2/44icDpZ02umq6S3ZxDwupp3hYs1cVMAu1noLBZaMNbJoAD3tl6prOodnTF5feBoBRmGweO8fyClISMlIowkkApRYyqbeZ5YJQrHc4UNieeGYArL8NeUkFcvgJKc/AU56ajxejod+/DT/W/IkQC4P3GoBwoGsFKAf9v2qAGIxej9MU8rTGdNjWtVsJv315aL3YwDYqG5MTDxAPMvTNkJS3ReY6AmtlTrhKsf/AHgAA6ezGE+FAAAAAElFTkSuQmCC",
ol3: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAAD10AAA9dAah0GUAAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAHtUlEQVRo3sWZTWxcVxXHf/d9zIztcTz+pE6cOHXiyLJJadKgKE2oCBLlQwIWSCxYI0WiGxZZIYRAArFAYoEEi0hIsGBBURd0g4iK2lJAaWlaojZVKkU0H26cxB8Zz/f7uPeweHdebDLPnqlQ5l2N5/mN7tz/+Z//OffcM4rPUKCPl0eBAqqfAEAt5Ia1LwCuAg93CyCnAzgj7TstEKMluW+/x0AsWmKBmFggTu4lIpYome2Qw0kA8I2xL9T2Bp5COY6ncJRSDkopFEolANowBEAEATGIGBEkFjEiYkQbI0ZrMaFobYwxkY51pOumpSNTiau6bm7oZX1NP4Ai+ylYADkmGqUPxwSUQsG2ZbcDsBAA2QoGkeSvSZ4kr/alDcRGSyyxbJqqvG5+pHAwbRegVMz+leTBY7qcbTee8vsmQycRmnL6CkD1G4DXFl0fGegvANfpnws8+947AwqFg2MDSjAYzJY80QuAHl2gcPDJF3PiDLiimtIQC0ETEhD3klE8AJeuASg8CgeHir7vLBVOjwypQK3plyoromRNtzSamJg6QbcgvJ7C0J0YnCweG/jek/Ozw5q6bEiFiIHz+wNWBv68+rPNmlQjYnKE1Ai6cYfXA/W5Q6Uvl84f3zel3vH+SIDYoVAeofOdqa9PvbHn/PoDHYZ4eDSpE3fJgLs79YXToz858uxJ5+/en4jQ6hHr5OPZlZHhpcM/4BUv9PFw8agQdQVg1+UHnx/75fG5Gf83lFWGVUrQsmmu/HBsbN8f3Mi1MVLeGUJ3Lig8P/a7s5MN97c01I5+VUIk91err0/fLqFwgBHKOzmimzyQPzX2q1OTZfeianUVKCLNr93EZxiFIOyhnB0Tu6vf/XTp54uzY+4r3S1veYj5CEPBjqFsA3cDoEaLXy199rj/Is0eM2XILXzy5MkzSO6TAvAOFF84qf5KRfWYYhE2aJCzI5MDbxf7B58pTpf89x8qX1yWGKXKFaUBZIF1tWo/KzJPiYi3VAgYbrFEnpiYiBzBTgx0ts99YvDcvHr7YSBJka/Q4k1u3jz5eQ/EYebkXvL241NUeZN/31gkDwibhHjk8PGzTh+OrWw7X/6g/+TB8nuJrQCc4Z/KU08rb+1f/1gCSqy9NUNoP72txtXRb40dfJ+nkgMEZTw78riZLhDRndNP3vGG9GBKnRzhrppmilfhmcWoRYkxyuxv86euUaT24h4W2WN53WQmheB1ygc7MaCKuc+N5LeW6wfOXeUorwFQZIV5RlnbNqcGjBMyaAFUcfHwcHHxOznBakA6JQq34B4dkXtt+8QjvnCQa/Z/jxpFCmdbpPSJI7NyhMVzK/j2UQuFi4OLkz57FECcIcGCU8yZeirQvdxjjuvpTKGAem2EcjpjkjnUC5cvfIm/bRG3Y4e7AwOmEwPKOJotfhvlPj61dGaBEChtAdD88Yeq9et1LqWOUTj2lYzOItSmcxi2ZDXUw+k0n0bqDoXDJBsMM8rHKeIKFbxgIV9nL3cSFlPpZQBoa6AjgCYXK2YkndbckkxmWWfu2D00ozzYNinOlagwbRct/k92zNJARxFK01yur/mX2wDWGE0jfuHyNfa+Y6hQYNsmJQ45hqwwFaPpOVo6s2zDsCMDgsBq2sBR9xj8ZvX70+LJc9w+scA1Sjz49rjMy7zMywE5IY64PMcNDlkHKCbt9xhMZwhOooGODGhMzVyqTUxIm4Pll9797ixnWFZ3WORdSqz//hI+Pv7LT5dXOcNZltUa49y3qplC0Hb5uBMAbwcGDKYS/eLu6YMfrSZCUhWY+QCfGZ7iZYRbarSdYMfd0bvXazh8ii/yF2vcAVwitB1hZirWnROREFLYjN4uLQ5QTZ/WmeA2VwDUHbBks351HRxK3OaqtTTHEQwxmpjkxJApQh111kBAvBH+9O7y/KveFsfcYyNj82qywqZdxmWBAjEREbHdkrNEqNE6o6qJiVeiC4UPHuqg20PvExxGE6YAWp2jwEvabmIyqpoGuTB4ozEwd6lKvYflRzgBBIQWQrQjAG2MZABoEeJH4UU3N8f1rC/psPyz+AQWQEhIK6s09wACk+EC0NTwcCM3KrDAf6ihd6ui2ccxcrRoEaQg6lnQPYDYSLZlAS1cXBzyLHGfW0SZPDgMscgBDK10BARUs48mVgNxtl2GKh6ObVpOM8Uy94hsZpe0nakoMMdhPGJreRtAg9YuJ6NIwp18G7OJsilVyHGIQ2yySZ0WIYocQ+xhknEUhiYRoQUQ0KJBbSfleAChjvQuh4wypbQLovEpMWHrnPY2K0RoG/eR5SCgQXVn1SQAJNpNWiFlhm0+i8jZIrMNoN0j0jbhJMoPaOwu2sQFJt69oRKyadNqTGQBOFsAiM34CQchIdVuwtYyEOgu4jumQosiEX5a6aq0S9Z2T2zTThfdkS0MRN21lISAiBwD5KwDnLReStp0MZomrc4bTyaAhql131gztAhw8cnhWxeIBRASEWbVPju5wAS9/VYgdnthGwPSe5uynYqlpun9EuCTzHt0O67r5uP8teRRAC25H/cXgNmQvgKomhXdLwB2M7pu0pTyeK70mJYUm251sLfo/T8AGEoKes8eIGZ43E5wk36BBwhO2mbqgwZa9C0CAP4LFLGzNDDzmrAAAAAASUVORK5CYII=",
lego: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD8AAAA/CAQAAAD9VthUAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAADzoAAA86AZc528IAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAHvElEQVRYw8WZWWxcVxnHf+fec2fGu+M4qbPH2EmTLk4FApqQNrgiVYyKeClIwBsvPCAQkZAQPND2gRekCoGQEItYHhBLurCksoTKA6QNJW0CBZLWCc3qEBvHy3hsz93O+XiYMxM7nhmPGxGf++Dre2fO7/v+5/u+s4zigzSxVq3osaZNAwzkuq1nPeUrAE9p99JTAKWn5WYEwErpv9TdGbECRlKMgBEjRlIgsqlAKBBaSKUokAjgkcFz+Ce6BvM9sVbKU55WKKWUh1IeoJQCFhsgIIIgIohYEWwq1ooVK9ZasdbG1hhrjUmMsYlZsJEJzYIpmLwZs/8xZ9JpaGYHOYfPyvrChrdbpAxbjFRltCqhnQ2yxBTKf0WQUgNrwYqIFStGUkkllqIU5E/2aQBbEV8pz/ZM3Or8/95UmeUB+J63RiHoAWi1ZHTvNl6pNfXe99Taeq/W1HvuYOzvKG5c4q1afIWHj4eHBwgWwWCQ1aWvBvC8VXngE5DbmO3UxrOeqEhmTFEcPiIiadwEfVttWxmd623tyu7Mfnrjru5cM0Th+Nyp2Z/MztvJNDLkSImZJ27MhNWIr8j1tn+g9at7+/ubivaSHYkmjPF1f+sj7Uc3Xc29VPjm1JSJEzJkCZkjaVT8hvzubDvQ8cz9AwPeG/rHFD3BZkoeTqLwCuqzrQf7nw9+UJhOidEEFAhX0sCJr1fyXm/uPLr5849n/u1/j3mMWtqtYEFm5v/2pXUHdhzNjgaxzunQQzNX3wDdWIT0dT3bP3Qo8wIXSVWNDpWQys2xmW/3fbn1WpAWXUrWNaARvN+/7lu7jzysf8q4siuEh5A8fX5/+8XepLyEs8zfCd7raP/K9scf1T9iQjUUzU+JynOR3TQBgpAS1a16dVtusONTH8kc42ZjcFFKEApcJyBHjizt+O8Wr3e2P7Uv+3curyT7InhJ8nFCMmTJkqWlVlnzVsj0psc69vbrV1SyKnjJgCsEZMiQoanWINcfe39v6xfv808Suu6f5EVlQA7QAcC/1DXp42GmuazOiaJbjjDFSTUNCLOEZMiQEJAjrZYB9b0PmoPe7fpNZQAkYFb1A9CphtWwGlbNkmX/R59TpzhPAAwdf37XKWac1JZJAnc1VSfp0ufSqtK3NT/Y3DJVKZ5tYbHiwfvJAjc5dO7Pw4cZOb4vc51ccvZjh7ZfubaTC8y4evgeAjQaTYCpgZfq06TXpD++Rd6hHHTdZ8JKDs8yAsAD92/gjxSfGNvYzp7Wt3nj6sS2D5NxtXAeHNwnIFpOqSe+bg+2d6ejFXzXS8WlJUSyhBiKoAqj1yFuYQLQZCvFOMLDx8evPFuOF7HV0sqzXmsuP1mJ5tbfVirYc++VITnItvyN8rhJjqIrL7qS50KCX1mWeLXFr5Z02nqiJ2+lXOasIQHJkD75C6DjtQ8dH6Eg99FHyD+LBRclaomnqgL3lo++w4utWsBVbNYtr1htYZFBZgm2299Z5rmXl4+ZtwaPjDlt9CJ0gIeqXNXFN7WKDtMLnW1y+9e6Txc5z2le25Te0BTVic89ovf3yIXE1QeP4FbJbmCla21V723evjklncued/0mZA6AcEABfH/6rXzb2IM5fJD1zLvIB02zm3ak+iK0hK8mvmBnzA/Hoy3LJoyW4XIITn5daAbaX0w3XBnIIsCBL7zDpFNvPWoRvBY+larBZ5Gb6eX20xXxf/2QDMkgmc+sl8MyJH2cf/Seka3yGFv+kR7Ok/1riwxhvruJUYffhGCxWKS0IqqReFXFN5g583qaNokC0aSf/JUaVn95ufNrJ9SwGlapMkkUXuPMAy/E24CJbQVeVWeIXDAFbEYwWCymes3XAMZW9d5gC8k3Rn++79hJjErvvcBB0P53/sBBAOa5knmdnWwlywlQZ7mHfQivOsd6yVDEkGIwxDVrfo2yY4nJ5tMTLe9rkYKSkUtcEqXk9/DKok9d5nLlfpzxyn0Tu7Gk7jLVNx8eQFw98oUi6Vz07NiZ3c/4y+bz+i1gHxliEhJnQFKn6MbVu01ISRaSX2b8vk/4q4D77GErCTGxM2EBW1P8pLr4YJkjiKORhZ91hR1qpsG9m89O9pASOXxMXF6wrCb0ACIidBJe8ZNdjHID24DsA/RhCImInAnztQqr897UeI1lDp3ToU8TO2jiat39q0cLD7GJlNBdERFhLd8dPjamtldx98K8dhNGD91cZ6zKPl6hyNJPP5rYIcsGFGprVva+Nl4GF455lVzI0UcvU0ySX7R5aKabHnrwMRSJlhiQr7fT1QCprYPnmKHgzjQtliwZNrIZHyHBkHHLSMG4KI+JK6Lna+9wFuETUzecLAUHN6QkBARofHwCFImr6Mbld+Lw0Upwhy/acKWUMswS07YI77tllHJTqsW4t4lLtcLKBwyl0JN05YQSiqS0knW+a7eGu4W3rrgmJMwRNpCkLvRsaBoqKAkzZGgi66S/HV+Sf4GQxvor4xPbYDkVIuLS2RZ6CV4wRMQkNNpXGb9go1V8BSElJXRrWIXCupM9We2hvMPPG1bbaqxf3sWhamTzhjVpHsCc/a9dQ3xo82uJL9jRNRLfTTnnBO+u/pTkLT5c8fPNd9nt5tLmRbsVynbsXR704Bbeq775v0uht3btfyZT7OA5knjdAAAAAElFTkSuQmCC"
};
/** Overwrite to handle brickSize
* @param {string} key
* @param {} val
*/
ol_filter_Lego.prototype.set = function (key, val)
{ ol_filter_Base.prototype.set.call(this, key, val);
if (key=="brickSize" && this.pattern.canvas.width!=val)
{ this.setBrick(val);
}
}
/** Set the current brick
* @param {Number} width the pattern width, default 30
* @param {brick|ol3|lego|undefined} img the pattern, default ol3
* @param {string} crossOrigin
*/
ol_filter_Lego.prototype.setBrick = function (width, img, crossOrigin)
{ width = Number(width) || 30;
if (typeof(img) === 'string')
{ var i = new Image;
i.src = this.img[img] || this.img.ol3;
i.crossOrigin = crossOrigin || null;
img = i;
}
if (img) this.pattern.img = img;
if (!this.pattern.img.width)
{ var self = this;
this.pattern.img.onload = function()
{ self.setBrick(width,img);
}
return;
}
this.pattern.canvas.width = this.pattern.canvas.height = width;
this.pattern.ctx = this.pattern.canvas.getContext("2d");
this.pattern.ctx.fillStyle = this.pattern.ctx.createPattern (this.pattern.img, 'repeat');
this.set("brickSize", width);
this.set("img", img.src);
};
/** Get translated pattern
* @param {number} offsetX x offset
* @param {number} offsetY y offset
*/
ol_filter_Lego.prototype.getPattern = function (offsetX, offsetY)
{
if (!this.pattern.ctx) return "transparent";
//return this.pattern.ctx.fillStyle
var c = this.pattern.canvas;
var ctx = this.pattern.ctx;
var sc = c.width / this.pattern.img.width;
ctx.save();
ctx.clearRect(0,0,c.width,c.height);
ctx.scale(sc,sc);
offsetX /= sc;
offsetY /= sc;
ctx.translate(offsetX, offsetY);
ctx.beginPath();
ctx.clearRect(-2*c.width, -2*c.height, 4*c.width, 4*c.height);
ctx.rect(-offsetX, -offsetY, 2*c.width/sc, 2*c.height/sc);
ctx.fill();
ctx.restore();
return ctx.createPattern(c, 'repeat');
};
/** Postcompose operation
*/
ol_filter_Lego.prototype.postcompose = function(e)
{ // Set back color hue
var ctx = e.context;
var canvas = ctx.canvas;
var ratio = e.frameState.pixelRatio;
ctx.save();
// resize
var step = this.pattern.canvas.width*ratio, step2 = step/2;
var p = e.frameState.extent;
var res = e.frameState.viewState.resolution/ratio;
var offset = [ -Math.round((p[0]/res)%step), Math.round((p[1]/res)%step) ];
var ctx2 = this.internal_.getContext("2d");
var w = this.internal_.width = canvas.width;
var h = this.internal_.height = canvas.height;
// No smoothing please
ctx2.webkitImageSmoothingEnabled = false;
ctx2.mozImageSmoothingEnabled = false;
ctx2.imageSmoothingEnabled = false;
/**/
var w2 = Math.floor((w-offset[0])/step);
var h2 = Math.floor((h-offset[1])/step);
ctx2.drawImage (canvas, offset[0], offset[1], w2*step, h2*step, 0, 0, w2, h2);
ctx.webkitImageSmoothingEnabled = false;
ctx.mozImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false; //future
ctx.clearRect (0, 0, w,h);
ctx.drawImage (this.internal_, 0,0, w2,h2, offset[0],offset[1], w2*step, h2*step);
/* /
for (var x=offset[0]; x<w; x+=step) for (var y=offset[1]; y<h; y+=step)
{ if (x>=0 && y<h) ctx2.drawImage (canvas, x, y, 1, 1, x, y, step, step);
}
ctx.clearRect (0, 0, w,h);
ctx.drawImage (c, 0, 0);
/**/
// Draw brick stud
ctx.scale(ratio,ratio);
ctx.fillStyle = this.getPattern (offset[0]/ratio, offset[1]/ratio);
ctx.rect(0,0, w, h);
ctx.fill();
ctx.restore();
};
export default ol_filter_Lego

94
build/filter/Mask.js Normal file
View File

@ -0,0 +1,94 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
import ol_color from 'ol/color'
/** Mask drawing using an ol.Feature
* @constructor
* @requires ol_filter
* @extends {ol_filter_Base}
* @param {ol_filter_CropOptions} options
* - feature {ol.Feature} feature to mask with
* - fill {ol.style.Fill} style to fill with
* - inner {bool} mask inner, default false
*/
var ol_filter_Mask = function(options)
{ options = options || {};
ol_filter_Base.call(this, options);
if (options.feature)
{ switch (options.feature.getGeometry().getType())
{ case "Polygon":
case "MultiPolygon":
this.feature_ = options.feature;
break;
default: break;
}
}
this.set("inner", options.inner);
this.fillColor_ = options.fill ? ol_color.asString(options.fill.getColor()) || "rgba(0,0,0,0.2)" : "rgba(0,0,0,0.2)";
}
ol.inherits(ol_filter_Mask, ol_filter_Base);
/** Draw the feature into canvas
*/
ol_filter_Mask.prototype.drawFeaturePath_ = function(e, out)
{ var ctx = e.context;
var canvas = ctx.canvas;
var ratio = e.frameState.pixelRatio;
// Transform
var m = e.frameState.coordinateToPixelTransform;
function tr(pt)
{ return [
(pt[0]*m[0]+pt[1]*m[1]+m[4])*ratio,
(pt[0]*m[2]+pt[1]*m[3]+m[5])*ratio
];
}
// Old version
if (!m)
{ m = e.frameState.coordinateToPixelMatrix;
tr = function(pt)
{ return [
(pt[0]*m[0]+pt[1]*m[1]+m[12])*ratio,
(pt[0]*m[4]+pt[1]*m[5]+m[13])*ratio
];
}
}
// Geometry
var ll = this.feature_.getGeometry().getCoordinates();
if (this.feature_.getGeometry().getType()=="Polygon") ll = [ll];
ctx.beginPath();
if (out)
{ ctx.moveTo (0,0);
ctx.lineTo (canvas.width, 0);
ctx.lineTo (canvas.width, canvas.height);
ctx.lineTo (0, canvas.height);
ctx.lineTo (0, 0);
}
for (var l=0; l<ll.length; l++)
{ var c = ll[l];
for (var i=0; i<c.length; i++)
{ var pt = tr(c[i][0]);
ctx.moveTo (pt[0], pt[1]);
for (var j=1; j<c[i].length; j++)
{ pt = tr(c[i][j]);
ctx.lineTo (pt[0], pt[1]);
}
}
}
}
ol_filter_Mask.prototype.postcompose = function(e)
{ if (!this.feature_) return;
var ctx = e.context;
ctx.save();
this.drawFeaturePath_(e, !this.get("inner"));
ctx.fillStyle = this.fillColor_;
ctx.fill("evenodd");
ctx.restore();
}
export default ol_filter_Mask

179
build/filter/Texture.js Normal file
View File

@ -0,0 +1,179 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_filter_Base from './Base'
import ol_filter_Texture_Image from './TextureImage'
/** Add texture effects on maps or layers
* @constructor
* @requires ol.filter
* @extends {ol_filter_Base}
* @param {ol_filter_TextureOptions} options
* - feature {_ol_Feature_} feature to mask with
* - fill {_ol_style_Fill_} style to fill with
* - inner {bool} mask inner, default false
*/
var ol_filter_Texture = function(options)
{ ol_filter_Base.call(this, options);
this.setFilter(options);
}
ol.inherits(ol_filter_Texture, ol_filter_Base);
/** Set texture
* @option {ol_filter_TextureOptions}
* - img {Image | undefined} Image object for the texture
* - src {string} Image source URI
* - scale {number} scale to draw the image. Default 1.
* - rotateWithView {bool} Whether to rotate the texture with the view (may cause animation lags on mobile or slow devices). Default is true.
* - crossOrigin {null | string | undefined} The crossOrigin attribute for loaded images.
*/
ol_filter_Texture.prototype.setFilter = function(options)
{ var img;
options = options || {};
if (options.img) img = option.img;
else
{ img = new Image();
if (options.src) {
// Look for a texture stored in ol_filter_Texture_Image
if (ol_filter_Texture_Image && ol_filter_Texture_Image[options.src]) {
img.src = ol_filter_Texture_Image[options.src];
}
// default source
else {
if (!img.src) img.src = options.src;
}
}
img.crossOrigin = options.crossOrigin || null;
}
this.set('rotateWithView', options.rotateWithView !== false);
this.set('opacity', typeof(options.opacity)=='number' ? options.opacity : 1);
this.set('ready', false);
var self = this;
function setPattern(img)
{ self.pattern = {};
self.pattern.scale = options.scale || 1;
self.pattern.canvas = document.createElement('canvas');
self.pattern.canvas.width = img.width * self.pattern.scale;
self.pattern.canvas.height = img.height * self.pattern.scale;
self.pattern.canvas.width = img.width;// * self.pattern.scale;
self.pattern.canvas.height = img.height;// * self.pattern.scale;
self.pattern.ctx = self.pattern.canvas.getContext("2d");
self.pattern.ctx.fillStyle = self.pattern.ctx.createPattern(img, 'repeat');
// Force refresh
self.set('ready', true);
};
if (img.width)
{ setPattern(img);
}
else
{ img.onload = function()
{ setPattern(img);
}
}
}
/** Get translated pattern
* @param {number} x offset
* @param {number} y offset
*/
ol_filter_Texture.prototype.getPattern = function (offsetX, offsetY)
{ var c = this.pattern.canvas;
var ctx = this.pattern.ctx;
ctx.save();
/*
offsetX /= this.pattern.scale;
offsetY /= this.pattern.scale;
ctx.scale(this.pattern.scale,this.pattern.scale);
*/
ctx.translate(-offsetX, offsetY);
ctx.beginPath();
ctx.rect(offsetX, -offsetY, c.width, c.height);
ctx.fill();
ctx.restore();
return ctx.createPattern(c, 'repeat');
}
/** Draw pattern over the map on postcompose
*/
ol_filter_Texture.prototype.postcompose = function(e)
{ // not ready
if (!this.pattern) return;
// Set back color hue
var ctx = e.context;
var canvas = ctx.canvas;
var m = 1.5 * Math.max(canvas.width, canvas.height);
var mt = e.frameState.pixelToCoordinateTransform;
// Old version (matrix)
if (!mt)
{ mt = e.frameState.pixelToCoordinateMatrix,
mt[2] = mt[4];
mt[3] = mt[5];
mt[4] = mt[12];
mt[5] = mt[13];
}
var ratio = e.frameState.pixelRatio;
var res = e.frameState.viewState.resolution;
var w = canvas.width/2,
h = canvas.height/2;
ctx.save();
ctx.globalCompositeOperation = "multiply";
//ctx.globalCompositeOperation = "overlay";
//ctx.globalCompositeOperation = "color";
ctx.globalAlpha = this.get('opacity');
ctx.scale(ratio*this.pattern.scale,ratio*this.pattern.scale);
if (this.get('rotateWithView'))
{ // Translate pattern
res *= this.pattern.scale
ctx.fillStyle = this.getPattern ((w*mt[0] + h*mt[1] + mt[4])/res, (w*mt[2] + h*mt[3] + mt[5])/res);
// Rotate on canvas center and fill
ctx.translate(w/this.pattern.scale, h/this.pattern.scale);
ctx.rotate(e.frameState.viewState.rotation);
ctx.beginPath();
ctx.rect(-w-m, -h-m, 2*m, 2*m);
ctx.fill();
}
else
{
/**/
var dx = -(w*mt[0] + h*mt[1] + mt[4])/res;
var dy = (w*mt[2] + h*mt[3] + mt[5])/res;
var cos = Math.cos(e.frameState.viewState.rotation);
var sin = Math.sin(e.frameState.viewState.rotation);
var offsetX = (dx*cos - dy*sin) / this.pattern.scale;
var offsetY = (dx*sin + dy*cos) / this.pattern.scale;
ctx.translate(offsetX, offsetY);
ctx.beginPath();
ctx.fillStyle = this.pattern.ctx.fillStyle;
ctx.rect(-offsetX -m , -offsetY -m, 2*m, 2*m);
ctx.fill();
/* //old version without centered rotation
var offsetX = -(e.frameState.extent[0]/res) % this.pattern.canvas.width;
var offsetY = (e.frameState.extent[1]/res) % this.pattern.canvas.height;
ctx.rotate(e.frameState.viewState.rotation);
ctx.translate(offsetX, offsetY);
ctx.beginPath();
ctx.fillStyle = this.pattern.ctx.fillStyle
ctx.rect(-offsetX -m , -offsetY -m, 2*m, 2*m);
ctx.fill();
*/
}
ctx.restore();
}
export default ol_filter_Texture

File diff suppressed because one or more lines are too long

996
build/filter/legostud.svg Normal file
View File

@ -0,0 +1,996 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="79.111137mm"
height="69.723396mm"
viewBox="0 0 280.31505 247.0514"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="legostud.svg">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient4479">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4481" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop4483" />
</linearGradient>
<linearGradient
id="linearGradient4264"
osb:paint="gradient">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4266" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4268" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4165">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4167" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4169" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="radialGradient4171"
cx="247.58907"
cy="806.17749"
fx="247.58907"
fy="806.17749"
r="16.712261"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1673248,0,0,1.1673248,-43.580899,-140.69401)" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4209"
x="-0.023999365"
width="1.0479987"
y="-0.024000635"
height="1.0480013">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.36829105"
id="feGaussianBlur4211" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4260"
x="-0.035885267"
width="1.0717705"
y="-0.036115468"
height="1.0722309">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.3757032"
id="feGaussianBlur4262" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4406"
x="-0.023999998"
width="1.048"
y="-0.024000002"
height="1.048">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.55023435"
id="feGaussianBlur4408" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4479"
id="radialGradient4485"
cx="243.34979"
cy="799.60266"
fx="243.34979"
fy="799.60266"
r="26.382999"
gradientTransform="matrix(0.94262735,-0.96925492,1.4109273,1.372166,-1114.2197,-61.71694)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4507"
x="-0.011999792"
width="1.0239996"
y="-0.012000208"
height="1.0240004">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.26382543"
id="feGaussianBlur4509" />
</filter>
<linearGradient
y2="0"
x2="1"
y1="0"
x1="0"
id="grad">
<stop
id="stop4520"
stop-opacity="0.25"
stop-color="#000000"
offset="20%" />
<stop
id="stop4522"
stop-opacity="0.5"
stop-color="#000000"
offset="80%" />
</linearGradient>
<path
d="M 0,0 5,10 Q 0,0 -5,10 Z"
id="arrow"
inkscape:connector-curvature="0"
style="stroke:none" />
<text
font-style="italic"
font-size="16"
text-align="middle"
dy="8.2103413e-035"
y="0"
x="0"
transform="matrix(0.69282032,-0.4,0.5,0.8660254,0,0)"
id="stud_text"
style="font-style:italic;font-size:16px;stroke:none">LEGO</text>
<g
id="stud">
<ellipse
id="ellipse4527"
ry="17.6777"
rx="30.618601"
cy="3"
cx="6"
style="fill:#000000;fill-opacity:0.25;stroke:none" />
<path
id="path4529"
d="m -30.6186,-17 a 30.6186,17.6777 0 0 1 61.2372,0 l 0,17 a 30.6186,17.6777 0 0 1 -61.2372,0 z"
inkscape:connector-curvature="0" />
<path
id="path4531"
d="m -30.6186,-17 a 30.6186,17.6777 0 0 0 61.2372,0 l 0,17 a 30.6186,17.6777 0 0 1 -61.2372,0 z"
inkscape:connector-curvature="0"
style="fill:url(#grad)" />
<use
id="use4533"
xlink:href="#stud_text"
transform="translate(1,-16)"
style="fill:#000000"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4535"
xlink:href="#stud_text"
transform="translate(0,-17)"
x="0"
y="0"
width="100%"
height="100%" />
</g>
<g
id="brick">
<path
id="path4538"
d="m 0,40 69.282,-40 0,-96 L 0,-136 l -69.282,40 0,96 z"
inkscape:connector-curvature="0" />
<path
id="path4540"
d="m 0,40 0,-96 69.282,-40 0,96 z"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:0.5" />
<path
id="path4542"
d="m 0,40 0,-96 -69.282,-40 0,96 z"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:0.25" />
<use
id="use4544"
xlink:href="#stud"
transform="translate(0,-96)"
x="0"
y="0"
width="100%"
height="100%" />
</g>
<g
id="plate">
<path
id="path4547"
d="m 0,40 69.282,-40 0,-32 -138.564,-80 -69.282,40 0,32 z"
inkscape:connector-curvature="0" />
<path
id="path4549"
d="m 0,40 0,-32 69.282,-40 0,32 z"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:0.5" />
<path
id="path4551"
d="m 0,40 0,-32 -138.564,-80 0,32 z"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:0.25" />
<use
id="use4553"
xlink:href="#stud"
transform="translate(-69.282,-72)"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4555"
xlink:href="#stud"
transform="translate(0,-32)"
x="0"
y="0"
width="100%"
height="100%" />
</g>
<g
font-size="16"
id="main"
style="font-size:16px;font-family:sans-serif;text-anchor:middle;fill:#000000;stroke:#000000;stroke-linecap:round;stroke-linejoin:round">
<g
id="g4558"
transform="translate(10,-5)">
<use
id="use4560"
xlink:href="#brick"
transform="translate(69.282,-40)"
style="fill:#ffcc00"
x="0"
y="0"
width="100%"
height="100%" />
<text
id="text4562"
y="-186"
x="69"
style="text-anchor:middle;stroke:none">4.8 mm</text>
<line
id="line4564"
y2="-180"
x2="100"
y1="-180"
x1="39" />
<use
id="use4566"
transform="matrix(0,-1,1,0,39,-180)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4568"
transform="matrix(0,1,-1,0,100,-180)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4570"
y2="-185"
x2="39"
y1="-161"
x1="39" />
<line
id="line4572"
y2="-185"
x2="100"
y1="-161"
x1="100" />
<text
id="text4574"
y="-170"
x="160"
style="text-anchor:start;stroke:none">1.7 mm</text>
<line
id="line4576"
y2="-159"
x2="147"
y1="-176"
x1="147" />
<use
id="use4578"
transform="translate(147,-176)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4580"
transform="matrix(-1,0,0,-1,147,-159)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4582"
y2="-181"
x2="156"
y1="-150"
x1="102" />
<line
id="line4584"
y2="-164"
x2="156"
y1="-133"
x1="102" />
<text
id="text4586"
y="-80"
x="150"
style="text-anchor:start;stroke:none">
<tspan
id="tspan4588">H = 9.6 mm</tspan>
<tspan
id="tspan4590"
dy="1.8479102e-034"
x="165">= 3 × h</tspan>
<tspan
id="tspan4592"
dy="1.7902963e-034"
x="165">= 1.2 × P</tspan>
</text>
<line
id="line4594"
y2="-35"
x2="147"
y1="-131"
x1="147" />
<use
id="use4596"
transform="translate(147,-131)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4598"
transform="matrix(-1,0,0,-1,147,-35)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<text
id="text4600"
y="0"
x="130"
style="text-anchor:start;stroke:none">
<tspan
id="tspan4602">P 0.2 mm</tspan>
<tspan
id="tspan4604"
dy="1.8528684e-034"
x="130">= 7.8 mm</tspan>
</text>
<line
id="line4606"
y2="-35"
x2="147"
y1="5"
x1="78" />
<use
id="use4608"
transform="matrix(-0.5,-0.8660254,0.8660254,-0.5,78,5)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4610"
transform="matrix(0.5,0.8660254,-0.8660254,0.5,147,-35)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4612"
y2="-126"
x2="156"
y1="-134"
x1="142" />
<line
id="line4614"
y2="-30"
x2="156"
y1="-38"
x1="142" />
<line
id="line4616"
y2="10"
x2="87"
y1="2"
x1="73" />
</g>
<g
id="g4618">
<use
id="use4620"
xlink:href="#plate"
style="fill:#ff0000"
x="0"
y="0"
width="100%"
height="100%" />
<text
id="text4622"
y="-190"
x="-170"
style="text-anchor:start;stroke:none">
<tspan
id="tspan4624">P = 8.0 mm</tspan>
<tspan
id="tspan4626"
dy="1.8722218e-034"
x="-155">= 5/6 × H</tspan>
<tspan
id="tspan4628"
dy="1.8727315e-034"
x="-155">= 2.5 × h</tspan>
</text>
<line
id="line4630"
y2="-190"
x2="-69"
y1="-150"
x1="0" />
<use
id="use4632"
transform="matrix(-0.5,0.8660254,-0.8660254,-0.5,0,-150)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4634"
transform="matrix(0.5,-0.8660254,0.8660254,0.5,-69,-190)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4636"
y2="-160"
x2="0"
y1="-50"
x1="0" />
<line
id="line4638"
y2="-200"
x2="-69"
y1="-90"
x1="-69" />
<text
id="text4640"
y="-130"
x="-32"
style="text-anchor:middle;stroke:none">3.2 mm</text>
<line
id="line4642"
y2="-120"
x2="-48"
y1="-105"
x1="-24" />
<use
id="use4644"
transform="matrix(-0.5,0.8660254,-0.8660254,-0.5,-24,-105)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4646"
transform="matrix(0.5,-0.8660254,0.8660254,0.5,-48,-120)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4648"
y2="-110"
x2="-24"
y1="-62"
x1="-24" />
<line
id="line4650"
y2="-125"
x2="-48"
y1="-78"
x1="-48" />
<text
id="text4652"
y="20"
x="-90"
style="text-anchor:end;stroke:none">
<tspan
id="tspan4654">2 × P 0.2 mm</tspan>
<tspan
id="tspan4656"
dy="1.8926102e-034"
x="-90">= 15.8 mm</tspan>
</text>
<line
id="line4658"
y2="-35"
x2="-147"
y1="45"
x1="-9" />
<use
id="use4660"
transform="matrix(-0.5,0.8660254,-0.8660254,-0.5,-9,45)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4662"
transform="matrix(0.5,-0.8660254,0.8660254,0.5,-147,-35)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<text
id="text4664"
y="-60"
x="-247"
style="text-anchor:start;stroke:none">
<tspan
id="tspan4666">h = 3.2 mm</tspan>
<tspan
id="tspan4668"
dy="1.8926892e-034"
x="-235">= 1/3 × H</tspan>
<tspan
id="tspan4670"
dy="1.8927287e-034"
x="-235">= 0.4 × P</tspan>
</text>
<line
id="line4672"
y2="-35"
x2="-147"
y1="-67"
x1="-147" />
<use
id="use4674"
transform="translate(-147,-67)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use4676"
transform="matrix(-1,0,0,-1,-147,-35)"
xlink:href="#arrow"
x="0"
y="0"
width="100%"
height="100%" />
<line
id="line4678"
y2="-62"
x2="-156"
y1="-70"
x1="-142" />
<line
id="line4680"
y2="-30"
x2="-156"
y1="-38"
x1="-142" />
<line
id="line4682"
y2="50"
x2="-17"
y1="42"
x1="-3" />
</g>
</g>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5268"
x="-0.0091189481"
width="1.0182379"
y="-0.017542355"
height="1.0350847">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.06438475"
id="feGaussianBlur5270" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5328"
x="-0.018060395"
width="1.0361208"
y="-0.035760824"
height="1.0715218">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.1314258"
id="feGaussianBlur5330" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5602"
x="-0.019410826"
width="1.0388217"
y="-0.03143103"
height="1.0628622">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.15183545"
id="feGaussianBlur5604" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5676"
x="-0.019262506"
width="1.038525"
y="-0.031827867"
height="1.0636557">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.1528711"
id="feGaussianBlur5678" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4406-3"
x="-0.023999998"
width="1.048"
y="-0.024000002"
height="1.048">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.55023435"
id="feGaussianBlur4408-6" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="radialGradient4171-0"
cx="247.58907"
cy="806.17749"
fx="247.58907"
fy="806.17749"
r="16.712261"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1673248,0,0,1.1673248,-43.580899,-140.69401)" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4209-7"
x="-0.023999365"
width="1.0479987"
y="-0.024000635"
height="1.0480013">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.36829105"
id="feGaussianBlur4211-6" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4260-5"
x="-0.035885267"
width="1.0717705"
y="-0.036115468"
height="1.0722309">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.3757032"
id="feGaussianBlur4262-7" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4479"
id="radialGradient4485-6"
cx="243.34979"
cy="799.60266"
fx="243.34979"
fy="799.60266"
r="26.382999"
gradientTransform="matrix(0.94262735,-0.96925492,1.4109273,1.372166,-1114.2197,-61.71694)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4507-13"
x="-0.011999792"
width="1.0239996"
y="-0.012000208"
height="1.0240004">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.26382543"
id="feGaussianBlur4509-2" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4406-3-61"
x="-0.023999998"
width="1.048"
y="-0.024000002"
height="1.048">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.55023435"
id="feGaussianBlur4408-6-3" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="radialGradient4171-0-4"
cx="247.58907"
cy="806.17749"
fx="247.58907"
fy="806.17749"
r="16.712261"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1673248,0,0,1.1673248,-43.580899,-140.69401)" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4209-7-7"
x="-0.023999365"
width="1.0479987"
y="-0.024000635"
height="1.0480013">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.36829105"
id="feGaussianBlur4211-6-4" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4260-5-2"
x="-0.035885267"
width="1.0717705"
y="-0.036115468"
height="1.0722309">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.3757032"
id="feGaussianBlur4262-7-25" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4479"
id="radialGradient4485-6-5"
cx="243.34979"
cy="799.60266"
fx="243.34979"
fy="799.60266"
r="26.382999"
gradientTransform="matrix(0.94262735,-0.96925492,1.4109273,1.372166,-1114.2197,-61.71694)"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4507-13-6"
x="-0.011999792"
width="1.0239996"
y="-0.012000208"
height="1.0240004">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.26382543"
id="feGaussianBlur4509-2-7" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.2311604"
inkscape:cx="130.15593"
inkscape:cy="112.1381"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="972"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
showguides="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-26.160786,-625.08677)">
<rect
y="665.62579"
x="57.765621"
height="81.142677"
width="217.85828"
id="rect5502"
style="font-style:normal;font-weight:normal;font-size:medium;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#ff0000;fill-opacity:1;stroke:#ffffff;stroke-width:0.83908439;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<g
transform="translate(-148.38464,-2.1702488)"
id="g5868-1-0"
inkscape:export-xdpi="99.888031"
inkscape:export-ydpi="99.888031">
<path
inkscape:export-ydpi="99.888062"
inkscape:export-xdpi="99.888062"
id="path4296-5-6"
d="m 216.28711,772.07227 0,55.02343 55.02344,0 0,-55.02343 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4406-3-61);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4148-9-7-6"
d="m 245.4367,781.96308 a 18.414436,18.414436 0 0 0 -18.41601,18.41406 18.414436,18.414436 0 0 0 18.41601,18.41407 18.414436,18.414436 0 0 0 18.41407,-18.41407 18.414436,18.414436 0 0 0 -18.41407,-18.41406 z m -1.70312,2 a 14.545857,14.545857 0 0 1 14.54687,14.54492 14.545857,14.545857 0 0 1 -14.54687,14.54688 14.545857,14.545857 0 0 1 -14.54492,-14.54688 14.545857,14.545857 0 0 1 14.54492,-14.54492 z"
style="opacity:1;fill:url(#radialGradient4171-0-4);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4209-7-7)" />
<path
inkscape:connector-curvature="0"
id="path4148-6-4-7"
d="m 243.65555,784.04016 a 14.545857,14.545857 0 0 0 -14.54493,14.54493 14.545857,14.545857 0 0 0 4.41993,10.42187 14.545857,14.545857 0 0 1 -3.95508,-9.95703 14.545857,14.545857 0 0 1 14.54492,-14.54492 14.545857,14.545857 0 0 1 10.11719,4.11328 14.545857,14.545857 0 0 0 -10.58203,-4.57813 z"
style="opacity:0.7;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4260-5-2)" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path4296-1-2-1"
d="m 216.96679,773.22058 0,0.74972 0,52.01445 52.766,-52.76417 z m 1.50126,1.49943 49.76348,0 -49.76348,49.76531 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient4485-6-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60997915;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4507-13-6);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
id="g5868"
inkscape:export-xdpi="99.888031"
inkscape:export-ydpi="99.888031">
<path
inkscape:export-ydpi="99.888062"
inkscape:export-xdpi="99.888062"
id="path4296"
d="m 216.28711,772.07227 0,55.02343 55.02344,0 0,-55.02343 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4406);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4148-9"
d="m 245.4367,781.96308 a 18.414436,18.414436 0 0 0 -18.41601,18.41406 18.414436,18.414436 0 0 0 18.41601,18.41407 18.414436,18.414436 0 0 0 18.41407,-18.41407 18.414436,18.414436 0 0 0 -18.41407,-18.41406 z m -1.70312,2 a 14.545857,14.545857 0 0 1 14.54687,14.54492 14.545857,14.545857 0 0 1 -14.54687,14.54688 14.545857,14.545857 0 0 1 -14.54492,-14.54688 14.545857,14.545857 0 0 1 14.54492,-14.54492 z"
style="opacity:1;fill:url(#radialGradient4171);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4209)" />
<path
inkscape:connector-curvature="0"
id="path4148-6"
d="m 243.65555,784.04016 a 14.545857,14.545857 0 0 0 -14.54493,14.54493 14.545857,14.545857 0 0 0 4.41993,10.42187 14.545857,14.545857 0 0 1 -3.95508,-9.95703 14.545857,14.545857 0 0 1 14.54492,-14.54492 14.545857,14.545857 0 0 1 10.11719,4.11328 14.545857,14.545857 0 0 0 -10.58203,-4.57813 z"
style="opacity:0.7;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4260)" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path4296-1"
d="m 216.96679,773.22058 0,0.74972 0,52.01445 52.766,-52.76417 z m 1.50126,1.49943 49.76348,0 -49.76348,49.76531 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient4485);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60997915;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4507);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
id="g5332"
transform="matrix(1.1226559,0,0,1.3295087,-29.131334,-264.53007)">
<path
id="path4898-7"
d="m 245.24023,795.35547 c -0.32818,0 -0.62759,0.0839 -0.89648,0.25 -0.26889,0.16226 -0.51759,0.40997 -0.74414,0.74609 -0.35993,0.53702 -0.64229,1.21012 -0.84766,2.01758 -0.20326,0.80359 -0.30468,1.65051 -0.30468,2.54297 0,1.07404 0.16742,1.91293 0.50195,2.51562 0.17136,0.3068 0.37667,0.53291 0.61523,0.6836 -0.16749,-0.1426 -0.32194,-0.31551 -0.45117,-0.54688 -0.33453,-0.60269 -0.50195,-1.44158 -0.50195,-2.51562 0,-0.89246 0.10143,-1.73938 0.30469,-2.54297 0.20537,-0.80746 0.48772,-1.48056 0.84765,-2.01758 0.22655,-0.33612 0.47525,-0.58383 0.74414,-0.74609 0.26889,-0.1661 0.56831,-0.25 0.89649,-0.25 0.29641,0 0.5786,0.0699 0.84961,0.20898 0.11658,0.0577 0.22984,0.13395 0.34179,0.2168 -0.16403,-0.14275 -0.33146,-0.26718 -0.50586,-0.35352 -0.27101,-0.13908 -0.5532,-0.20898 -0.84961,-0.20898 z m 4.94336,0 c -0.39805,0 -0.7615,0.14783 -1.09179,0.44531 -0.33029,0.29363 -0.62955,0.74101 -0.89844,1.33984 -0.22866,0.50999 -0.40976,1.09123 -0.54102,1.74415 -0.12916,0.65293 -0.19336,1.29209 -0.19336,1.91796 0,1.09336 0.16565,1.95425 0.49805,2.58399 0.17479,0.32903 0.38458,0.56731 0.62695,0.72461 -0.17215,-0.15097 -0.32987,-0.33749 -0.46289,-0.58789 -0.3324,-0.62974 -0.49804,-1.49063 -0.49804,-2.58399 0,-0.62587 0.0642,-1.26504 0.19336,-1.91797 0.13126,-0.65292 0.31235,-1.23416 0.54101,-1.74414 0.26889,-0.59883 0.56815,-1.04621 0.89844,-1.33984 0.33029,-0.29748 0.69375,-0.44531 1.0918,-0.44531 0.27698,0 0.52484,0.0759 0.74609,0.21875 -0.26064,-0.22728 -0.56071,-0.35547 -0.91016,-0.35547 z m -14.67187,0.15625 -0.91797,8.65234 0.17773,0 0.9043,-8.51562 0.4668,0 0.0137,-0.13672 -0.64453,0 z m 3.62695,0 -0.92383,8.65234 0.17774,0 0.91015,-8.51562 2.81836,0 0.0156,-0.13672 -2.99805,0 z m 11.64453,1.0664 c 0.1016,0.10262 0.19504,0.22559 0.27344,0.38868 0.21172,0.43657 0.31836,1.05378 0.31836,1.85351 0,0.45589 -0.0338,0.91525 -0.10156,1.375 -0.0677,0.45589 -0.16577,0.89136 -0.29492,1.3086 -0.19267,0.62203 -0.4261,1.09139 -0.69922,1.4082 -0.27101,0.31293 -0.58051,0.46875 -0.92774,0.46875 -0.17133,0 -0.32221,-0.0505 -0.45898,-0.13672 0.17429,0.17561 0.37854,0.27344 0.62304,0.27344 0.34723,0 0.65673,-0.15582 0.92774,-0.46875 0.27312,-0.31681 0.50655,-0.78618 0.69922,-1.40821 0.12915,-0.41723 0.22722,-0.8527 0.29492,-1.30859 0.0678,-0.45975 0.10156,-0.91911 0.10156,-1.375 0,-0.79973 -0.10664,-1.41694 -0.31836,-1.85351 -0.11844,-0.24641 -0.26587,-0.41698 -0.4375,-0.5254 z m -4.60156,0.125 c 0.20848,0.18276 0.39913,0.41306 0.56055,0.72071 l 0.01,-0.0996 c -0.15558,-0.24079 -0.32281,-0.44931 -0.51562,-0.5918 -0.0176,-0.0133 -0.0369,-0.017 -0.0547,-0.0293 z m -6.60547,2.35547 -0.0137,0.13672 2.08594,0 0.0156,-0.13672 -2.08789,0 z m 5.42188,0.58594 -0.0977,0.96094 0.17773,0 0.084,-0.82422 1.50391,0 0.0156,-0.13672 -1.68359,0 z m 0.93945,1.09766 -0.23047,2.1289 c -0.17573,0.1661 -0.36852,0.29395 -0.57812,0.38282 -0.20961,0.085 -0.42791,0.12695 -0.65235,0.12695 -0.25615,0 -0.47288,-0.0733 -0.65625,-0.20508 0.21121,0.22788 0.48368,0.3418 0.82031,0.3418 0.22444,0 0.44274,-0.0419 0.65235,-0.12696 0.2096,-0.0889 0.40239,-0.21671 0.57812,-0.38281 l 0.2461,-2.26562 -0.17969,0 z m -6.79688,2.4375 -0.0137,0.13672 2.23633,0 0.0137,-0.13672 -2.23633,0 z m -3.61914,0.0117 -0.0137,0.13671 2.12891,0 0.0156,-0.13671 -2.13086,0 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';letter-spacing:0px;word-spacing:0px;opacity:0.5;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter5268)"
inkscape:connector-curvature="0" />
<path
id="path5096"
d="m 236.28711,795.95312 -0.7793,7.375 0.24805,0 0.7793,-7.375 -0.24805,0 z m 5.98047,0 -0.0723,0.67969 -2.35937,0 -0.27344,2.5625 0.24805,0 0.24023,-2.25781 2.35938,0 0.10546,-0.98438 -0.24804,0 z m 9.36523,0.34571 c 0.0286,0.0465 0.0609,0.0823 0.0879,0.13281 0.33453,0.62201 0.50196,1.47093 0.50196,2.54883 0,0.66452 -0.0644,1.31765 -0.19141,1.95898 -0.12704,0.64133 -0.30974,1.22258 -0.54687,1.74414 -0.27101,0.6027 -0.57027,1.05208 -0.89844,1.34571 -0.32606,0.29361 -0.68969,0.43945 -1.08985,0.43945 -0.42003,0 -0.77338,-0.17011 -1.06445,-0.49805 0.32517,0.52581 0.74732,0.80274 1.2793,0.80274 0.40016,0 0.76378,-0.14585 1.08984,-0.43946 0.32817,-0.29363 0.62743,-0.743 0.89844,-1.3457 0.23713,-0.52156 0.41983,-1.10281 0.54687,-1.74414 0.12703,-0.64133 0.19141,-1.29446 0.19141,-1.95898 0,-1.0779 -0.16742,-1.92682 -0.50195,-2.54883 -0.0914,-0.17092 -0.19296,-0.31319 -0.30274,-0.4375 z m -4.60742,0.10937 -0.11719,1.12891 c 0.073,0.10398 0.14757,0.20362 0.21289,0.32812 l 0.12891,-1.24609 c -0.0731,-0.0809 -0.14933,-0.14225 -0.22461,-0.21094 z m -1.60937,0.0352 c -0.33665,0 -0.63249,0.11783 -0.88868,0.35352 -0.25618,0.2318 -0.48636,0.59137 -0.6875,1.08203 -0.17149,0.41725 -0.30675,0.91059 -0.40625,1.47851 -0.0974,0.56406 -0.14453,1.13932 -0.14453,1.72656 0,0.80747 0.1133,1.41666 0.33985,1.82618 0.059,0.10566 0.12721,0.1954 0.20117,0.27343 -0.21635,-0.40908 -0.32617,-1.00584 -0.32617,-1.79492 0,-0.58724 0.0471,-1.1625 0.14453,-1.72656 0.0995,-0.56792 0.23476,-1.06127 0.40625,-1.47852 0.20114,-0.49066 0.43132,-0.85023 0.6875,-1.08203 0.25619,-0.23568 0.55202,-0.35351 0.88867,-0.35351 0.29006,0 0.56412,0.0959 0.82031,0.28906 0.11151,0.0824 0.21347,0.18948 0.3125,0.30469 -0.15847,-0.24921 -0.32978,-0.46339 -0.52734,-0.60938 -0.25619,-0.19316 -0.53025,-0.28906 -0.82031,-0.28906 z m 4.91406,0 c -0.35147,0 -0.66275,0.15581 -0.93164,0.46875 -0.26889,0.30907 -0.50216,0.78245 -0.70117,1.41992 -0.12704,0.40566 -0.22527,0.83708 -0.29297,1.29297 -0.0657,0.45589 -0.0977,0.91529 -0.0977,1.37891 0,0.8036 0.10485,1.42281 0.31445,1.85937 0.0711,0.14656 0.15561,0.26015 0.2461,0.35742 -0.01,-0.019 -0.0216,-0.0329 -0.0312,-0.0527 -0.2096,-0.43656 -0.31446,-1.05578 -0.31446,-1.85938 0,-0.46362 0.032,-0.92301 0.0977,-1.3789 0.0677,-0.45589 0.16593,-0.88731 0.29297,-1.29297 0.19901,-0.63747 0.43228,-1.11085 0.70117,-1.41992 0.26889,-0.31294 0.58017,-0.46875 0.93164,-0.46875 0.25109,0 0.46174,0.10403 0.63867,0.29297 -0.20888,-0.39422 -0.49094,-0.59766 -0.85351,-0.59766 z m -8.53516,3.05664 -0.0723,0.67969 -2.26368,0 -0.33203,3.13672 0.24805,0 0.29883,-2.83203 2.26367,0 0.10547,-0.98438 -0.24805,0 z m 5.01758,0.58594 -0.37695,3.50195 c -0.2816,0.28204 -0.58947,0.49976 -0.92188,0.6543 -0.33241,0.15066 -0.66531,0.22656 -1.00195,0.22656 -0.4443,0 -0.81665,-0.16771 -1.11719,-0.50391 0.3311,0.53237 0.77289,0.8086 1.33203,0.8086 0.33664,0 0.66955,-0.0759 1.00196,-0.22656 0.33241,-0.15454 0.64027,-0.37226 0.92187,-0.6543 l 0.41016,-3.80664 -0.24805,0 z m -1.50195,0.65625 -0.0312,0.30469 0.80468,0 0.0332,-0.30469 -0.80664,0 z m -3.80078,2.8789 -0.0723,0.67969 -2.81055,0 -0.0332,0.30469 3.05859,0 0.10352,-0.98438 -0.24609,0 z m -3.72657,0.0117 -0.0723,0.66797 -2.70508,0 -0.0332,0.30469 2.95312,0 0.10547,-0.97266 -0.24805,0 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';letter-spacing:0px;word-spacing:0px;opacity:0.5;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5328)"
inkscape:connector-curvature="0" />
</g>
<path
sodipodi:nodetypes="cssccsscccsccccscccssccsccccccccccscccscscccscccccccscccccccscccscccscccccscsccccccccccccccc"
id="path5423"
d="m 104.89822,791.46407 c 0.0801,0.0663 0.16145,0.13186 0.23242,0.21289 0.38967,0.4449 0.58594,1.04084 0.58594,1.78906 0,0.73309 -0.15579,1.36289 -0.46484,1.88867 -0.30571,0.5258 -0.72869,0.88602 -1.26954,1.07813 0.42327,0.18202 0.73344,0.46538 0.93164,0.84961 0.19821,0.38424 0.29883,0.89147 0.29883,1.52344 0,0.60668 -0.0981,1.17619 -0.29297,1.70703 -0.19147,0.53084 -0.46922,0.98685 -0.83203,1.37109 -0.27547,0.29324 -0.60336,0.51079 -0.98633,0.65234 -0.38296,0.14661 -0.82564,0.22071 -1.32617,0.22071 -0.31577,0 -0.63453,-0.0485 -0.95703,-0.14453 -0.15662,-0.0442 -0.31565,-0.0994 -0.47461,-0.16602 l -0.006,0.0508 c 0.33257,0.18706 0.65992,0.32502 0.98243,0.41602 0.32249,0.0961 0.64125,0.14453 0.95703,0.14453 0.50053,0 0.94321,-0.0741 1.32617,-0.2207 0.38296,-0.14156 0.71086,-0.35911 0.98633,-0.65235 0.3628,-0.38423 0.64055,-0.84025 0.83203,-1.37109 0.19483,-0.53085 0.29297,-1.10035 0.29297,-1.70703 0,-0.63197 -0.10063,-1.13921 -0.29883,-1.52344 -0.1982,-0.38424 -0.50837,-0.6676 -0.93164,-0.84961 0.54084,-0.19212 0.96383,-0.55233 1.26953,-1.07812 0.30905,-0.52579 0.46484,-1.15559 0.46484,-1.88868 0,-0.74823 -0.19626,-1.34415 -0.58593,-1.78906 -0.20565,-0.23478 -0.45209,-0.40262 -0.73438,-0.51367 z m -8.10938,0.0508 -1.25195,9.46082 0.54102,0 1.25195,-9.46082 z m -4.58984,0.0137 c 0.24292,0.18913 0.47005,0.41261 0.66211,0.70899 0.53077,0.81397 0.79688,1.92735 0.79688,3.33789 0,0.86958 -0.10118,1.72326 -0.30274,2.5625 -0.20155,0.83925 -0.49095,1.60068 -0.86719,2.2832 -0.42999,0.7887 -0.90509,1.37553 -1.42578,1.75977 -0.51734,0.38424 -1.09361,0.57617 -1.72851,0.57617 -0.37359,0 -0.70636,-0.0859 -1.01563,-0.22071 0.42915,0.33503 0.92861,0.52149 1.51758,0.52149 0.63491,0 1.21118,-0.19194 1.72852,-0.57617 0.52069,-0.38424 0.99579,-0.97108 1.42578,-1.75977 0.37624,-0.68252 0.66563,-1.44395 0.86718,-2.2832 0.20156,-0.83924 0.30274,-1.69292 0.30274,-2.5625 0,-1.41055 -0.26611,-2.52392 -0.79688,-3.33789 -0.31626,-0.48804 -0.70972,-0.81255 -1.16406,-1.00977 z m 11.13281,0.70899 c -0.32249,0 -0.6529,0.054 -0.99218,0.16015 -0.15641,0.0471 -0.31657,0.10758 -0.47852,0.17774 l -0.0664,0.58593 c 0.36281,-0.20727 0.71095,-0.36177 1.04688,-0.46289 0.33929,-0.10617 0.6697,-0.16015 0.99219,-0.16015 0.17244,0 0.32535,0.0273 0.46679,0.0703 -0.23358,-0.24575 -0.55628,-0.37109 -0.96875,-0.37109 z m -12.67773,0.0156 c -0.55764,0 -1.04993,0.20572 -1.47656,0.61524 -0.42663,0.40447 -0.79752,1.02323 -1.11328,1.85742 -0.20156,0.53085 -0.35541,1.09483 -0.4629,1.6914 -0.10416,0.59658 -0.15624,1.19801 -0.15624,1.80469 0,1.05159 0.16547,1.8623 0.49804,2.4336 0.22791,0.38759 0.52393,0.63304 0.87891,0.75781 -0.13888,-0.12558 -0.26747,-0.27084 -0.37695,-0.45703 -0.33258,-0.5713 -0.49805,-1.38201 -0.49805,-2.4336 0,-0.60668 0.0521,-1.20811 0.15625,-1.80468 0.10749,-0.59657 0.26133,-1.16056 0.46289,-1.69141 0.31577,-0.83419 0.68665,-1.45296 1.11328,-1.85742 0.42663,-0.40951 0.91892,-0.61524 1.47656,-0.61524 0.19185,0 0.36453,0.0402 0.5293,0.0977 -0.28484,-0.25761 -0.62491,-0.39844 -1.03125,-0.39844 z m 11.68164,4.86133 -0.0371,0.30078 0.875,0 c 0.21444,0 0.40312,0.0322 0.57422,0.0879 -0.25937,-0.25663 -0.61645,-0.38867 -1.07617,-0.38867 l -0.33594,0 z m -1.8125,3.93359 -0.008,0.0547 c 0.0942,0.0577 0.18876,0.10037 0.2832,0.14649 -0.0921,-0.0653 -0.18369,-0.12483 -0.27539,-0.20118 z m -1.36133,0.51563 -0.12695,0.97265 -4.14649,0 -0.0391,0.30079 4.6875,0 0.16602,-1.27344 -0.54102,0 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';letter-spacing:0px;word-spacing:0px;opacity:0.5;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter5602)"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="scccsccscccsccsscccccccsccccccccccccccscsccccscsccccscccsccscccsccccscsccccccscsccccccccc"
id="path5423-3-3"
d="m 90.46658,790.68087 c -0.63154,0 -1.21032,0.19469 -1.73438,0.58398 -0.52404,0.38423 -0.99914,0.96831 -1.42578,1.75195 -0.3628,0.66735 -0.6472,1.42879 -0.85547,2.28321 -0.20491,0.85441 -0.30859,1.69074 -0.30859,2.50976 0,1.43077 0.26361,2.55874 0.79102,3.38282 0.0431,0.0669 0.095,0.11431 0.14062,0.17578 -0.46959,-0.80995 -0.71289,-1.88038 -0.71289,-3.23047 0,-0.81903 0.10368,-1.65535 0.30859,-2.50977 0.20827,-0.85441 0.49267,-1.61586 0.85547,-2.2832 0.42664,-0.78364 0.90174,-1.36773 1.42578,-1.75195 0.52406,-0.3893 1.10284,-0.58399 1.73438,-0.58399 0.85021,0 1.52538,0.36567 2.04297,1.06445 -0.0307,-0.0524 -0.0532,-0.11389 -0.0859,-0.16406 -0.53075,-0.81902 -1.25533,-1.22851 -2.17578,-1.22851 z m 12.86328,0 c -0.33593,0 -0.67798,0.0422 -1.02734,0.12304 -0.34601,0.0809 -0.70469,0.20151 -1.07422,0.36328 l -0.1543,1.36524 c 0.0924,-0.0528 0.18092,-0.0927 0.27149,-0.13867 l 0.10156,-0.89844 c 0.36952,-0.16178 0.72821,-0.28244 1.07422,-0.36328 0.34936,-0.0808 0.69141,-0.12305 1.02734,-0.12305 0.66514,0 1.19234,0.22307 1.58203,0.66797 0.0225,0.0257 0.0374,0.0572 0.0586,0.084 -0.0787,-0.14832 -0.16821,-0.2875 -0.27735,-0.41211 -0.38969,-0.4449 -0.91689,-0.66796 -1.58203,-0.66796 z m -7.74414,0.20507 -1.45703,11.32227 0.26172,0 1.41406,-10.99414 0.76172,0 0.043,-0.32813 -1.02344,0 z m 8.7168,1.72461 c 0.10148,0.2186 0.15625,0.48024 0.15625,0.79297 0,0.65724 -0.15993,1.17826 -0.48243,1.5625 -0.31912,0.38423 -0.75876,0.57617 -1.3164,0.57617 l -0.92774,0 -0.15429,1.24414 0.25976,0 0.11328,-0.91601 0.92774,0 c 0.55764,0 0.99728,-0.19194 1.31641,-0.57617 0.32249,-0.38424 0.48242,-0.90527 0.48242,-1.5625 0,-0.47523 -0.11643,-0.84177 -0.35157,-1.09961 -0.007,-0.008 -0.0161,-0.0137 -0.0234,-0.0215 z m -12.41407,0.25977 c 0.30812,0.5663 0.4668,1.34344 0.4668,2.3457 0,0.59657 -0.0527,1.1972 -0.16015,1.79883 -0.1075,0.59657 -0.26384,1.16688 -0.46876,1.71289 -0.3057,0.81397 -0.67602,1.4292 -1.10937,1.84375 -0.42998,0.40951 -0.91977,0.61328 -1.4707,0.61328 -0.51257,0 -0.92303,-0.2136 -1.24219,-0.61523 0.0144,0.0269 0.024,0.0601 0.0391,0.0859 0.33593,0.57128 0.81048,0.85742 1.42188,0.85742 0.55093,0 1.04072,-0.20377 1.4707,-0.61328 0.43335,-0.41456 0.80367,-1.02978 1.10938,-1.84375 0.20491,-0.54602 0.36125,-1.11632 0.46874,-1.71289 0.1075,-0.60163 0.16016,-1.20226 0.16016,-1.79883 0,-1.04653 -0.16798,-1.8545 -0.5039,-2.42578 -0.055,-0.0943 -0.11937,-0.16912 -0.18165,-0.24805 z m 11.89844,4.66797 c 0.11882,0.24454 0.1836,0.54026 0.1836,0.89453 0,0.81901 -0.20595,1.48627 -0.61915,2.00195 -0.40983,0.51063 -0.94564,0.76563 -1.60742,0.76563 -0.33592,0 -0.66578,-0.0631 -0.98828,-0.18946 -0.31913,-0.13143 -0.63735,-0.32888 -0.95312,-0.59179 l -0.18555,1.44922 c 0.0828,0.0465 0.16399,0.0806 0.24609,0.12109 l 0.15821,-1.24219 c 0.31577,0.2629 0.63399,0.46036 0.95312,0.5918 0.3225,0.12639 0.65235,0.18945 0.98828,0.18945 0.66178,0 1.19759,-0.255 1.60743,-0.76562 0.41319,-0.51568 0.61914,-1.18294 0.61914,-2.00196 0,-0.52579 -0.13055,-0.93171 -0.39258,-1.21484 -0.003,-0.003 -0.007,-0.005 -0.01,-0.008 z m -8.20703,3.39648 -0.043,0.32813 3.40235,0 0.043,-0.32813 -3.40234,0 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.6600647px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Italic';letter-spacing:0px;word-spacing:0px;opacity:0.4;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter5676)"
inkscape:connector-curvature="0" />
<g
transform="translate(-71.352998,-1.0760495)"
id="g5868-1"
inkscape:export-xdpi="99.888031"
inkscape:export-ydpi="99.888031">
<path
inkscape:export-ydpi="99.888062"
inkscape:export-xdpi="99.888062"
id="path4296-5"
d="m 216.28711,772.07227 0,55.02343 55.02344,0 0,-55.02343 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4406-3);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4148-9-7"
d="m 245.4367,781.96308 a 18.414436,18.414436 0 0 0 -18.41601,18.41406 18.414436,18.414436 0 0 0 18.41601,18.41407 18.414436,18.414436 0 0 0 18.41407,-18.41407 18.414436,18.414436 0 0 0 -18.41407,-18.41406 z m -1.70312,2 a 14.545857,14.545857 0 0 1 14.54687,14.54492 14.545857,14.545857 0 0 1 -14.54687,14.54688 14.545857,14.545857 0 0 1 -14.54492,-14.54688 14.545857,14.545857 0 0 1 14.54492,-14.54492 z"
style="opacity:1;fill:url(#radialGradient4171-0);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4209-7)" />
<path
inkscape:connector-curvature="0"
id="path4148-6-4"
d="m 243.65555,784.04016 a 14.545857,14.545857 0 0 0 -14.54493,14.54493 14.545857,14.545857 0 0 0 4.41993,10.42187 14.545857,14.545857 0 0 1 -3.95508,-9.95703 14.545857,14.545857 0 0 1 14.54492,-14.54492 14.545857,14.545857 0 0 1 10.11719,4.11328 14.545857,14.545857 0 0 0 -10.58203,-4.57813 z"
style="opacity:0.7;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4260-5)" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path4296-1-2"
d="m 216.96679,773.22058 0,0.74972 0,52.01445 52.766,-52.76417 z m 1.50126,1.49943 49.76348,0 -49.76348,49.76531 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient4485-6);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.60997915;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4507-13);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 50 KiB

97
build/geom/ConvexHull.js Normal file
View File

@ -0,0 +1,97 @@
/*
Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (http://www.cecill.info/).
ol.coordinate.convexHull compute a convex hull using Andrew's Monotone Chain Algorithm.
@see https://en.wikipedia.org/wiki/Convex_hull_algorithms
*/
import ol_geom_Geometry from 'ol/geom/geometry'
(function(){
/* Tests if a point is left or right of line (a,b).
* @param {ol.coordinate} a point on the line
* @param {ol.coordinate} b point on the line
* @param {ol.coordinate} 0
* @return {bool} true if (a,b,o) turns clockwise
*/
function clockwise (a, b, o)
{ return ( (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) <= 0 )
}
/** Compute a convex hull using Andrew's Monotone Chain Algorithm
* @param {Array<ol.geom.Point>} points an array of 2D points
* @return {Array<ol.geom.Point>} the convex hull vertices
*/
var ol_coordinate_convexHull = function (points)
{ // Sort by increasing x and then y coordinate
points.sort(function(a, b)
{ return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
});
// Compute the lower hull
var lower = [];
for (var i = 0; i < points.length; i++)
{ while (lower.length >= 2 && clockwise (lower[lower.length - 2], lower[lower.length - 1], points[i]) )
{ lower.pop();
}
lower.push(points[i]);
}
// Compute the upper hull
var upper = [];
for (var i = points.length - 1; i >= 0; i--)
{ while (upper.length >= 2 && clockwise (upper[upper.length - 2], upper[upper.length - 1], points[i]) )
{ upper.pop();
}
upper.push(points[i]);
}
upper.pop();
lower.pop();
return lower.concat(upper);
}
/* Get coordinates of a geometry */
function getCoordinates(geom)
{ var h = [];
switch (geom.getType())
{ case "Point":
h.push(geom.getCoordinates());
break;
case "LineString":
case "LinearRing":
case "MultiPoint":
h = geom.getCoordinates();
break;
case "MultiLineString":
var p = geom.getLineStrings();
for (var i=0; i<p.length; i++) h.concat(getCoordinates(p[i]));
break;
case "Polygon":
h = getCoordinates(geom.getLinearRing(0));
break;
case "MultiPolygon":
var p = geom.getPolygons();
for (var i=0; i<p.length; i++) h.concat(getCoordinates(p[i]));
break;
case "GeometryCollection":
var p = geom.getGeometries();
for (var i=0; i<p.length; i++) h.concat(getCoordinates(p[i]));
break;
default:break;
}
return h;
}
/** Compute a convex hull on a geometry using Andrew's Monotone Chain Algorithm
* @return {Array<ol.geom.Point>} the convex hull vertices
*/
ol_geom_Geometry.prototype.convexHull = function()
{ return ol_coordinate_convexHull( getCoordinates(this) );
};
})();

122
build/geom/GeomUtils.js Normal file
View File

@ -0,0 +1,122 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
Usefull function to handle geometric operations
*/
import ol_geom_LineString from 'ol/geom/linestring'
import ol_coordinate from 'ol/coordinate'
import ol_extent from 'ol/extent'
/** Distance beetween 2 points
* Usefull geometric functions
* @param {ol.coordinate} p1 first point
* @param {ol.coordinate} p2 second point
* @return {number} distance
*/
var ol_coordinate_dist2d = function(p1, p2)
{ var dx = p1[0]-p2[0];
var dy = p1[1]-p2[1];
return Math.sqrt(dx*dx+dy*dy);
}
/** 2 points are equal
* Usefull geometric functions
* @param {ol.coordinate} p1 first point
* @param {ol.coordinate} p2 second point
* @return {boolean}
*/
var ol_coordinate_equal = function(p1, p2)
{ return (p1[0]==p2[0] && p1[1]==p2[1]);
}
/** Get center coordinate of a feature
* @param {ol.Feature} f
* @return {ol.coordinate} the center
*/
var ol_coordinate_getFeatureCenter = function(f)
{ return ol_coordinate.getGeomCenter (f.getGeometry());
};
/** Get center coordinate of a geometry
* @param {ol.Feature} geom
* @return {ol.coordinate} the center
*/
var ol_coordinate_getGeomCenter = function(geom)
{ switch (geom.getType())
{ case 'Point':
return geom.getCoordinates();
case "MultiPolygon":
geom = geom.getPolygon(0);
case "Polygon":
return geom.getInteriorPoint().getCoordinates();
default:
return geom.getClosestPoint(ol_extent.getCenter(geom.getExtent()));
};
};
/** Split a lineString by a point or a list of points
* NB: points must be on the line, use getClosestPoint() to get one
* @param {ol.Coordinate | Array<ol.Coordinate>} pt points to split the line
* @param {Number} tol distance tolerance for 2 points to be equal
*/
ol_geom_LineString.prototype.splitAt = function(pt, tol)
{ if (!pt) return [this];
if (!tol) tol = 1e-10;
// Test if list of points
if (pt.length && pt[0].length)
{ var result = [this];
for (var i=0; i<pt.length; i++)
{ var r = [];
for (var k=0; k<result.length; k++)
{ var ri = result[k].splitAt(pt[i], tol);
r = r.concat(ri);
}
result = r;
}
return result;
}
// Nothing to do
if (ol_coordinate.equal(pt,this.getFirstCoordinate())
|| ol_coordinate.equal(pt,this.getLastCoordinate()))
{ return [this];
}
// Get
var c0 = this.getCoordinates();
var ci=[c0[0]], p0, p1;
var c = [];
for (var i=0; i<c0.length-1; i++)
{ // Filter equal points
if (ol_coordinate.equal(c0[i],c0[i+1])) continue;
// Extremity found
if (ol_coordinate.equal(pt,c0[i+1]))
{ ci.push(c0[i+1]);
c.push(new ol.geom.LineString(ci));
ci = [];
}
// Test alignement
else if (!ol_coordinate.equal(pt,c0[i]))
{ var d1, d2;
if (c0[i][0] == c0[i+1][0])
{ d1 = d2 = (c0[i][1]-pt[1]) / (c0[i][1]-c0[i+1][1]);
}
else if (c0[i][1] == c0[i+1][1])
{ d1 = d2 = (c0[i][0]-pt[0]) / (c0[i][0]-c0[i+1][0]);
}
else
{ d1 = (c0[i][0]-pt[0]) / (c0[i][0]-c0[i+1][0]);
d2 = (c0[i][1]-pt[1]) / (c0[i][1]-c0[i+1][1]);
}
if (Math.abs(d1-d2)<tol && 0<=d1 && d1<=1)
{ ci.push(pt);
c.push (new ol.geom.LineString(ci));
ci = [pt];
}
}
ci.push(c0[i+1]);
}
if (ci.length>1) c.push (new ol_geom_LineString(ci));
if (c.length) return c;
else return [this];
}

View File

@ -0,0 +1,149 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_style_RegularShape from 'ol/style/regularshape'
import ol_style_Style from 'ol/style/style'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_geom_Point from 'ol/geom/point'
import ol_Map from 'ol/map'
import ol_style_Stroke from 'ol/style/stroke'
/** Handles coordinates on the center of the viewport.
* It can be used as abstract base class used for creating subclasses.
* The CenterTouch interaction modifies map browser event coordinate and pixel properties to force pointer on the viewport center to any interaction that them.
* Only pointermove pointerup are concerned with it.
* @constructor
* @extends {ol_interaction_Interaction}
* @param {olx.interaction.InteractionOptions} options Options
* - targetStyle {ol_style_Style|Array<ol_style_Style>} a style to draw the target point, default cross style
* - composite {string} composite operation : difference|multiply|xor|screen|overlay|darken|lighter|lighten|...
*/
var ol_interaction_CenterTouch = function(options)
{ options = options || {};
// Filter event
var rex = /^pointermove$|^pointerup$/;
// Default style = cross
this.targetStyle = options.targetStyle ||
[ new ol_style_Style({ image: new ol_style_RegularShape ({ points: 4, radius: 11, radius1: 0, radius2: 0, snapToPixel:true, stroke: new ol_style_Stroke({ color: "#fff", width:3 }) }) }),
new ol_style_Style({ image: new ol_style_RegularShape ({ points: 4, radius: 11, radius1: 0, radius2: 0, snapToPixel:true, stroke: new ol_style_Stroke({ color: "#000", width:1 }) }) })
];
if (!(this.targetStyle instanceof Array)) this.targetStyle = [this.targetStyle];
this.composite = options.composite || '';
// Interaction to defer center on top of the interaction
// this is done to enable other coordinates manipulation inserted after the interaction (snapping)
this.ctouch = new ol_interaction_Interaction(
{ handleEvent: function(e)
{ if (rex.test(e.type) && this.getMap())
{ e.coordinate = this.getMap().getView().getCenter();
e.pixel = this.getMap().getSize();
e.pixel = [ e.pixel[0]/2, e.pixel[1]/2 ];
}
return true;
}
});
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ if (rex.test(e.type)) this.pos_ = e.coordinate;
if (options.handleEvent) return options.handleEvent.call (this,e);
return true;
}
});
};
ol.inherits(ol_interaction_CenterTouch, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {_ol_Map_} map Map.
* @api stable
*/
ol_interaction_CenterTouch.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().removeInteraction(this.ctouch);
this.getMap().un('postcompose', this.drawTarget_, this);
}
ol_interaction_Interaction.prototype.setMap.call (this, map);
if (this.getMap())
{ if (this.getActive()) this.getMap().addInteraction(this.ctouch);
this.getMap().on('postcompose', this.drawTarget_, this);
}
};
/**
* Activate or deactivate the interaction.
* @param {boolean} active Active.
* @observable
* @api
*/
ol_interaction_CenterTouch.prototype.setActive = function(b)
{ ol_interaction_Interaction.prototype.setActive.call (this, b);
this.pos_ = null;
if (this.getMap())
{ if (this.getActive())
{ this.getMap().addInteraction(this.ctouch);
}
else this.getMap().removeInteraction(this.ctouch);
}
};
/** Get the position of the target
*/
ol_interaction_CenterTouch.prototype.getPosition = function (e)
{ if (!this.pos_)
{ var px =this.getMap().getSize();
px = [ px[0]/2, px[1]/2 ];
this.pos_ = this.getMap().getCoordinateFromPixel(px);
}
return this.pos_;
};
/** Draw the target
* @private
*/
ol_interaction_CenterTouch.prototype.drawTarget_ = function (e)
{ if (!this.getMap() || !this.getActive()) return;
var ctx = e.context;
var ratio = e.frameState.pixelRatio;
ctx.save();
var cx = ctx.canvas.width/(2*ratio);
var cy = ctx.canvas.height/(2*ratio);
var geom = new ol_geom_Point (this.getMap().getCoordinateFromPixel([cx,cy]));
if (this.composite) ctx.globalCompositeOperation = this.composite;
for (var i=0; i<this.targetStyle.length; i++)
{ var style = this.targetStyle[i];
if (style instanceof ol_style_Style)
{ var sc=0;
// OL < v4.3 : setImageStyle doesn't check retina
var imgs = ol_Map.prototype.getFeaturesAtPixel ? false : style.getImage();
if (imgs)
{ sc = imgs.getScale();
imgs.setScale(ratio*sc);
}
e.vectorContext.setStyle(style);
e.vectorContext.drawGeometry(geom);
if (imgs) imgs.setScale(sc);
}
}
ctx.restore();
};
export default ol_interaction_CenterTouch

148
build/interaction/Clip.js Normal file
View File

@ -0,0 +1,148 @@
import ol from 'ol'
import ol_interaction_Pointer from 'ol/interaction/pointer'
/** Clip interaction to clip layers in a circle
* @constructor
* @extends {ol_interaction_Pointer}
* @param {ol_interaction_Clip.options} options flashlight param
* - radius {number} radius of the clip, default 100
* - layers {ol.layer|Array<ol.layer>} layers to clip
*/
var ol_interaction_Clip = function(options) {
this.layers_ = [];
ol_interaction_Pointer.call(this,
{ handleDownEvent: this.setPosition,
handleMoveEvent: this.setPosition
});
// Default options
options = options || {};
this.pos = false;
this.radius = (options.radius||100);
if (options.layers) this.addLayer(options.layers);
};
ol.inherits(ol_interaction_Clip, ol_interaction_Pointer);
/** Set the map > start postcompose
*/
ol_interaction_Clip.prototype.setMap = function(map)
{ if (this.getMap())
{ for (var i=0; i<this.layers_.length; i++)
{ this.layers_[i].un('precompose', this.precompose_, this);
this.layers_[i].un('postcompose', this.postcompose_, this);
}
this.getMap().renderSync();
}
ol_interaction_Pointer.prototype.setMap.call(this, map);
if (map)
{ for (var i=0; i<this.layers_.length; i++)
{ this.layers_[i].on('precompose', this.precompose_, this);
this.layers_[i].on('postcompose', this.postcompose_, this);
}
map.renderSync();
}
}
/** Set clip radius
* @param {integer} radius
*/
ol_interaction_Clip.prototype.setRadius = function(radius)
{ this.radius = radius;
if (this.getMap()) this.getMap().renderSync();
}
/** Add a layer to clip
* @param {ol.layer|Array<ol.layer>} layer to clip
*/
ol_interaction_Clip.prototype.addLayer = function(layers)
{ if (!(layers instanceof Array)) layers = [layers];
for (var i=0; i<layers.length; i++)
{ if (this.getMap())
{ layers[i].on('precompose', this.precompose_, this);
layers[i].on('postcompose', this.postcompose_, this);
this.getMap().renderSync();
}
this.layers_.push(layers[i]);
}
}
/** Remove a layer to clip
* @param {ol.layer|Array<ol.layer>} layer to clip
*/
ol_interaction_Clip.prototype.removeLayer = function(layers)
{ if (!(layers instanceof Array)) layers = [layers];
for (var i=0; i<layers.length; i++)
{ var k;
for (k=0; k<this.layers_.length; k++)
{ if (this.layers_[k]===layers[i])
{ break;
}
}
if (k!=this.layers_.length && this.getMap())
{ this.layers_.splice(k,1);
layers[i].un('precompose', this.precompose_, this);
layers[i].un('postcompose', this.postcompose_, this);
this.getMap().renderSync();
}
}
}
/** Set position of the clip
* @param {ol.Pixel|ol.MapBrowserEvent}
*/
ol_interaction_Clip.prototype.setPosition = function(e)
{ if (e.pixel) this.pos = e.pixel;
else
{ if (e && e instanceof Array) this.pos = e;
else e = [-10000000,-10000000];
}
if (this.getMap()) this.getMap().renderSync();
}
/* @private
*/
ol_interaction_Clip.prototype.precompose_ = function(e)
{ var ctx = e.context;
var ratio = e.frameState.pixelRatio;
ctx.save();
ctx.beginPath();
ctx.arc (this.pos[0]*ratio, this.pos[1]*ratio, this.radius*ratio, 0, 2*Math.PI);
ctx.clip();
}
/* @private
*/
ol_interaction_Clip.prototype.postcompose_ = function(e)
{ e.context.restore();
};
/**
* Activate or deactivate the interaction.
* @param {boolean} active Active.
* @observable
* @api
*/
ol_interaction_Clip.prototype.setActive = function(b)
{ ol_interaction_Pointer.prototype.setActive.call (this, b);
if(b) {
for(var i=0; i<this.layers_.length; i++) {
this.layers_[i].on('precompose', this.precompose_, this);
this.layers_[i].on('postcompose', this.postcompose_, this);
}
} else {
for(var i=0; i<this.layers_.length; i++) {
this.layers_[i].un('precompose', this.precompose_, this);
this.layers_[i].un('postcompose', this.postcompose_, this);
}
}
if (this.getMap()) this.getMap().renderSync();
}
export default ol_interaction_Clip

View File

@ -0,0 +1,171 @@
/* Copyright (c) 2017 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_geom_Polygon from 'ol/geom/polygon'
import ol_geom_LinearRing from 'ol/geom/linearring'
import ol_interaction_Draw from 'ol/interaction/draw'
import ol_interaction_Select from 'ol/interaction/select'
/** Interaction draw hole
* @constructor
* @extends {ol_interaction_Interaction}
* @fires drawstart, drawend
* @param {olx.interaction.DrawHoleOptions} options extend olx.interaction.DrawOptions
* @param {Array<ol.layer.Vector> | undefined} options.layers A list of layers from which polygons should be selected. Alternatively, a filter function can be provided. default: all visible layers
*/
var ol_interaction_DrawHole = function(options)
{ if (!options) options = {};
var self = this;
// Select interaction for the current feature
this._select = new ol_interaction_Select();
this._select.setActive(false);
// Geometry function that test points inside the current
var geometryFn, geomFn = options.geometryFunction;
if (geomFn)
{ geometryFn = function(c,g)
{ g = self._geometryFn (c, g);
return geomFn (c,g);
}
}
else
{ geometryFn = function(c,g) { return self._geometryFn (c, g); }
}
// Create draw interaction
options.type = "Polygon";
options.geometryFunction = geometryFn;
ol_interaction_Draw.call(this, options);
// Layer filter function
if (options.layers)
{ if (typeof (options.layers) === 'function') this.layers_ = options.layers;
else if (options.layers.indexOf)
{ this.layers_ = function(l)
{ return (options.layers.indexOf(l) >= 0);
};
}
}
// Start drawing if inside a feature
this.on('drawstart', this._startDrawing, this );
// End drawing add the hole to the current Polygon
this.on('drawend', this._finishDrawing, this);
};
ol.inherits(ol_interaction_DrawHole, ol_interaction_Draw);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_DrawHole.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeInteraction(this._select);
if (map) map.addInteraction(this._select);
ol_interaction_Draw.prototype.setMap.call (this, map);
};
/**
* Activate/deactivate the interaction
* @param {boolean}
* @api stable
*/
ol_interaction_DrawHole.prototype.setActive = function(b)
{ this._select.getFeatures().clear();
ol_interaction_Draw.prototype.setActive.call (this, b);
};
/**
* Remove last point of the feature currently being drawn
* (test if points to remove before).
*/
ol_interaction_DrawHole.prototype.removeLastPoint = function()
{ if (this._feature && this._feature.getGeometry().getCoordinates()[0].length>2)
{ ol_interaction_Draw.prototype.removeLastPoint.call(this);
}
};
/**
* Get the current polygon to hole
* @return {ol.Feature}
*/
ol_interaction_DrawHole.prototype.getPolygon = function()
{ return this._select.getFeatures().item(0);
};
/**
* Get current feature to add a hole and start drawing
* @param {ol_interaction_Draw.Event} e
* @private
*/
ol_interaction_DrawHole.prototype._startDrawing = function(e)
{ var map = this.getMap();
var layersFilter = this.layers_;
this._feature = e.feature;
coord = e.feature.getGeometry().getCoordinates()[0][0];
// Check object under the pointer
var features = map.getFeaturesAtPixel(
map.getPixelFromCoordinate(coord),
{ layerFilter: layersFilter
}
);
var current = null;
if (features)
{ if (features[0].getGeometry().getType() !== "Polygon") current = null;
else if (features[0].getGeometry().intersectsCoordinate(coord)) current = features[0];
else current = null;
}
else current = null;
if (!current)
{ this.setActive(false);
this.setActive(true);
this._select.getFeatures().clear();
}
else
{ this._select.getFeatures().push(current);
}
};
/**
* Stop drawing and add the sketch feature to the target feature.
* @param {ol_interaction_Draw.Event} e
* @private
*/
ol_interaction_DrawHole.prototype._finishDrawing = function(e)
{ var c = e.feature.getGeometry().getCoordinates()[0];
if (c.length > 3) this.getPolygon().getGeometry().appendLinearRing(new ol_geom_LinearRing(c));
this._feature = null;
this._select.getFeatures().clear();
};
/**
* Function that is called when a geometry's coordinates are updated.
* @param {Array<ol.coordinate>} coordinates
* @param {ol_geom_Polygon} geometry
* @return {ol_geom_Polygon}
* @private
*/
ol_interaction_DrawHole.prototype._geometryFn = function(coordinates, geometry)
{ var coord = coordinates[0].pop();
if (!this.getPolygon() || this.getPolygon().getGeometry().intersectsCoordinate(coord))
{ this.lastOKCoord = [coord[0],coord[1]];
}
coordinates[0].push([this.lastOKCoord[0],this.lastOKCoord[1]]);
if (geometry)
{ geometry.setCoordinates([coordinates[0].concat([coordinates[0][0]])]);
}
else
{ geometry = new ol_geom_Polygon(coordinates);
}
return geometry;
};
export default ol_interaction_DrawHole

View File

@ -0,0 +1,417 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_style_Style from 'ol/style/style'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Stroke from 'ol/style/stroke'
import ol_style_Fill from 'ol/style/fill'
import ol_Collection from 'ol/collection'
import ol_layer_Vector from 'ol/layer/vector'
import ol_source_Vector from 'ol/source/vector'
import ol_geom_Circle from 'ol/geom/circle'
import ol_geom_Polygon from 'ol/geom/polygon'
import ol_geom_Point from 'ol/geom/point'
/** Interaction rotate
* @constructor
* @extends {ol_interaction_Interaction}
* @fires drawstart, drawing, drawend, drawcancel
* @param {olx.interaction.TransformOptions} options
* @param {Array<ol.Layer>} source Destination source for the drawn features
* @param {ol.Collection<ol.Feature>} features Destination collection for the drawn features
* @param {ol.style.Style | Array.<ol.style.Style> | ol.style.StyleFunction | undefined} style style for the sketch
* @param {integer} sides number of sides, default 0 = circle
* @param { ol.events.ConditionType | undefined } squareCondition A function that takes an ol.MapBrowserEvent and returns a boolean to draw square features.
* @param { ol.events.ConditionType | undefined } centerCondition A function that takes an ol.MapBrowserEvent and returns a boolean to draw centered features.
* @param { bool } canRotate Allow rotation when centered + square, default: true
* @param { number } clickTolerance click tolerance on touch devices, default: 6
* @param { number } maxCircleCoordinates Maximum number of point on a circle, default: 100
*/
var ol_interaction_DrawRegular = function(options)
{ if (!options) options={};
var self = this;
this.squaredClickTolerance_ = options.clickTolerance ? options.clickTolerance * options.clickTolerance : 36;
this.maxCircleCoordinates_ = options.maxCircleCoordinates || 100;
// Collection of feature to transform
this.features_ = options.features;
// List of layers to transform
this.source_ = options.source;
// Square condition
this.squareFn_ = options.squareCondition;
// Centered condition
this.centeredFn_ = options.centerCondition;
// Allow rotation when centered + square
this.canRotate_ = (options.canRotate !== false);
// Number of sides (default=0: circle)
this.setSides(options.sides);
// Style
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var defaultStyle = [
new ol_style_Style({
stroke: new ol_style_Stroke({ color: white, width: width + 2 })
}),
new ol.style.Style({
image: new ol_style_Circle({
radius: width * 2,
fill: new ol_style_Fill({ color: blue }),
stroke: new ol_style_Stroke({ color: white, width: width / 2 })
}),
stroke: new ol_style_Stroke({ color: blue, width: width }),
fill: new ol_style_Fill({
color: [255, 255, 255, 0.5]
})
})
];
// Create a new overlay layer for the sketch
this.sketch_ = new ol_Collection();
this.overlayLayer_ = new ol_layer_Vector(
{ source: new ol_source_Vector({
features: this.sketch_,
useSpatialIndex: false
}),
name:'DrawRegular overlay',
displayInLayerSwitcher: false,
style: options.style || defaultStyle
});
ol_interaction_Interaction.call(this,
{
/*
handleDownEvent: this.handleDownEvent_,
handleMoveEvent: this.handleMoveEvent_,
handleUpEvent: this.handleUpEvent_,
*/
handleEvent: this.handleEvent_
});
};
ol.inherits(ol_interaction_DrawRegular, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_DrawRegular.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_);
ol_interaction_Interaction.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
};
/**
* Activate/deactivate the interaction
* @param {boolean}
* @api stable
*/
ol_interaction_DrawRegular.prototype.setActive = function(b)
{ this.reset();
ol_interaction_Interaction.prototype.setActive.call (this, b);
}
/**
* Reset the interaction
* @api stable
*/
ol_interaction_DrawRegular.prototype.reset = function()
{ this.overlayLayer_.getSource().clear();
this.started_ = false;
}
/**
* Set the number of sides.
* @param {int} number of sides.
* @api stable
*/
ol_interaction_DrawRegular.prototype.setSides = function (nb)
{ nb = parseInt(nb);
this.sides_ = nb>2 ? nb : 0;
}
/**
* Allow rotation when centered + square
* @param {bool}
* @api stable
*/
ol_interaction_DrawRegular.prototype.canRotate = function (b)
{ if (b===true || b===false) this.canRotate_ = b;
return this.canRotate_;
}
/**
* Get the number of sides.
* @return {int} number of sides.
* @api stable
*/
ol_interaction_DrawRegular.prototype.getSides = function ()
{ return this.sides_;
}
/** Default start angle array for each sides
*/
ol_interaction_DrawRegular.prototype.startAngle =
{ 'default':Math.PI/2,
3: -Math.PI/2,
4: Math.PI/4
};
/** Get geom of the current drawing
* @return {ol.geom.Polygon | ol.geom.Point}
*/
ol_interaction_DrawRegular.prototype.getGeom_ = function ()
{ this.overlayLayer_.getSource().clear();
if (!this.center_) return false;
var g;
if (this.coord_)
{ var center = this.center_;
var coord = this.coord_;
// Special case: circle
if (!this.sides_ && this.square_ && !this.centered_){
center = [(coord[0] + center[0])/2, (coord[1] + center[1])/2];
var d = [coord[0] - center[0], coord[1] - center[1]];
var r = Math.sqrt(d[0]*d[0]+d[1]*d[1]);
var circle = new ol.geom.Circle(center, r, 'XY');
// Optimize points on the circle
var centerPx = this.getMap().getPixelFromCoordinate(center);
var dmax = Math.max (100, Math.abs(centerPx[0]-this.coordPx_[0]), Math.abs(centerPx[1]-this.coordPx_[1]));
dmax = Math.min ( this.maxCircleCoordinates_, Math.round(dmax / 3 ));
return ol.geom.Polygon.fromCircle (circle, dmax, 0);
}
else {
var hasrotation = this.canRotate_ && this.centered_ && this.square_;
var d = [coord[0] - center[0], coord[1] - center[1]];
if (this.square_ && !hasrotation)
{ //var d = [coord[0] - center[0], coord[1] - center[1]];
var dm = Math.max (Math.abs(d[0]), Math.abs(d[1]));
coord[0] = center[0] + (d[0]>0 ? dm:-dm);
coord[1] = center[1] + (d[1]>0 ? dm:-dm);
}
var r = Math.sqrt(d[0]*d[0]+d[1]*d[1]);
if (r>0)
{ var circle = new ol_geom_Circle(center, r, 'XY');
var a;
if (hasrotation) a = Math.atan2(d[1], d[0]);
else a = this.startAngle[this.sides_] || this.startAngle['default'];
if (this.sides_) g = ol_geom_Polygon.fromCircle (circle, this.sides_, a);
else
{ // Optimize points on the circle
var centerPx = this.getMap().getPixelFromCoordinate(this.center_);
var dmax = Math.max (100, Math.abs(centerPx[0]-this.coordPx_[0]), Math.abs(centerPx[1]-this.coordPx_[1]));
dmax = Math.min ( this.maxCircleCoordinates_, Math.round(dmax / (this.centered_ ? 3:5) ));
g = ol.geom.Polygon.fromCircle (circle, dmax, 0);
}
if (hasrotation) return g;
// Scale polygon to fit extent
var ext = g.getExtent();
if (!this.centered_) center = this.center_;
else center = [ 2*this.center_[0]-this.coord_[0], 2*this.center_[1]-this.coord_[1] ];
var scx = (center[0] - coord[0]) / (ext[0] - ext[2]);
var scy = (center[1] - coord[1]) / (ext[1] - ext[3]);
if (this.square_)
{ var sc = Math.min(Math.abs(scx),Math.abs(scy));
scx = Math.sign(scx)*sc;
scy = Math.sign(scy)*sc;
}
var t = [ center[0] - ext[0]*scx, center[1] - ext[1]*scy ];
g.applyTransform(function(g1, g2, dim)
{ for (i=0; i<g1.length; i+=dim)
{ g2[i] = g1[i]*scx + t[0];
g2[i+1] = g1[i+1]*scy + t[1];
}
return g2;
});
return g;
}
}
}
// No geom => return a point
return new ol_geom_Point(this.center_);
};
/** Draw sketch
* @return {ol.Feature} The feature being drawn.
*/
ol_interaction_DrawRegular.prototype.drawSketch_ = function(evt)
{ this.overlayLayer_.getSource().clear();
if (evt)
{ this.square_ = this.squareFn_ ? this.squareFn_(evt) : evt.originalEvent.shiftKey;
this.centered_ = this.centeredFn_ ? this.centeredFn_(evt) : evt.originalEvent.metaKey || evt.originalEvent.ctrlKey;
var g = this.getGeom_();
if (g)
{ var f = this.feature_;
f.setGeometry (g);
this.overlayLayer_.getSource().addFeature(f);
if (this.coord_ && this.square_ && ((this.canRotate_ && this.centered_ && this.coord_) || (!this.sides_ && !this.centered_)))
{ this.overlayLayer_.getSource().addFeature(new ol.Feature(new ol.geom.LineString([this.center_,this.coord_])));
}
return f;
}
}
};
/** Draw sketch (Point)
*/
ol_interaction_DrawRegular.prototype.drawPoint_ = function(pt, noclear)
{ if (!noclear) this.overlayLayer_.getSource().clear();
this.overlayLayer_.getSource().addFeature(new ol.Feature(new ol.geom.Point(pt)));
};
/**
* @param {ol.MapBrowserEvent} evt Map browser event.
*/
ol_interaction_DrawRegular.prototype.handleEvent_ = function(evt)
{ switch (evt.type)
{ case "pointerdown": {
this.downPx_ = evt.pixel;
this.start_(evt);
}
break;
case "pointerup":
// Started and fisrt move
if (this.started_ && this.coord_)
{ var dx = this.downPx_[0] - evt.pixel[0];
var dy = this.downPx_[1] - evt.pixel[1];
if (dx*dx + dy*dy <= this.squaredClickTolerance_)
{ // The pointer has moved
if ( this.lastEvent == "pointermove" )
{ this.end_(evt);
}
// On touch device there is no move event : terminate = click on the same point
else
{ dx = this.upPx_[0] - evt.pixel[0];
dy = this.upPx_[1] - evt.pixel[1];
if ( dx*dx + dy*dy <= this.squaredClickTolerance_)
{ this.end_(evt);
}
else
{ this.handleMoveEvent_(evt);
this.drawPoint_(evt.coordinate,true);
}
}
}
}
this.upPx_ = evt.pixel;
break;
case "pointerdrag":
if (this.started_)
{ var centerPx = this.getMap().getPixelFromCoordinate(this.center_);
var dx = centerPx[0] - evt.pixel[0];
var dy = centerPx[1] - evt.pixel[1];
if (dx*dx + dy*dy <= this.squaredClickTolerance_)
{ this.reset();
}
}
break;
case "pointermove":
if (this.started_)
{ var dx = this.downPx_[0] - evt.pixel[0];
var dy = this.downPx_[1] - evt.pixel[1];
if (dx*dx + dy*dy > this.squaredClickTolerance_)
{ this.handleMoveEvent_(evt);
this.lastEvent = evt.type;
}
}
break;
default:
this.lastEvent = evt.type;
// Prevent zoom in on dblclick
if (this.started_ && evt.type==='dblclick')
{ //evt.stopPropagation();
return false;
}
break;
}
return true;
}
/** Stop drawing.
*/
ol_interaction_DrawRegular.prototype.finishDrawing = function()
{ if (this.started_ && this.coord_)
{ this.end_({ pixel: this.upPx_, coordinate: this.coord_});
}
};
/**
* @param {ol.MapBrowserEvent} evt Event.
*/
ol_interaction_DrawRegular.prototype.handleMoveEvent_ = function(evt)
{ if (this.started_)
{ this.coord_ = evt.coordinate;
this.coordPx_ = evt.pixel;
var f = this.drawSketch_(evt);
this.dispatchEvent({
type:'drawing',
feature: f,
pixel: evt.pixel,
startCoordinate: this.center_,
coordinate: evt.coordinate,
square: this.square_,
centered: this.centered_
});
}
else
{ this.drawPoint_(evt.coordinate);
}
};
/** Start an new draw
* @param {ol.MapBrowserEvent} evt Map browser event.
* @return {boolean} `false` to stop the drag sequence.
*/
ol_interaction_DrawRegular.prototype.start_ = function(evt)
{ if (!this.started_)
{ this.started_ = true;
this.center_ = evt.coordinate;
this.coord_ = null;
var f = this.feature_ = new ol.Feature();
this.drawSketch_(evt);
this.dispatchEvent({ type:'drawstart', feature: f, pixel: evt.pixel, coordinate: evt.coordinate });
}
else
{ this.coord_ = evt.coordinate;
}
};
/** End drawing
* @param {ol.MapBrowserEvent} evt Map browser event.
* @return {boolean} `false` to stop the drag sequence.
*/
ol_interaction_DrawRegular.prototype.end_ = function(evt)
{ this.coord_ = evt.coordinate;
this.started_ = false;
// Add new feature
if (this.coord_ && this.center_[0]!=this.coord_[0] && this.center_[1]!=this.coord_[1])
{ var f = this.feature_;
f.setGeometry(this.getGeom_());
if (this.source_) this.source_.addFeature(f);
else if (this.features_) this.features_.push(f);
this.dispatchEvent({ type:'drawend', feature: f, pixel: evt.pixel, coordinate: evt.coordinate, square: this.square_, centered: this.centered_ });
}
else
{ this.dispatchEvent({ type:'drawcancel', feature: null, pixel: evt.pixel, coordinate: evt.coordinate, square: this.square_, centered: this.centered_ });
}
this.center_ = this.coord_ = null;
this.drawSketch_();
};
export default ol_interaction_DrawRegular

View File

@ -0,0 +1,241 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_CenterTouch from './CenterTouch'
import ol_style_Style from 'ol/style/style'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Stroke from 'ol/style/stroke'
import ol_style_Fill from 'ol/style/fill'
import ol_Feature from 'ol/feature'
import ol_layer_Vector from 'ol/layer/vector'
import ol_source_Vector from 'ol/source/vector'
import ol_geom_LineString from 'ol/geom/linestring'
import ol_geom_Polygon from 'ol/geom/polygon'
import ol_geom_Point from 'ol/geom/point'
/** Interaction DrawTouch :
* @constructor
* @extends {ol_interaction_CenterTouch}
* @param {olx.interaction.DrawOptions} options
* - source {ol_source_Vector | undefined} Destination source for the drawn features.
* - type {ol.geom.GeometryType} Drawing type ('Point', 'LineString', 'Polygon') not ('MultiPoint', 'MultiLineString', 'MultiPolygon' or 'Circle'). Required.
* - tap {boolean} enable on tap, default true
* Inherited params
* - targetStyle {ol_style_Style|Array<ol_style_Style>} a style to draw the target point, default cross style
* - composite {string} composite operation : difference|multiply|xor|screen|overlay|darken|lighter|lighten|...
*/
var ol_interaction_DrawTouch = function(options)
{ var options = options||{};
var self = this;
options.handleEvent = function(e)
{ if (this.get("tap"))
{ switch (e.type)
{ case "singleclick":
this.addPoint();
break;
case "dblclick":
this.addPoint();
this.finishDrawing();
return false;
break;
default: break;
}
}
return true;
}
ol_interaction_CenterTouch.call(this, options);
this.typeGeom_ = options.type;
this.source_ = options.source;
this.set("tap", (options.tap!==false));
// Style
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var defaultStyle = [
new ol_style_Style({
stroke: new ol_style_Stroke({ color: white, width: width + 2 })
}),
new ol_style_Style({
image: new ol_style_Circle({
radius: width * 2,
fill: new ol_style_Fill({ color: blue }),
stroke: new ol_style_Stroke({ color: white, width: width / 2 })
}),
stroke: new ol_style_Stroke({ color: blue, width: width }),
fill: new ol_style_Fill({
color: [255, 255, 255, 0.5]
})
})
];
this.overlay_ = new ol_layer_Vector(
{ source: new ol_source_Vector({useSpatialIndex: false }),
style: defaultStyle
});
this.geom_ = [];
};
ol.inherits(ol_interaction_DrawTouch, ol_interaction_CenterTouch);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_DrawTouch.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().un("postcompose", this.drawSketchLink_, this);
}
ol_interaction_CenterTouch.prototype.setMap.call (this, map);
this.overlay_.setMap(map);
if (this.getMap())
{ this.getMap().on("postcompose", this.drawSketchLink_, this);
}
};
/** Start drawing and add the sketch feature to the target layer.
* The ol.interaction.Draw.EventType.DRAWSTART event is dispatched before inserting the feature.
*/
ol_interaction_DrawTouch.prototype.startDrawing = function()
{ this.geom_ = [];
this.addPoint();
};
/** Get geometry type
* @return {ol.geom.GeometryType}
*/
ol_interaction_DrawTouch.prototype.getGeometryType = function()
{ return this.typeGeom_;
};
/** Start drawing and add the sketch feature to the target layer.
* The ol.interaction.Draw.EventType.DRAWEND event is dispatched before inserting the feature.
*/
ol_interaction_DrawTouch.prototype.finishDrawing = function()
{ if (!this.getMap()) return;
var f;
switch (this.typeGeom_)
{ case "LineString":
if (this.geom_.length > 1) f = new ol.Feature(new ol_geom_LineString(this.geom_));
break;
case "Polygon":
// Close polygon
if (this.geom_[this.geom_.length-1] != this.geom_[0])
{ this.geom_.push(this.geom_[0]);
}
// Valid ?
if (this.geom_.length > 3)
{ f = new ol.Feature(new ol.geom.Polygon([ this.geom_ ]));
}
break;
default: break;
}
if (f) this.source_.addFeature (f);
// reset
this.geom_ = [];
this.drawSketch_();
}
/** Add a new Point to the drawing
*/
ol_interaction_DrawTouch.prototype.addPoint = function()
{ if (!this.getMap()) return;
this.geom_.push(this.getPosition());
switch (this.typeGeom_)
{ case "Point":
var f = new ol_Feature( new ol_geom_Point (this.geom_.pop()));
this.source_.addFeature(f);
break;
case "LineString":
case "Polygon":
this.drawSketch_();
break;
default: break;
}
}
/** Remove last point of the feature currently being drawn.
*/
ol_interaction_DrawTouch.prototype.removeLastPoint = function()
{ if (!this.getMap()) return;
this.geom_.pop();
this.drawSketch_();
}
/** Draw sketch
* @private
*/
ol_interaction_DrawTouch.prototype.drawSketch_ = function()
{ this.overlay_.getSource().clear();
if (this.geom_.length)
{ var f;
if (this.typeGeom_ == "Polygon")
{ f = new ol_Feature(new ol_geom_Polygon([this.geom_]));
this.overlay_.getSource().addFeature(f);
}
var geom = new ol_geom_LineString(this.geom_);
f = new ol_Feature(geom);
this.overlay_.getSource().addFeature(f);
f = new ol_Feature( new ol_geom_Point (this.geom_.slice(-1).pop()) );
this.overlay_.getSource().addFeature(f);
}
}
/** Draw contruction lines on postcompose
* @private
*/
ol_interaction_DrawTouch.prototype.drawSketchLink_ = function(e)
{ if (!this.getActive() || !this.getPosition()) return;
var ctx = e.context;
ctx.save();
var p, pt = this.getMap().getPixelFromCoordinate(this.getPosition());
var ratio = e.frameState.pixelRatio || 1;
ctx.scale(ratio,ratio);
ctx.strokeStyle = "rgba(0, 153, 255, 1)";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc (pt[0],pt[1], 5, 0, 2*Math.PI);
ctx.stroke();
if (this.geom_.length)
{ p = this.getMap().getPixelFromCoordinate(this.geom_[this.geom_.length-1]);
ctx.beginPath();
ctx.moveTo(p[0],p[1]);
ctx.lineTo(pt[0],pt[1]);
if (this.typeGeom_ == "Polygon")
{ p = this.getMap().getPixelFromCoordinate(this.geom_[0]);
ctx.lineTo(p[0],p[1]);
}
ctx.stroke();
}
ctx.restore();
}
/**
* Activate or deactivate the interaction.
* @param {boolean} active Active.
* @observable
* @api
*/
ol_interaction_DrawTouch.prototype.setActive = function(b)
{ ol_interaction_CenterTouch.prototype.setActive.call (this, b);
if (!b) this.geom_ = [];
this.drawSketch_();
}
export default ol_interaction_DrawTouch

View File

@ -0,0 +1,110 @@
import ol from 'ol'
import ol_interaction_DragAndDrop from 'ol/interaction/draganddrop'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_format_GPX from 'ol/format/gpx'
import ol_format_GeoJSON from 'ol/format/geojson'
import ol_format_IGC from 'ol/format/igc'
import ol_format_KML from 'ol/format/kml'
import ol_format_TopoJSON from 'ol/format/topojson'
/** Extend DragAndDrop choose drop zone + fires loadstart, loadend
* @require jQuery
*
* @constructor
* @extends {ol_interaction_DragAndDrop}
* @fires loadstart, loadend, addfeatures
* @param {ol.dropfile.options} flashlight options param
* - zone {string} selector for the drop zone, default document
* - projection {ol.projection} default projection of the map
* - formatConstructors {Array<function(new:ol.format.Feature)>|undefined} Format constructors, default [ ol.format.GPX, ol.format.GeoJSON, ol.format.IGC, ol.format.KML, ol.format.TopoJSON ]
* - accept {Array<string>|undefined} list of eccepted format, default ["gpx","json","geojson","igc","kml","topojson"]
*/
var ol_interaction_DropFile = function(options)
{ options = options||{};
ol_interaction_DragAndDrop.call(this, {});
var zone = options.zone || document;
$(zone).on('dragenter', this.onstop );
$(zone).on('dragover', this.onstop );
$(zone).on('dragleave', this.onstop );
// Options
this.formatConstructors_ = options.formatConstructors || [ ol_format_GPX, ol_format_GeoJSON, ol_format_IGC, ol_format_KML, ol_format_TopoJSON ];
this.projection_ = options.projection;
this.accept_ = options.accept || ["gpx","json","geojson","igc","kml","topojson"];
var self = this;
$(zone).on('drop', function(e){ return self.ondrop(e.originalEvent); });
};
ol.inherits(ol_interaction_DropFile, ol_interaction_DragAndDrop);
/** Set the map
*/
ol_interaction_DropFile.prototype.setMap = function(map)
{ ol_interaction_Interaction.prototype.setMap.call(this, map);
};
/** Do somthing when over
*/
ol_interaction_DropFile.prototype.onstop = function(e)
{ e.preventDefault();
e.stopPropagation();
return false;
}
/** Do somthing when over
*/
ol_interaction_DropFile.prototype.ondrop = function(e)
{ if (e.dataTransfer && e.dataTransfer.files.length)
{ var self = this;
e.preventDefault();
e.stopPropagation();
// fetch FileList object
var files = e.dataTransfer.files; // e.originalEvent.target.files ?
// process all File objects
var file;
var pat = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/;
for (var i=0; file=files[i]; i++)
{ var ex = file.name.match(pat)[0];
self.dispatchEvent({ type:'loadstart', file: file, filesize: file.size, filetype: file.type, fileextension: ex, projection: projection, target: self });
// Load file
features = [];
var reader = new FileReader();
var projection = this.projection_ || this.getMap().getView().getProjection();
var formatConstructors = this.formatConstructors_
if (!projection) return;
function tryReadFeatures (format, result, options)
{ try
{ return format.readFeatures(result, options);
} catch (e) {}
}
var theFile = file;
reader.onload = function(e)
{ var result = e.target.result;
var features = [];
var i, ii;
for (i = 0, ii = formatConstructors.length; i < ii; ++i)
{ var formatConstructor = formatConstructors[i];
var format = new formatConstructor();
features = tryReadFeatures(format, result, { featureProjection: projection });
if (features && features.length > 0)
{ self.dispatchEvent({ type:'addfeatures', features: features, file: theFile, projection: projection, target: self });
self.dispatchEvent({ type:'loadend', features: features, file: theFile, projection: projection, target: self });
return;
}
}
self.dispatchEvent({ type:'loadend', file: theFile, target: self });
};
reader.readAsText(file);
};
}
else {}
return false;
};
export default ol_interaction_DropFile

View File

@ -0,0 +1,118 @@
import ol from 'ol'
import ol_interaction_Pointer from 'ol/interaction/pointer'
import ol_color from 'ol/color'
/**
* @constructor
* @extends {ol_interaction_Pointer}
* @param {ol.flashlight.options} flashlight options param
* - color {ol.Color} light color, default transparent
* - fill {ol.Color} fill color, default rgba(0,0,0,0.8)
* - radius {number} radius of the flash
*/
var ol_interaction_Flashlight = function(options) {
ol_interaction_Pointer.call(this,
{ handleDownEvent: this.setPosition,
handleMoveEvent: this.setPosition
});
// Default options
options = options||{};
this.pos = false;
this.radius = (options.radius||100);
this.setColor(options);
};
ol.inherits(ol_interaction_Flashlight, ol_interaction_Pointer);
/** Set the map > start postcompose
*/
ol_interaction_Flashlight.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().un('postcompose', this.postcompose_, this);
this.getMap().render();
}
ol_interaction_Pointer.prototype.setMap.call(this, map);
if (map)
{ map.on('postcompose', this.postcompose_, this);
}
}
/** Set flashlight radius
* @param {integer} radius
*/
ol_interaction_Flashlight.prototype.setRadius = function(radius)
{ this.radius = radius
if (this.getMap()) this.getMap().renderSync();
}
/** Set flashlight color
* @param {ol.flashlight.options} flashlight options param
* - color {ol.Color} light color, default transparent
* - fill {ol.Color} fill color, default rgba(0,0,0,0.8)
*/
ol_interaction_Flashlight.prototype.setColor = function(options)
{ // Backcolor
var color = (options.fill ? options.fill : [0,0,0,0.8]);
var c = ol_color.asArray(color);
this.startColor = ol_color.asString(c);
// Halo color
var endColor;
if (options.color)
{ c = this.endColor = ol_color.asString(ol_color.asArray(options.color)||options.color);
}
else
{ c[3] = 0
this.endColor = ol_color.asString(c);
}
c[3] = 0.1;
this.midColor = ol_color.asString(c);
if (this.getMap()) this.getMap().renderSync();
}
/** Set position of the flashlight
* @param {ol.Pixel|ol.MapBrowserEvent}
*/
ol_interaction_Flashlight.prototype.setPosition = function(e)
{ if (e.pixel) this.pos = e.pixel;
else this.pos = e;
if (this.getMap())
{ this.getMap().renderSync();
}
}
/** Postcompose function
*/
ol_interaction_Flashlight.prototype.postcompose_ = function(e)
{ var ctx = e.context;
var ratio = e.frameState.pixelRatio;
var w = ctx.canvas.width;
var h = ctx.canvas.height;
ctx.save();
ctx.scale(ratio,ratio);
if (!this.pos)
{ ctx.fillStyle = this.startColor;
ctx.fillRect( 0,0,w,h );
}
else
{ var d = Math.max(w, h);
// reveal wherever we drag
var radGrd = ctx.createRadialGradient( this.pos[0], this.pos[1], w*this.radius/d, this.pos[0], this.pos[1], h*this.radius/d );
radGrd.addColorStop( 0, this.startColor );
radGrd.addColorStop( 0.8, this.midColor );
radGrd.addColorStop( 1, this.endColor );
ctx.fillStyle = radGrd;
ctx.fillRect( this.pos[0] - d, this.pos[1] - d, 2*d, 2*d );
}
ctx.restore();
};
export default ol_interaction_Flashlight

View File

@ -0,0 +1,338 @@
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_Geolocation from 'ol/geolocation'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Stroke from 'ol/style/stroke'
import ol_geom_Point from 'ol/geom/point'
import ol_style_Style from 'ol/style/style'
import ol_style_RegularShape from 'ol/style/regularshape'
import ol_style_Fill from 'ol/style/fill'
import ol_layer_Vector from 'ol/layer/vector'
import ol_source_Vector from 'ol/source/vector'
import ol_Feature from 'ol/feature'
import ol_interaction_Pointer from 'ol/interaction/pointer'
import ol_extent from 'ol/extent'
/** Interaction to draw on the current geolocation
* It combines a draw with a ol_Geolocation
* @constructor
* @extends {ol_interaction_Interaction}
* @fires drawstart, drawend, drawing, tracking, follow
* @param {olx.interaction.GeolocationDrawOption} options
* @param { ol.Collection.<ol.Feature> | undefined } option.features Destination collection for the drawn features.
* @param { ol.source.Vector | undefined } options.source Destination source for the drawn features.
* @param {ol.geom.GeometryType} options.type Drawing type ('Point', 'LineString', 'Polygon'). Required.
* @param {Number | undefined} options.minAccuracy minimum accuracy underneath a new point will be register (if no condition), default 20
* @param {function | undefined} options.condition a function that take a ol_Geolocation object and return a boolean to indicate whether location should be handled or not, default return true if accuraty < minAccuraty
* @param {Object} options.attributes a list of attributes to register as Point properties: {accuracy:true,accuracyGeometry:true,heading:true,speed:true}, default none.
* @param {Number} options.tolerance tolerance to add a new point (in projection unit), use ol.geom.LineString.simplify() method, default 5
* @param {Number} options.zoom zoom for tracking, default 16
* @param {boolean|auto|position|visible} options.followTrack true if you want the interaction to follow the track on the map, default true
* @param { ol.style.Style | Array.<ol.style.Style> | ol.StyleFunction | undefined } options.style Style for sketch features.
*/
var ol_interaction_GeolocationDraw = function(options)
{ if (!options) options={};
var self = this;
// Geolocation
var geoloc = this.geolocation = new ol_Geolocation(/** @type {olx.GeolocationOptions} */
({ projection: "EPSG:4326",
trackingOptions:
{ maximumAge: 10000,
enableHighAccuracy: true,
timeout: 600000
}
}));
this.geolocation.on('change', this.draw_, this);
// Current path
this.path_ = [];
this.lastPosition_ = false;
// Default style
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var circle = new ol_style_Circle(
{ radius: width * 2,
fill: new ol_style_Fill({ color: blue }),
stroke: new ol_style_Stroke({ color: white, width: width / 2 })
});
var style =
[ new ol_style_Style(
{ stroke: new ol_style_Stroke({ color: white, width: width + 2 })
}),
new ol_style_Style(
{ stroke: new ol_style_Stroke({ color: blue, width: width }),
fill: new ol_style_Fill({
color: [255, 255, 255, 0.5]
})
})
];
var triangle = new ol_style_RegularShape(
{ radius: width * 3.5,
points: 3,
rotation: 0,
fill: new ol_style_Fill({ color: blue }),
stroke: new ol_style_Stroke({ color: white, width: width / 2 })
});
// stretch the symbol
var c = triangle.getImage();
var ctx = c.getContext("2d");
var c2 = document.createElement('canvas');
c2.width = c2.height = c.width;
c2.getContext("2d").drawImage(c, 0,0);
ctx.clearRect(0,0,c.width,c.height);
ctx.drawImage(c2, 0,0, c.width, c.height, width, 0, c.width-2*width, c.height);
var defaultStyle = function(f)
{ if (f.get('heading')===undefined)
{ style[1].setImage(circle);
}
else
{ style[1].setImage(triangle);
triangle.setRotation( f.get('heading') || 0);
}
return style;
}
// Style for the accuracy geometry
this.locStyle =
{ error: new ol_style_Style({ fill: new ol_style_Fill({ color: [255, 0, 0, 0.2] }) }),
warn: new ol_style_Style({ fill: new ol_style_Fill({ color: [255, 192, 0, 0.2] }) }),
ok: new ol_style_Style({ fill: new ol_style_Fill({ color: [0, 255, 0, 0.2] }) }),
};
// Create a new overlay layer for the sketch
this.overlayLayer_ = new ol_layer_Vector(
{ source: new ol_source_Vector(),
name:'GeolocationDraw overlay',
style: options.style || defaultStyle
});
this.sketch_ = [new ol_Feature(), new ol_Feature(), new ol_Feature()];
this.overlayLayer_.getSource().addFeatures(this.sketch_);
this.features_ = options.features;
this.source_ = options.source;
this.condition_ = options.condition || function(loc) { return loc.getAccuracy() < this.get("minAccuracy") };
// Prevent interaction when tracking
ol_interaction_Interaction.call(this,
{ handleEvent: function()
{ return (!this.get('followTrack') || this.get('followTrack')=='auto');// || !geoloc.getTracking());
}
});
this.set("type", options.type||"LineString");
this.set("attributes", options.attributes||{});
this.set("minAccuracy", options.minAccuracy||20);
this.set("tolerance", options.tolerance||5);
this.set("zoom", options.zoom);
this.setFollowTrack (options.followTrack===undefined ? true : options.followTrack);
this.setActive(false);
};
ol.inherits(ol_interaction_GeolocationDraw, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_GeolocationDraw.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_);
ol_interaction_Pointer.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
if (map) this.geolocation.setProjection(map.getView().getProjection());
};
/** Activate or deactivate the interaction.
* @param {boolean} active
*/
ol_interaction_GeolocationDraw.prototype.setActive = function(active)
{ ol_interaction_Interaction.prototype.setActive.call(this, active);
this.overlayLayer_.setVisible(active);
if (this.getMap())
{ this.geolocation.setTracking(active);
this.getMap().renderSync();
}
this.pause(!active);
if (active)
{ // Start drawing
this.reset();
this.dispatchEvent({ type:'drawstart', feature: this.sketch_[1]});
}
else
{ var f = this.sketch_[1].clone();
if (f.getGeometry())
{ if (this.features_) this.features_.push(f);
if (this.source_) this.source_.addFeature(f);
this.dispatchEvent({ type:'drawend', feature: f});
}
}
};
/** Reset drawing
*/
ol_interaction_GeolocationDraw.prototype.reset = function()
{ this.sketch_[1].setGeometry();
this.path_ = [];
this.lastPosition_ = false;
};
/** Start tracking = setActive(true)
*/
ol_interaction_GeolocationDraw.prototype.start = function()
{ this.setActive(true);
};
/** Stop tracking = setActive(false)
*/
ol_interaction_GeolocationDraw.prototype.stop = function()
{ this.setActive(false);
};
/** Pause drawing
* @param {boolean} b
*/
ol_interaction_GeolocationDraw.prototype.pause = function(b)
{ this.pause_ = b!==false;
};
/** Enable following the track on the map
* @param {boolean|auto|position|visible} follow,
* false: don't follow,
* true: follow (position+zoom),
* 'position': follow only position,
* 'auto': start following until user move the map,
* 'visible': center when position gets out of the visible extent
*/
ol_interaction_GeolocationDraw.prototype.setFollowTrack = function(follow)
{ this.set('followTrack', follow);
var map = this.getMap();
// Center if wanted
if (follow !== false && !this.lastPosition_ && map)
{ var pos = this.path_[this.path_.length-1];
if (pos)
{ map.getView().animate({
center: pos,
zoom: (follow!="position" ? this.get("zoom") : undefined)
})
}
}
this.lastPosition_ = false;
this.dispatchEvent({ type:'follow', following: follow!==false });
};
/** Add a new point to the current path
* @private
*/
ol_interaction_GeolocationDraw.prototype.draw_ = function(active)
{ var map = this.getMap();
if (!map) return;
// Current location
var loc = this.geolocation;
var accu = loc.getAccuracy();
var pos = loc.getPosition();
pos.push (Math.round((loc.getAltitude()||0)*100)/100);
pos.push (Math.round((new Date()).getTime()/1000));
var p = loc.getAccuracyGeometry();
// Center on point
// console.log(this.get('followTrack'))
switch (this.get('followTrack'))
{ // Follow center + zoom
case true:
// modify zoom
if (this.get('followTrack') == true)
{ map.getView().setZoom( this.get("zoom") || 16 );
if (!ol_extent.containsExtent(map.getView().calculateExtent(map.getSize()), p.getExtent()))
{ map.getView().fit(p.getExtent());
}
}
// Follow position
case 'position':
// modify center
map.getView().setCenter( pos );
break;
// Keep on following
case 'auto':
if (this.lastPosition_)
{ var center = map.getView().getCenter();
// console.log(center,this.lastPosition_)
if (center[0]!=this.lastPosition_[0] || center[1]!=this.lastPosition_[1])
{ //this.dispatchEvent({ type:'follow', following: false });
this.setFollowTrack (false);
}
else
{ map.getView().setCenter( pos );
this.lastPosition_ = pos;
}
}
else
{ map.getView().setCenter( pos );
if (this.get("zoom")) map.getView().setZoom( this.get("zoom") );
this.lastPosition_ = pos;
}
break;
// Force to stay on the map
case 'visible':
if (!ol_extent.containsCoordinate(map.getView().calculateExtent(map.getSize()), pos))
{ map.getView().setCenter (pos);
}
break;
// Don't follow
default: break;
}
// Draw occuracy
var f = this.sketch_[0];
f.setGeometry(p);
if (accu < this.get("minAccuracy")/2) f.setStyle(this.locStyle.ok);
else if (accu < this.get("minAccuracy")) f.setStyle(this.locStyle.warn);
else f.setStyle(this.locStyle.error);
var geo;
if (!this.pause_ && this.condition_.call(this, loc))
{ f = this.sketch_[1];
this.path_.push(pos);
switch (this.get("type"))
{ case "Point":
this.path_ = [pos];
f.setGeometry(new ol_geom_Point(pos, 'XYZM'));
var attr = this.get('attributes');
if (attr.heading) f.set("heading",loc.getHeading());
if (attr.accuracy) f.set("accuracy",loc.getAccuracy());
if (attr.altitudeAccuracy) f.set("altitudeAccuracy",loc.getAltitudeAccuracy());
if (attr.speed) f.set("speed",loc.getSpeed());
break;
case "LineString":
if (this.path_.length>1)
{ geo = new ol.geom.LineString(this.path_, 'XYZM');
geo.simplify (this.get("tolerance"));
f.setGeometry(geo);
}
else f.setGeometry();
break;
case "Polygon":
if (this.path_.length>2)
{ geo = new ol.geom.Polygon([this.path_], 'XYZM');
geo.simplify (this.get("tolerance"));
f.setGeometry(geo);
}
else f.setGeometry();
break;
}
this.dispatchEvent({ type:'drawing', feature: this.sketch_[1], geolocation: loc });
}
this.sketch_[2].setGeometry(new ol_geom_Point(pos));
this.sketch_[2].set("heading",loc.getHeading());
// Drawing
this.dispatchEvent({ type:'tracking', feature: this.sketch_[1], geolocation: loc });
};
export default ol_interaction_GeolocationDraw

127
build/interaction/Hover.js Normal file
View File

@ -0,0 +1,127 @@
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
/** Interaction hover do to something when hovering a feature
* @constructor
* @extends {ol_interaction_Interaction}
* @fires hover, enter, leave
* @param {olx.interaction.HoverOptions}
* - cursor { string | undefined } css cursor propertie or a function that gets a feature, default: none
* - featureFilter {function | undefined} filter a function with two arguments, the feature and the layer of the feature. Return true to select the feature
* - layerFilter {function | undefined} filter a function with one argument, the layer to test. Return true to test the layer
* - handleEvent { function | undefined } Method called by the map to notify the interaction that a browser event was dispatched to the map. The function may return false to prevent the propagation of the event to other interactions in the map's interactions chain.
*/
var ol_interaction_Hover = function(options)
{ if (!options) options={};
var self = this;
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ if (e.type=="pointermove") { self.handleMove_(e); };
if (options.handleEvent) return options.handleEvent(e);
return true;
}
});
this.setFeatureFilter (options.featureFilter);
this.setLayerFilter (options.layerFilter);
this.setCursor (options.cursor);
};
ol.inherits(ol_interaction_Hover, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_Hover.prototype.setMap = function(map)
{ if (this.previousCursor_!==undefined && this.getMap())
{ this.getMap().getTargetElement().style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
ol_interaction_Interaction.prototype.setMap.call (this, map);
};
/**
* Set cursor on hover
* @param { string } cursor css cursor propertie or a function that gets a feature, default: none
* @api stable
*/
ol_interaction_Hover.prototype.setCursor = function(cursor)
{ if (!cursor && this.previousCursor_!==undefined && this.getMap())
{ this.getMap().getTargetElement().style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
this.cursor_ = cursor;
};
/** Feature filter to get only one feature
* @param {function} filter a function with two arguments, the feature and the layer of the feature. Return true to select the feature
*/
ol_interaction_Hover.prototype.setFeatureFilter = function(filter)
{ if (typeof (filter) == 'function') this.featureFilter_ = filter;
else this.featureFilter_ = function(){ return true; };
};
/** Feature filter to get only one feature
* @param {function} filter a function with one argument, the layer to test. Return true to test the layer
*/
ol_interaction_Hover.prototype.setLayerFilter = function(filter)
{ if (typeof (filter) == 'function') this.layerFilter_ = filter;
else this.layerFilter_ = function(){ return true; };
};
/** Get features whenmove
* @param {ol.event} e "move" event
*/
ol_interaction_Hover.prototype.handleMove_ = function(e)
{ var map = this.getMap();
if (map)
{ //var b = map.hasFeatureAtPixel(e.pixel);
var feature, layer;
var self = this;
var b = map.forEachFeatureAtPixel(e.pixel,
function(f, l)
{ if (self.layerFilter_.call(null, l)
&& self.featureFilter_.call(null,f,l))
{ feature = f;
layer = l;
return true;
}
else
{ feature = layer = null;
return false;
}
});
if (b) this.dispatchEvent({ type:"hover", feature:feature, layer:layer, coordinate:e.coordinate, pixel: e.pixel, map: e.map, dragging:e.dragging });
if (this.feature_===feature && this.layer_===layer)
{
}
else
{ this.feature_ = feature;
this.layer_ = layer;
if (feature) this.dispatchEvent({ type:"enter", feature:feature, layer:layer, coordinate:e.coordinate, pixel: e.pixel, map: e.map, dragging:e.dragging });
else this.dispatchEvent({ type:"leave", coordinate:e.coordinate, pixel: e.pixel, map: e.map, dragging:e.dragging });
}
if (this.cursor_)
{ var style = map.getTargetElement().style;
if (b)
{ if (style.cursor != this.cursor_)
{ this.previousCursor_ = style.cursor;
style.cursor = this.cursor_;
}
}
else if (this.previousCursor_ !== undefined)
{ style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
}
}
};
export default ol_interaction_Hover

View File

@ -0,0 +1,58 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
/** Interaction to handle longtouch events
* @constructor
* @extends {ol_interaction_Interaction}
* @param {olx.interaction.LongTouchOptions}
* @param {function | undefined} options.handleLongTouchEvent Function handling "longtouch" events, it will receive a mapBrowserEvent.
* @param {interger | undefined} options.delay The delay for a long touch in ms, default is 1000
*/
var ol_interaction_LongTouch = function(options)
{ if (!options) options = {};
this.delay_ = options.delay || 1000;
var ltouch = options.handleLongTouchEvent || function(){};
var _timeout = null;
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ if (this.getActive())
{ switch (e.type)
{ case 'pointerdown':
if (_timeout) clearTimeout(_timeout);
_timeout = setTimeout (function()
{ e.type = "longtouch";
ltouch(e)
}, this.delay_);
break;
/* case 'pointermove': */
case 'pointerdrag':
case 'pointerup':
if (_timeout)
{ clearTimeout(_timeout);
_timeout = null;
}
break;
default: break;;
}
}
else
{ if (_timeout)
{ clearTimeout(_timeout);
_timeout = null;
}
}
return true;
}
});
};
ol.inherits(ol_interaction_LongTouch, ol_interaction_Interaction);
export default ol_interaction_LongTouch

197
build/interaction/Ripple.js Normal file
View File

@ -0,0 +1,197 @@
/*
Water ripple effect.
Original code (Java) by Neil Wallis
@link http://www.neilwallis.com/java/water.html
Original code (JS) by Sergey Chikuyonok (serge.che@gmail.com)
@link http://chikuyonok.ru
@link http://media.chikuyonok.ru/ripple/
Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
@link https://github.com/Viglino
*/
import ol from 'ol'
import ol_interaction_Pointer from 'ol/interaction/pointer'
import ol_Observable from 'ol/observable'
/**
* @constructor
* @extends {ol_interaction_Pointer}
* @param {ol.flashlight.options} flashlight options param
* - color {ol.Color} light color, default transparent
* - fill {ol.Color} fill color, default rgba(0,0,0,0.8)
* - radius {number} radius of the flash
*/
var ol_interaction_Ripple = function(options)
{
ol_interaction_Pointer.call(this,
{ handleDownEvent: this.rainDrop,
handleMoveEvent: this.rainDrop
});
// Default options
options = options||{};
this.riprad = options.radius || 3;
this.ripplemap = [];
this.last_map = [];
// Generate random ripples
this.interval = options.interval;
this.rains (this.interval);
};
ol.inherits(ol_interaction_Ripple, ol_interaction_Pointer);
/** Set the map > start postcompose
*/
ol_interaction_Ripple.prototype.setMap = function(map)
{ if (this.oncompose)
{ ol_Observable.unByKey(oncompose);
if (this.getMap()) this.getMap().render();
}
ol_interaction_Pointer.prototype.setMap.call(this, map);
if (map)
{ this.oncompose = map.on('postcompose', this.postcompose_, this);
}
}
/** Generate random rain drop
* @param {integer} interval
*/
ol_interaction_Ripple.prototype.rains = function(interval)
{ if (this.onrain) clearTimeout (this.onrain);
var self = this;
vdelay = (typeof(interval)=="number" ? interval : 1000)/2;
delay = 3*vdelay/2;
var rnd = Math.random;
function rain()
{ if (self.width) self.rainDrop([rnd() * self.width, rnd() * self.height]);
self.onrain = setTimeout (rain, rnd()*vdelay + delay);
};
// Start raining
if (delay) rain();
}
/** Disturb water at specified point
* @param {ol.Pixel|ol.MapBrowserEvent}
*/
ol_interaction_Ripple.prototype.rainDrop = function(e)
{ if (!this.width) return;
var dx,dy;
if (e.pixel)
{ dx = e.pixel[0]*this.ratio;
dy = e.pixel[1]*this.ratio;
}
else
{ dx = e[0]*this.ratio;
dy = e[1]*this.ratio;
}
dx <<= 0;
dy <<= 0;
for (var j = dy - this.riprad*this.ratio; j < dy + this.riprad*this.ratio; j++)
{ for (var k = dx - this.riprad*this.ratio; k < dx + this.riprad*this.ratio; k++)
{ this.ripplemap[this.oldind + (j * this.width) + k] += 128;
}
}
}
/** Postcompose function
*/
ol_interaction_Ripple.prototype.postcompose_ = function(e)
{ var ctx = e.context;
var canvas = ctx.canvas;
// Initialize when canvas is ready / modified
if (this.width != canvas.width || this.height != canvas.height)
{ this.width = canvas.width;
this.height = canvas.height;
this.ratio = e.frameState.pixelRatio;
this.half_width = this.width >> 1;
this.half_height = this.height >> 1;
this.size = this.width * (this.height + 2) * 2;
this.oldind = this.width;
this.newind = this.width * (this.height + 3);
for (var i = 0; i < this.size; i++) {
this.last_map[i] = this.ripplemap[i] = 0;
}
}
this.texture = ctx.getImageData(0, 0, this.width, this.height);
this.ripple = ctx.getImageData(0, 0, this.width, this.height);
// Run animation
var a, b, data, cur_pixel, new_pixel;
var t = this.oldind; this.oldind = this.newind; this.newind = t;
var i = 0;
var _rd = this.ripple.data,
_td = this.texture.data;
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
var _newind = this.newind + i,
_mapind = this.oldind + i;
data = (
this.ripplemap[_mapind - this.width] +
this.ripplemap[_mapind + this.width] +
this.ripplemap[_mapind - 1] +
this.ripplemap[_mapind + 1]) >> 1;
data -= this.ripplemap[_newind];
data -= data >> 5;
this.ripplemap[_newind] = data;
//where data=0 then still, where data>0 then wave
data = 1024 - data;
if (this.last_map[i] != data)
{ this.last_map[i] = data;
//offsets
a = (((x - this.half_width) * data / 1024) << 0) + this.half_width;
b = (((y - this.half_height) * data / 1024) << 0) + this.half_height;
//bounds check
if (a >= this.width) a = this.width - 1;
if (a < 0) a = 0;
if (b >= this.height) b = this.height - 1;
if (b < 0) b = 0;
new_pixel = (a + (b * this.width)) * 4;
cur_pixel = i * 4;
/**/
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
/*/
// only in blue pixels
if (_td[new_pixel + 2]>_td[new_pixel + 1]
&& _td[new_pixel + 2]>_td[new_pixel])
{
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
}
else this.ripplemap[_newind] = 0;
/**/
}
++i;
}
}
ctx.putImageData(this.ripple, 0, 0);
// tell OL3 to continue postcompose animation
this.getMap().render();
};
export default ol_interaction_Ripple

View File

@ -0,0 +1,291 @@
/*
Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (http://www.cecill.info/).
ol.interaction.SelectCluster is an interaction for selecting vector features in a cluster.
*/
import ol from 'ol'
import ol_Map from 'ol/map'
import ol_Collection from 'ol/collection'
import ol_layer_Vector from 'ol/layer/vector'
import ol_source_Vector from 'ol/source/vector'
import ol_interaction_Select from 'ol/interaction/select'
import ol_Feature from 'ol/feature'
import ol_geom_LineString from 'ol/geom/linestring'
import ol_Observable from 'ol/observable'
import ol_easing from 'ol/easing'
import ol_geom_Point from 'ol/geom/point'
/**
* @classdesc
* Interaction for selecting vector features in a cluster.
* It can be used as an ol.interaction.Select.
* When clicking on a cluster, it springs apart to reveal the features in the cluster.
* Revealed features are selectable and you can pick the one you meant.
* Revealed features are themselves a cluster with an attribute features that contain the original feature.
*
* @constructor
* @extends {ol.interaction.Select}
* @param {olx.interaction.SelectOptions=} options SelectOptions.
* @param {ol.style} options.featureStyle used to style the revealed features as options.style is used by the Select interaction.
* @param {boolean} options.selectCluster false if you don't want to get cluster selected
* @param {Number} options.PointRadius to calculate distance between the features
* @param {bool} options.spiral means you want the feature to be placed on a spiral (or a circle)
* @param {Number} options.circleMaxObject number of object that can be place on a circle
* @param {Number} options.maxObjects number of object that can be drawn, other are hidden
* @param {bool} options.animation if the cluster will animate when features spread out, default is false
* @param {Number} options.animationDuration animation duration in ms, default is 500ms
* @fires ol.interaction.SelectEvent
* @api stable
*/
var ol_interaction_SelectCluster = function(options)
{ options = options || {};
this.pointRadius = options.pointRadius || 12;
this.circleMaxObjects = options.circleMaxObjects || 10;
this.maxObjects = options.maxObjects || 60;
this.spiral = (options.spiral !== false);
this.animate = options.animate;
this.animationDuration = options.animationDuration || 500;
this.selectCluster_ = (options.selectCluster !== false);
// Create a new overlay layer for
var overlay = this.overlayLayer_ = new ol_layer_Vector(
{ source: new ol_source_Vector({
features: new ol_Collection(),
useSpatialIndex: true
}),
name:'Cluster overlay',
updateWhileAnimating: true,
updateWhileInteracting: true,
displayInLayerSwitcher: false,
style: options.featureStyle
});
// Add the overlay to selection
if (options.layers)
{ if (typeof(options.layers) == "function")
{ var fn = options.layers;
options.layers = function(layer)
{ return (layer===overlay || fn(layer));
};
}
else if (options.layers.push)
{ options.layers.push(this.overlayLayer_);
}
}
// Don't select links
if (options.filter)
{ var fn = options.filter;
options.filter = function(f,l)
{ //if (l===overlay && f.get("selectclusterlink")) return false;
if (!l && f.get("selectclusterlink")) return false;
else return fn(f,l);
};
}
else options.filter = function(f,l)
{ //if (l===overlay && f.get("selectclusterlink")) return false;
if (!l && f.get("selectclusterlink")) return false;
else return true;
};
this.filter_ = options.filter;
ol_interaction_Select.call(this, options);
this.on("select", this.selectCluster, this);
};
ol.inherits(ol_interaction_SelectCluster, ol_interaction_Select);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_SelectCluster.prototype.setMap = function(map)
{ if (this.getMap())
{ if (this.getMap().getView())
{ this.getMap().getView().un('change:resolution', this.clear, this);
}
this.getMap().removeLayer(this.overlayLayer_);
}
ol_interaction_Select.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
// map.addLayer(this.overlayLayer_);
if (map && map.getView())
{ map.getView().on('change:resolution', this.clear, this);
}
};
/**
* Clear the selection, close the cluster and remove revealed features
* @api stable
*/
ol_interaction_SelectCluster.prototype.clear = function()
{ this.getFeatures().clear();
this.overlayLayer_.getSource().clear();
};
/**
* Get the layer for the revealed features
* @api stable
*/
ol_interaction_SelectCluster.prototype.getLayer = function()
{ return this.overlayLayer_;
};
/**
* Select a cluster
* @param {ol.Feature} a cluster feature ie. a feature with a 'features' attribute.
* @api stable
*/
ol_interaction_SelectCluster.prototype.selectCluster = function (e)
{ // Nothing selected
if (!e.selected.length)
{ this.clear();
return;
}
// Get selection
var feature = e.selected[0];
// It's one of ours
if (feature.get('selectclusterfeature')) return;
// Clic out of the cluster => close it
var source = this.overlayLayer_.getSource();
source.clear();
var cluster = feature.get('features');
// Not a cluster (or just one feature)
if (!cluster || cluster.length==1) return;
// Remove cluster from selection
if (!this.selectCluster_) this.getFeatures().clear();
var center = feature.getGeometry().getCoordinates();
// Pixel size in map unit
var pix = this.getMap().getView().getResolution();
var r = pix * this.pointRadius * (0.5 + cluster.length / 4);
// Draw on a circle
if (!this.spiral || cluster.length <= this.circleMaxObjects)
{ var max = Math.min(cluster.length, this.circleMaxObjects);
for (i=0; i<max; i++)
{ var a = 2*Math.PI*i/max;
if (max==2 || max == 4) a += Math.PI/4;
var p = [ center[0]+r*Math.sin(a), center[1]+r*Math.cos(a) ];
var cf = new ol_Feature({ 'selectclusterfeature':true, 'features':[cluster[i]], geometry: new ol_geom_Point(p) });
cf.setStyle(cluster[i].getStyle());
source.addFeature(cf);
var lk = new ol_Feature({ 'selectclusterlink':true, geometry: new ol_geom_LineString([center,p]) });
source.addFeature(lk);
};
}
// Draw on a spiral
else
{ // Start angle
var a = 0;
var r;
var d = 2*this.pointRadius;
var features = new Array();
var links = new Array();
var max = Math.min (this.maxObjects, cluster.length);
// Feature on a spiral
for (i=0; i<max; i++)
{ // New radius => increase d in one turn
r = d/2 + d*a/(2*Math.PI);
// Angle
a = a + (d+0.1)/r;
var dx = pix*r*Math.sin(a)
var dy = pix*r*Math.cos(a)
var p = [ center[0]+dx, center[1]+dy ];
var cf = new ol_Feature({ 'selectclusterfeature':true, 'features':[cluster[i]], geometry: new ol_geom_Point(p) });
cf.setStyle(cluster[i].getStyle());
source.addFeature(cf);
var lk = new ol_Feature({ 'selectclusterlink':true, geometry: new ol_geom_LineString([center,p]) });
source.addFeature(lk);
}
}
if (this.animate) this.animateCluster_(center);
};
/**
* Animate the cluster and spread out the features
* @param {ol.Coordinates} the center of the cluster
*/
ol_interaction_SelectCluster.prototype.animateCluster_ = function(center)
{ // Stop animation (if one is running)
if (this.listenerKey_)
{ this.overlayLayer_.setVisible(true);
ol_Observable.unByKey(this.listenerKey_);
}
// Features to animate
var features = this.overlayLayer_.getSource().getFeatures();
if (!features.length) return;
this.overlayLayer_.setVisible(false);
var style = this.overlayLayer_.getStyle();
var stylefn = (typeof(style) == 'function') ? style : style.length ? function(){ return style; } : function(){ return [style]; } ;
var duration = this.animationDuration || 500;
var start = new Date().getTime();
// Animate function
function animate(event)
{ var vectorContext = event.vectorContext;
// Retina device
var ratio = event.frameState.pixelRatio;
var res = event.target.getView().getResolution();
var e = ol_easing.easeOut((event.frameState.time - start) / duration);
for (var i=0, feature; feature = features[i]; i++) if (feature.get('features'))
{ var pt = feature.getGeometry().getCoordinates();
pt[0] = center[0] + e * (pt[0]-center[0]);
pt[1] = center[1] + e * (pt[1]-center[1]);
var geo = new ol_geom_Point(pt);
// Image style
var st = stylefn(feature, res);
for (var s=0; s<st.length; s++)
{ var sc;
// OL < v4.3 : setImageStyle doesn't check retina
var imgs = ol_Map.prototype.getFeaturesAtPixel ? false : st[s].getImage();
if (imgs)
{ sc = imgs.getScale();
imgs.setScale(ratio);
}
// OL3 > v3.14
if (vectorContext.setStyle)
{ vectorContext.setStyle(st[s]);
vectorContext.drawGeometry(geo);
}
// older version
else
{ vectorContext.setImageStyle(imgs);
vectorContext.drawPointGeometry(geo);
}
if (imgs) imgs.setScale(sc);
}
}
// Stop animation and restore cluster visibility
if (e > 1.0)
{ ol_Observable.unByKey(this.listenerKey_);
this.overlayLayer_.setVisible(true);
this.overlayLayer_.changed();
return;
}
// tell OL3 to continue postcompose animation
event.frameState.animate = true;
}
// Start a new postcompose animation
this.listenerKey_ = this.getMap().on('postcompose', animate, this);
//select.getMap().renderSync();
};
export default ol_interaction_SelectCluster

View File

@ -0,0 +1,256 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_style_Style from 'ol/style/style'
import ol_style_Stroke from 'ol/style/stroke'
import ol_extent from 'ol/extent'
import ol_source_Vector from 'ol/source/vector'
import ol_layer_Vector from 'ol/layer/vector'
import ol_Collection from 'ol/collection'
import ol_layer_Image from 'ol/layer/image'
import ol_Feature from 'ol/feature'
import ol_geom_LineString from 'ol/geom/linestring'
/** Interaction to snap to guidelines
* @constructor
* @extends {ol_interaction_Interaction}
* @param {olx.interaction.SnapGuidesOptions}
* - pixelTolerance {number | undefined} distance (in px) to snap to a guideline, default 10 px
* - style {ol_style_Style | Array<ol_style_Style> | undefined} Style for the sektch features.
*/
var ol_interaction_SnapGuides = function(options)
{ if (!options) options = {};
// Intersect 2 guides
function getIntersectionPoint (d1, d2)
{ var d1x = d1[1][0] - d1[0][0];
var d1y = d1[1][1] - d1[0][1];
var d2x = d2[1][0] - d2[0][0];
var d2y = d2[1][1] - d2[0][1];
var det = d1x * d2y - d1y * d2x;
if (det != 0)
{ var k = (d1x * d1[0][1] - d1x * d2[0][1] - d1y * d1[0][0] + d1y * d2[0][0]) / det;
return [d2[0][0] + k*d2x, d2[0][1] + k*d2y];
}
else return false;
}
function dist2D (p1,p2)
{ var dx = p1[0]-p2[0];
var dy = p1[1]-p2[1];
return Math.sqrt(dx*dx+dy*dy);
}
// Snap distance (in px)
this.snapDistance_ = options.pixelTolerance || 10;
// Default style
var sketchStyle =
[ new ol_style_Style({
stroke: new ol_style_Stroke(
{ color: '#ffcc33',
lineDash: [8,5],
width: 1.25
})
})
];
// Custom style
if (options.style) sketchStyle = options.style instanceof Array ? options.style : [options.style];
// Create a new overlay for the sketch
this.overlaySource_ = new ol_source_Vector(
{ features: new ol_Collection(),
useSpatialIndex: false
});
/* Speed up with a ImageVector layer (deprecated)
this.overlayLayer_ = new ol_layer_Image(
{ source: new ol_source_ImageVector(
{ source: this.overlaySource_,
style: function(f)
{ return sketchStyle;
}
}),
name:'Snap overlay',
displayInLayerSwitcher: false
});
*/
this.overlayLayer_ = new ol_layer_Vector(
{ source: this.overlaySource_,
style: function(f)
{ return sketchStyle;
},
name:'Snap overlay',
displayInLayerSwitcher: false
});
// Use snap interaction
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ if (this.getActive())
{ var features = this.overlaySource_.getFeatures();
var prev = null;
var p = null;
var res = e.frameState.viewState.resolution;
for (var i=0, f; f = features[i]; i++)
{ var c = f.getGeometry().getClosestPoint(e.coordinate);
if ( dist2D(c, e.coordinate) / res < this.snapDistance_)
{ // Intersection on 2 lines
if (prev)
{ var c2 = getIntersectionPoint(prev.getGeometry().getCoordinates(), f.getGeometry().getCoordinates());
if (c2)
{ if (dist2D(c2, e.coordinate) / res < this.snapDistance_)
{ p = c2;
}
}
}
else
{ p = c;
}
prev = f;
}
}
if (p) e.coordinate = p;
}
return true;
}
});
};
ol.inherits(ol_interaction_SnapGuides, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_SnapGuides.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_);
ol_interaction_Interaction.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
if (map) this.projExtent_ = map.getView().getProjection().getExtent();
};
/** Activate or deactivate the interaction.
* @param {boolean} active
*/
ol_interaction_SnapGuides.prototype.setActive = function(active)
{ this.overlayLayer_.setVisible(active);
ol_interaction_Interaction.prototype.setActive.call (this, active);
}
/** Clear previous added guidelines
* @param {Array<ol.Feature> | undefined} features a list of feature to remove, default remove all feature
*/
ol_interaction_SnapGuides.prototype.clearGuides = function(features)
{ if (!features) this.overlaySource_.clear();
else
{ for (var i=0, f; f=features[i]; i++)
{ this.overlaySource_.removeFeature(f);
}
}
}
/** Get guidelines
* @return {ol.Collection} guidelines features
*/
ol_interaction_SnapGuides.prototype.getGuides = function(features)
{ return this.overlaySource_.getFeaturesCollection();
}
/** Add a new guide to snap to
* @param {Array<ol.coordinate>} v the direction vector
* @return {ol.Feature} feature guide
*/
ol_interaction_SnapGuides.prototype.addGuide = function(v, ortho)
{ if (v)
{ var map = this.getMap();
// Limit extent
var extent = map.getView().calculateExtent(map.getSize());
extent = ol_extent.buffer(extent, Math.max (1e5+1, (extent[2]-extent[0])*100));
extent = ol_extent.getIntersection(extent, this.projExtent_);
var dx = v[0][0] - v[1][0];
var dy = v[0][1] - v[1][1];
var d = 1 / Math.sqrt(dx*dx+dy*dy);
var p, g = [];
var p0, p1;
for (var i= 0; i<1e8; i+=1e5)
{ if (ortho) p = [ v[0][0] + dy*d*i, v[0][1] - dx*d*i];
else p = [ v[0][0] + dx*d*i, v[0][1] + dy*d*i];
if (ol_extent.containsCoordinate(extent, p)) g.push(p);
else break;
}
var f0 = new ol_Feature(new ol_geom_LineString(g));
var g=[];
for (var i= 0; i>-1e8; i-=1e5)
{ if (ortho) p = [ v[0][0] + dy*d*i, v[0][1] - dx*d*i];
else p = [ v[0][0] + dx*d*i, v[0][1] + dy*d*i];
if (ol_extent.containsCoordinate(extent, p)) g.push(p);
else break;
}
var f1 = new ol_Feature(new ol_geom_LineString(g));
this.overlaySource_.addFeature(f0);
this.overlaySource_.addFeature(f1);
return [f0, f1];
}
};
/** Add a new orthogonal guide to snap to
* @param {Array<ol.coordinate>} v the direction vector
* @return {ol.Feature} feature guide
*/
ol_interaction_SnapGuides.prototype.addOrthoGuide = function(v)
{ return this.addGuide(v, true);
};
/** Listen to draw event to add orthogonal guidelines on the first and last point.
* @param {_ol_interaction_Draw_} drawi a draw interaction to listen to
* @api
*/
ol_interaction_SnapGuides.prototype.setDrawInteraction = function(drawi)
{ var self = this;
// Number of points currently drawing
var nb = 0;
// Current guidelines
var features = [];
function setGuides(e)
{ var coord = [];
var s = 2;
switch (e.target.getType())
{ case 'LineString':
coord = e.target.getCoordinates();
s = 2;
break;
case 'Polygon':
coord = e.target.getCoordinates()[0];
s = 3;
break;
default: break;
}
var l = coord.length;
if (l != nb && l > s)
{ self.clearGuides(features);
features = self.addOrthoGuide([coord[l-s],coord[l-s-1]]);
features = features.concat(self.addGuide([coord[0],coord[1]]));
features = features.concat(self.addOrthoGuide([coord[0],coord[1]]));
nb = l;
}
};
// New drawing
drawi.on ("drawstart", function(e)
{ // When geom is changing add a new orthogonal direction
e.feature.getGeometry().on("change", setGuides);
});
// end drawing, clear directions
drawi.on ("drawend", function(e)
{ self.clearGuides(features);
e.feature.getGeometry().un("change", setGuides);
nb = 0;
features = [];
});
};
export default ol_interaction_SnapGuides

260
build/interaction/Split.js Normal file
View File

@ -0,0 +1,260 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_style_Style from 'ol/style/style'
import ol_style_Stroke from 'ol/style/stroke'
import ol_source_Vector from 'ol/source/vector'
import ol_style_Fill from 'ol/style/fill'
import ol_style_Circle from 'ol/style/circle'
import ol_layer_Vector from 'ol/layer/vector'
import ol_coordinate from 'ol/coordinate'
import ol_geom_Point from 'ol/geom/point'
import ol_Feature from 'ol/feature'
import ol_geom_LineString from 'ol/geom/linestring'
/** Interaction split interaction for splitting feature geometry
* @constructor
* @extends {ol_interaction_Interaction}
* @fires beforesplit, aftersplit
* @param {olx.interaction.SplitOptions}
* - source {ol.source.Vector|Array{ol.source.Vector}} a list of source to split (configured with useSpatialIndex set to true)
* - features {ol.Collection.<ol.Feature>} collection of feature to split
* - snapDistance {integer} distance (in px) to snap to an object, default 25px
* - cursor {string|undefined} cursor name to display when hovering an objet
* - filter {function|undefined} a filter that takes a feature and return true if it can be clipped, default always split.
* - featureStyle {ol_style_Style | Array<ol_style_Style> | false | undefined} Style for the selected features, choose false if you don't want feature selection. By default the default edit style is used.
* - sketchStyle {ol_style_Style | Array<ol_style_Style> | undefined} Style for the sektch features.
* - tolerance {function|undefined} Distance between the calculated intersection and a vertex on the source geometry below which the existing vertex will be used for the split. Default is 1e-10.
*/
var ol_interaction_Split = function(options)
{ if (!options) options = {};
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ switch (e.type)
{ case "singleclick":
return this.handleDownEvent(e);
case "pointermove":
return this.handleMoveEvent(e);
default:
return true;
}
return true;
}
});
// Snap distance (in px)
this.snapDistance_ = options.snapDistance || 25;
// Split tolerance between the calculated intersection and the geometry
this.tolerance_ = options.tolerance || 1e-10;
// Cursor
this.cursor_ = options.cursor;
// List of source to split
this.sources_ = options.sources ? (options.sources instanceof Array) ? options.sources:[options.sources] : [];
if (options.features)
{ this.sources_.push (new ol_source_Vector({ features: features }));
}
// Get all features candidate
this.filterSplit_ = options.filter || function(){ return true; };
// Default style
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var fill = new ol_style_Fill({ color: 'rgba(255,255,255,0.4)' });
var stroke = new ol_style_Stroke({
color: '#3399CC',
width: 1.25
});
var sketchStyle =
[ new ol_style_Style({
image: new ol_style_Circle({
fill: fill,
stroke: stroke,
radius: 5
}),
fill: fill,
stroke: stroke
})
];
var featureStyle =
[ new ol_style_Style({
stroke: new ol_style_Stroke({
color: white,
width: width + 2
})
}),
new ol_style_Style({
image: new ol_style_Circle({
radius: 2*width,
fill: new ol_style_Fill({
color: blue
}),
stroke: new ol_style_Stroke({
color: white,
width: width/2
})
}),
stroke: new ol_style_Stroke({
color: blue,
width: width
})
}),
];
// Custom style
if (options.sketchStyle) sketchStyle = options.sketchStyle instanceof Array ? options.sketchStyle : [options.sketchStyle];
if (options.featureStyle) featureStyle = options.featureStyle instanceof Array ? options.featureStyle : [options.featureStyle];
// Create a new overlay for the sketch
this.overlayLayer_ = new ol_layer_Vector(
{ source: new ol_source_Vector({
useSpatialIndex: false
}),
name:'Split overlay',
displayInLayerSwitcher: false,
style: function(f)
{ if (f._sketch_) return sketchStyle;
else return featureStyle;
}
});
};
ol.inherits(ol_interaction_Split, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol.Map} map Map.
* @api stable
*/
ol_interaction_Split.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_);
ol_interaction_Interaction.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
};
/** Get closest feature at pixel
* @param {ol.Pixel}
* @return {ol.feature}
* @private
*/
ol_interaction_Split.prototype.getClosestFeature = function(e)
{ var f, c, g, d = this.snapDistance_+1;
for (var i=0; i<this.sources_.length; i++)
{ var source = this.sources_[i];
f = source.getClosestFeatureToCoordinate(e.coordinate);
if (f.getGeometry().splitAt, this.tolerance_)
{ c = f.getGeometry().getClosestPoint(e.coordinate);
g = new ol_geom_LineString([e.coordinate,c]);
d = g.getLength() / e.frameState.viewState.resolution;
break;
}
}
if (d > this.snapDistance_) return false;
else
{ // Snap to node
var coord = this.getNearestCoord (c, f.getGeometry().getCoordinates());
var p = this.getMap().getPixelFromCoordinate(coord);
if (ol_coordinate.dist2d(e.pixel, p) < this.snapDistance_)
{ c = coord;
}
//
return { source:source, feature:f, coord: c, link: g };
}
}
/** Get nearest coordinate in a list
* @param {ol.coordinate} pt the point to find nearest
* @param {Array<ol.coordinate>} coords list of coordinates
* @return {ol.coordinate} the nearest coordinate in the list
*/
ol_interaction_Split.prototype.getNearestCoord = function(pt, coords)
{ var d, dm=Number.MAX_VALUE, p0;
for (var i=0; i < coords.length; i++)
{ d = ol_coordinate.dist2d (pt, coords[i]);
if (d < dm)
{ dm = d;
p0 = coords[i];
}
}
return p0;
};
/**
* @param {ol.MapBrowserEvent} evt Map browser event.
* @return {boolean} `true` to start the drag sequence.
*/
ol_interaction_Split.prototype.handleDownEvent = function(evt)
{ // Something to split ?
var current = this.getClosestFeature(evt);
if (current)
{ var self = this;
self.overlayLayer_.getSource().clear();
var split = current.feature.getGeometry().splitAt(current.coord, this.tolerance_);
if (split.length > 1)
{ var tosplit = [];
for (var i=0; i<split.length; i++)
{ var f = current.feature.clone();
f.setGeometry(split[i]);
tosplit.push(f);
}
self.dispatchEvent({ type:'beforesplit', original: current.feature, features: tosplit });
current.source.dispatchEvent({ type:'beforesplit', original: current.feature, features: tosplit });
current.source.removeFeature(current.feature);
for (var i=0; i<tosplit.length; i++)
{ current.source.addFeature(tosplit[i]);
}
self.dispatchEvent({ type:'aftersplit', original: current.feature, features: tosplit });
current.source.dispatchEvent({ type:'aftersplit', original: current.feature, features: tosplit });
}
}
return false;
};
/**
* @param {ol.MapBrowserEvent} evt Event.
*/
ol_interaction_Split.prototype.handleMoveEvent = function(e)
{ var map = e.map;
this.overlayLayer_.getSource().clear();
var current = this.getClosestFeature(e);
if (current && this.filterSplit_(current.feature))
{ var coord, p, l;
// Draw sketch
this.overlayLayer_.getSource().addFeature(current.feature);
p = new ol_Feature(new ol_geom_Point(current.coord));
p._sketch_ = true;
this.overlayLayer_.getSource().addFeature(p);
//
l = new ol_Feature(new ol_geom_LineString([e.coordinate,current.coord]));
l._sketch_ = true;
this.overlayLayer_.getSource().addFeature(l);
}
var element = map.getTargetElement();
if (this.cursor_)
{ if (current)
{ if (element.style.cursor != this.cursor_)
{ this.previousCursor_ = element.style.cursor;
element.style.cursor = this.cursor_;
}
}
else if (this.previousCursor_ !== undefined)
{ element.style.cursor = this.previousCursor_;
this.previousCursor_ = undefined;
}
}
};
export default ol_interaction_Split

View File

@ -0,0 +1,254 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_source_Vector from 'ol/source/vector'
import ol_Collection from 'ol/collection'
import ol_extent from 'ol/extent'
/** Interaction splitter: acts as a split feature agent while editing vector features (LineString).
* @constructor
* @extends {ol_interaction_Interaction}
* @fires beforesplit, aftersplit
* @param {olx.interaction.SplitOptions}
* - source {ol.source.Vector|Array{ol.source.Vector}} The target source (or array of source) with features to be split (configured with useSpatialIndex set to true)
* - triggerSource {ol.source.Vector} Any newly created or modified features from this source will be used to split features on the target source. If none is provided the target source is used instead.
* - features {ol_Collection.<ol.Feature>} A collection of feature to be split (replace source target).
* - triggerFeatures {ol_Collection.<ol.Feature>} Any newly created or modified features from this collection will be used to split features on the target source (replace triggerSource).
* - filter {function|undefined} a filter that takes a feature and return true if the feature is eligible for splitting, default always split.
* - tolerance {function|undefined} Distance between the calculated intersection and a vertex on the source geometry below which the existing vertex will be used for the split. Default is 1e-10.
* @todo verify auto intersection on features that split.
*/
var ol_interaction_Splitter = function(options)
{ if (!options) options = {};
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ // Hack to get only one changeFeature when draging with ol.interaction.Modify on.
if (e.type != "pointermove" && e.type != "pointerdrag")
{ if (this.lastEvent_)
{ this.splitSource(this.lastEvent_.feature);
this.lastEvent_ = null;
}
this.moving_ = false;
}
else this.moving_ = true;
return true;
},
});
// Features added / remove
this.added_ = [];
this.removed_ = [];
// Source to split
if (options.features)
{ this.source_ = new ol_source_Vector({ features: options.features });
}
else
{ this.source_ = options.source ? options.source : new ol_source_Vector({ features: new ol_Collection() });
}
var trigger = this.triggerSource;
if (options.triggerFeatures)
{ trigger = new ol_source_Vector({ features: options.triggerFeatures });
}
if (trigger)
{ trigger.on("addfeature", this.onAddFeature, this);
trigger.on("changefeature", this.onChangeFeature, this);
trigger.on("removefeature", this.onRemoveFeature, this);
}
else
{ this.source_.on("addfeature", this.onAddFeature, this);
this.source_.on("changefeature", this.onChangeFeature, this);
this.source_.on("removefeature", this.onRemoveFeature, this);
}
// Split tolerance between the calculated intersection and the geometry
this.tolerance_ = options.tolerance || 1e-10;
// Get all features candidate
this.filterSplit_ = options.filter || function(){ return true; };
};
ol.inherits(ol_interaction_Splitter, ol_interaction_Interaction);
/** Calculate intersection on 2 segs
* @param {Array<_ol_coordinate_>} s1 first seg to intersect (2 points)
* @param {Array<_ol_coordinate_>} s2 second seg to intersect (2 points)
* @return { boolean | _ol_coordinate_ } intersection point or false no intersection
*/
ol_interaction_Splitter.prototype.intersectSegs = function(s1,s2)
{ var tol = this.tolerance_;
// Solve
var x12 = s1[0][0] - s1[1][0];
var x34 = s2[0][0] - s2[1][0];
var y12 = s1[0][1] - s1[1][1];
var y34 = s2[0][1] - s2[1][1];
var det = x12 * y34 - y12 * x34;
// No intersection
if (Math.abs(det) < tol)
{ return false;
}
else
{ // Outside segement
var r1 = ((s1[0][0] - s2[1][0])*y34 - (s1[0][1] - s2[1][1])*x34) / det;
if (Math.abs(r1)<tol) return s1[0];
if (Math.abs(1-r1)<tol) return s1[1];
if (r1<0 || r1>1) return false;
var r2 = ((s1[0][1] - s2[1][1])*x12 - (s1[0][0] - s2[1][0])*y12) / det;
if (Math.abs(r2)<tol) return s2[1];
if (Math.abs(1-r2)<tol) return s2[0];
if (r2<0 || r2>1) return false;
// Intersection
var a = s1[0][0] * s1[1][1] - s1[0][1] * s1[1][0];
var b = s2[0][0] * s2[1][1] - s2[0][1] * s2[1][0];
var p = [(a * x34 - b * x12) / det, (a * y34 - b * y12) / det];
// Test start / end
/*
console.log("r1: "+r1)
console.log("r2: "+r2)
console.log ("s10: "+(_ol_coordinate_.dist2d(p,s1[0])<tol)) ;
console.log ("s11: "+(_ol_coordinate_.dist2d(p,s1[1])<tol)) ;
console.log ("s20: "+(_ol_coordinate_.dist2d(p,s2[0])<tol)) ;
console.log ("s21: "+(_ol_coordinate_.dist2d(p,s2[1])<tol)) ;
*/
return p;
}
};
/** Split the source using a feature
* @param {ol.Feature} feature The feature to use to split.
*/
ol_interaction_Splitter.prototype.splitSource = function(feature)
{ // Allready perform a split
if (this.splitting) return;
var self = this;
var i, k, f2;
// Start splitting
this.source_.dispatchEvent({ type:'beforesplit', feaure: feature, source: this.source_ });
this.splitting = true;
this.added_ = [];
this.removed_ = [];
var c = feature.getGeometry().getCoordinates();
var seg, split = [];
function intersect (f)
{ if (f !== feature)
{ var c2 = f.getGeometry().getCoordinates();
for (var j=0; j<c2.length-1; j++)
{ var p = this.intersectSegs (seg, [c2[j],c2[j+1]]);
if (p)
{ split.push(p);
g = f.getGeometry().splitAt(p, this.tolerance_);
if (g && g.length>1)
{ found = f;
return true;
}
}
}
}
return false;
}
// Split existing features
for (i=0; i<c.length-1; i++)
{ seg = [c[i],c[i+1]];
var extent = ol_extent.buffer(ol_extent.boundingExtent(seg), this.tolerance_ /*0.01*/ );
var g;
while (true)
{ var found = false;
this.source_.forEachFeatureIntersectingExtent(extent, intersect, this);
// Split feature
if (found)
{ var f = found;
this.source_.removeFeature(f);
for (k=0; k<g.length; k++)
{ f2 = f.clone();
f2.setGeometry(g[k]);
this.source_.addFeature(f2);
}
}
else break;
}
}
// Auto intersect
for (i=0; i<c.length-2; i++)
{ for (var j=i+1; j<c.length-1; j++)
{ var p = this.intersectSegs ([c[i],c[i+1]], [c[j],c[j+1]]);
if (p && p!=c[i+1])
{ split.push(p);
}
}
}
// Split original
var splitOriginal = false;
if (split.length)
{ var result = feature.getGeometry().splitAt(split, this.tolerance_);
if (result.length>1)
{ for (k=0; k<result.length; k++)
{ f2 = feature.clone();
f2.setGeometry(result[k]);
this.source_.addFeature(f2);
}
splitOriginal = true;
}
}
// If the interaction is inserted after modify interaction, the objet is not consistant
// > wait end of other interactions
setTimeout (function()
{ if (splitOriginal) self.source_.removeFeature(feature);
self.source_.dispatchEvent({ type:'aftersplit', featureAdded: self.added_, featureRemoved: self.removed_, source: this.source_ });
// Finish
self.splitting = false;
},0);
};
/** New feature source is added
*/
ol_interaction_Splitter.prototype.onAddFeature = function(e)
{ this.splitSource(e.feature);
if (this.splitting)
{ this.added_.push(e.feature);
}
/*
if (this.splitting) return;
var self = this;
setTimeout (function() { self.splitSource(e.feature); }, 0);
*/
};
/** Feature source is removed > count features added/removed
*/
ol_interaction_Splitter.prototype.onRemoveFeature = function(e)
{ if (this.splitting)
{ var n = this.added_.indexOf(e.feature);
if (n==-1)
{ this.removed_.push(e.feature);
}
else
{ this.added_.splice(n,1);
}
}
};
/** Feature source is changing
*/
ol_interaction_Splitter.prototype.onChangeFeature = function(e)
{ if (this.moving_)
{ this.lastEvent_ = e;
}
else this.splitSource(e.feature);
};
export default ol_interaction_Splitter

View File

@ -0,0 +1,27 @@
.ol-target-overlay .ol-target
{ border: 1px solid transparent;
box-shadow: 0 0 1px 1px #fff;
display: block;
height: 20px;
width: 0;
}
.ol-target-overlay .ol-target:after,
.ol-target-overlay .ol-target:before
{ content:"";
border: 1px solid #369;
box-shadow: 0 0 1px 1px #fff;
display: block;
width: 20px;
height: 0;
position:absolute;
top:10px;
left:-10px;
}
.ol-target-overlay .ol-target:after
{ box-shadow: none;
height: 20px;
width: 0;
top:0px;
left:0px;
}

View File

@ -0,0 +1,151 @@
/* Copyright (c) 2016 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/
import ol from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_Map from 'ol/map'
import ol_events from 'ol/events'
import ol_events_EventType from 'ol/events/eventtype'
import ol_Overlay from 'ol/overlay'
/** Interaction synchronize
* @constructor
* @extends {ol_interaction_Interaction}
* @param {olx.interaction.SynchronizeOptions}
* - maps {Array<ol.Map>} An array of maps to synchronize with the map of the interaction
*/
var ol_interaction_Synchronize = function(options)
{ if (!options) options={};
var self = this;
ol_interaction_Interaction.call(this,
{ handleEvent: function(e)
{ if (e.type=="pointermove") { self.handleMove_(e); }
return true;
}
});
this.maps = options.maps;
};
ol.inherits(ol_interaction_Synchronize, ol_interaction_Interaction);
/**
* Remove the interaction from its current map, if any, and attach it to a new
* map, if any. Pass `null` to just remove the interaction from the current map.
* @param {ol_Map} map Map.
* @api stable
*/
ol_interaction_Synchronize.prototype.setMap = function(map)
{
if (this.getMap())
{
this.getMap().getView().un('change:center', this.syncMaps, this);
this.getMap().getView().un('change:rotation', this.syncMaps, this);
this.getMap().getView().un('change:resolution', this.syncMaps, this);
ol_events.unlisten(this.getMap().getViewport(), ol_events_EventType.MOUSEOUT, this.handleMouseOut_, this);
}
ol_interaction_Interaction.prototype.setMap.call (this, map);
if (map)
{ this.getMap().getView().on('change:center', this.syncMaps, this);
this.getMap().getView().on('change:rotation', this.syncMaps, this);
this.getMap().getView().on('change:resolution', this.syncMaps, this);
var me = this;
$(this.getMap().getTargetElement()).mouseout(function() {
for (var i=0; i<me.maps.length; i++)
{ me.maps[i].hideTarget();
}
me.getMap().hideTarget();
});
this.syncMaps();
}
};
/** Synchronize the maps
*/
ol_interaction_Synchronize.prototype.syncMaps = function(e)
{ var map = this.getMap();
if (!e) e = { type:'all' };
if (map)
{ for (var i=0; i<this.maps.length; i++)
{ switch (e.type)
{ case 'change:rotation':
if (this.maps[i].getView().getRotation() != map.getView().getRotation())
this.maps[i].getView().setRotation(map.getView().getRotation());
break;
case 'change:center':
if (this.maps[i].getView().getCenter() != map.getView().getCenter())
this.maps[i].getView().setCenter(map.getView().getCenter());
break;
case 'change:resolution':
if (this.maps[i].getView().getResolution() != map.getView().getResolution())
{ /* old version prior to 1.19.1
this.maps[i].beforeRender ( ol.animation.zoom(
{ duration: 250,
resolution: this.maps[i].getView().getResolution()
}));
*/
this.maps[i].getView().setResolution(map.getView().getResolution());
}
break;
default:
this.maps[i].getView().setRotation(map.getView().getRotation());
this.maps[i].getView().setCenter(map.getView().getCenter());
this.maps[i].getView().setResolution(map.getView().getResolution());
break;
}
}
}
};
/** Cursor move > tells other maps to show the cursor
* @param {ol.event} e "move" event
*/
ol_interaction_Synchronize.prototype.handleMove_ = function(e)
{ for (var i=0; i<this.maps.length; i++)
{ this.maps[i].showTarget(e.coordinate);
}
this.getMap().showTarget();
};
/** Cursor out of map > tells other maps to hide the cursor
* @param {event} e "mouseOut" event
*/
ol_interaction_Synchronize.prototype.handleMouseOut_ = function(e, scope)
{ for (var i=0; i<scope.maps.length; i++)
{
scope.maps[i].targetOverlay_.setPosition(undefined);
}
};
/** Show a target overlay at coord
* @param {ol.coordinate} coord
*/
ol_Map.prototype.showTarget = function(coord)
{ if (!this.targetOverlay_)
{ var elt = $("<div>").addClass("ol-target");
this.targetOverlay_ = new ol_Overlay({ element: elt.get(0) });
this.targetOverlay_.setPositioning('center-center');
this.addOverlay(this.targetOverlay_);
elt.parent().addClass("ol-target-overlay");
// hack to render targetOverlay before positioning it
this.targetOverlay_.setPosition([0,0]);
}
this.targetOverlay_.setPosition(coord);
};
/** Hide the target overlay
*/
ol_Map.prototype.hideTarget = function()
{
this.removeOverlay(this.targetOverlay_);
this.targetOverlay_ = undefined;
};
export default ol_interaction_Synchronize

View File

@ -0,0 +1,97 @@
/*
Tinker Bell effect on maps.
Copyright (c) 2015 Jean-Marc VIGLINO,
released under the CeCILL-B license (French BSD license)
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
@link https://github.com/Viglino
*/
import ol from 'ol'
import ol_interaction_Pointer from 'ol/interaction/pointer'
import ol_color from 'ol/color'
/**
* @constructor
* @extends {ol_interaction_Pointer}
* @param {ol_interaction_TinkerBell.options} options flashlight param
* - color {ol_color} color of the sparkles
*/
var ol_interaction_TinkerBell = function(options)
{ options = options || {};
ol_interaction_Pointer.call(this,
{ handleDownEvent: this.onMove,
handleMoveEvent: this.onMove
});
this.set('color', options.color ? ol_color.asString(options.color) : "#fff");
this.sparkle = [0,0];
this.sparkles = [];
this.lastSparkle = this.time = new Date();
var self = this;
this.out_ = function() { self.isout_=true; };
this.isout_ = true;
};
ol.inherits(ol_interaction_TinkerBell, ol_interaction_Pointer);
/** Set the map > start postcompose
*/
ol_interaction_TinkerBell.prototype.setMap = function(map)
{ if (this.getMap())
{ this.getMap().un('postcompose', this.postcompose_, this);
map.getViewport().removeEventListener('mouseout', this.out_, false);
this.getMap().render();
}
ol_interaction_Pointer.prototype.setMap.call(this, map);
if (map)
{ map.on('postcompose', this.postcompose_, this);
map.on('mouseout', this.onMove, this);
map.getViewport().addEventListener('mouseout', this.out_, false);
}
};
ol_interaction_TinkerBell.prototype.onMove = function(e)
{ this.sparkle = e.pixel;
this.isout_ = false;
this.getMap().render();
};
/** Postcompose function
*/
ol_interaction_TinkerBell.prototype.postcompose_ = function(e)
{ var delta = 15;
var ctx = e.context;
var canvas = ctx.canvas;
var dt = e.frameState.time - this.time;
this.time = e.frameState.time;
if (e.frameState.time-this.lastSparkle > 30 && !this.isout_)
{ this.lastSparkle = e.frameState.time;
this.sparkles.push({ p:[this.sparkle[0]+Math.random()*delta-delta/2, this.sparkle[1]+Math.random()*delta], o:1 });
}
ctx.save();
ctx.scale(e.frameState.pixelRatio,e.frameState.pixelRatio);
ctx.fillStyle = this.get("color");
for (var i=this.sparkles.length-1, p; p=this.sparkles[i]; i--)
{ if (p.o < 0.2)
{ this.sparkles.splice(0,i+1);
break;
}
ctx.globalAlpha = p.o;
ctx.beginPath();
ctx.arc (p.p[0], p.p[1], 2.2, 0, 2 * Math.PI, false);
ctx.fill();
p.o *= 0.98;
p.p[0] += (Math.random()-0.5);
p.p[1] += dt*(1+Math.random())/30;
};
ctx.restore();
// tell OL3 to continue postcompose animation
if (this.sparkles.length) this.getMap().render();
};
export default ol_interaction_TinkerBell

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