diff --git a/.gitignore b/.gitignore
index b739568994de..ecc983f8e4ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@
/contribs/gmf/build/
/contribs/gmf/examples/https.js
/openlayers_src/
+/dist/
diff --git a/Makefile b/Makefile
index c78010e24fc2..1d6edd76dd7c 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ NGEO_EXAMPLES_JS_FILES := $(NGEO_EXAMPLES_HTML_FILES:.html=.js)
GMF_PARTIALS_FILES := $(shell find contribs/gmf/src/ -name *.html)
GMF_JS_FILES := $(shell find contribs/gmf/src/ -type f -name '*.js')
-GMF_ALL_SRC_FILES := $(shell find contribs/gmf/src/ -type f) $(shell find contribs/gmf/src/cursors/ -type f) $(NGEO_ALL_SRC_FILES)
+GMF_ALL_SRC_FILES := $(shell find contribs/gmf/src/ -type f) $(NGEO_ALL_SRC_FILES)
GMF_TEST_JS_FILES := $(shell find contribs/gmf/test/ -type f -name '*.js')
GMF_EXAMPLES_HTML_FILES := $(shell ls -1 contribs/gmf/examples/*.html)
GMF_EXAMPLES_JS_FILES := $(GMF_EXAMPLES_HTML_FILES:.html=.js)
diff --git a/buildtools/generate-xml-from-tokens.js b/buildtools/generate-xml-from-tokens.js
new file mode 100644
index 000000000000..4dcd0f62ad95
--- /dev/null
+++ b/buildtools/generate-xml-from-tokens.js
@@ -0,0 +1,98 @@
+// Initially get from https://github.com/tildeio/simple-html-tokenizer/blob/v0.1.1/lib/simple-html-tokenizer/generator.js
+
+const escape = (function() {
+ const test = /[&<>"'`]/;
+ const replace = /[&<>"'`]/g;
+ const map = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ '\'': ''',
+ '`': '`'
+ };
+ function escapeChar(char) {
+ return map[char];
+ }
+ return function escape(string) {
+ if (!test.test(string)) {
+ return string;
+ }
+ return string.replace(replace, escapeChar);
+ };
+}());
+
+function Generator() {
+ this.escape = escape;
+}
+
+Generator.prototype = {
+ generate: function(tokens) {
+ let buffer = '';
+ for (let i = 0; i < tokens.length; i++) {
+ const token = tokens[i];
+ buffer += this[token.type](token);
+ }
+ return buffer;
+ },
+
+ escape: function(text) {
+ const unsafeCharsMap = this.unsafeCharsMap;
+ return text.replace(this.unsafeChars, function(char) {
+ return unsafeCharsMap[char] || char;
+ });
+ },
+
+ StartTag: function(token) {
+ let out = '<';
+ out += token.tagName;
+
+ if (token.attributes.length) {
+ out += ' ' + this.Attributes(token.attributes);
+ }
+
+ out += token.selfClosing ? '/>' : '>';
+
+ return out;
+ },
+
+ EndTag: function(token) {
+ return '' + token.tagName + '>';
+ },
+
+ Chars: function(token) {
+ return this.escape(token.chars);
+ },
+
+ Comment: function(token) {
+ return '';
+ },
+
+ Attributes: function(attributes) {
+ const out = [];
+
+ for (let i = 0, l = attributes.length; i < l; i++) {
+ const attribute = attributes[i];
+
+ out.push(this.Attribute(attribute[0], attribute[1]));
+ }
+
+ return out.join(' ');
+ },
+
+ Attribute: function(name, value) {
+ let attrString = name;
+
+ if (value) {
+ value = this.escape(value);
+ attrString += '="' + value + '"';
+ }
+
+ return attrString;
+ }
+};
+
+module.exports = function(tokens) {
+ const generator = new Generator();
+ return generator.generate(tokens);
+};
diff --git a/buildtools/svg-viewbox-loader.js b/buildtools/svg-viewbox-loader.js
index 577d23e4cc38..95634d8634e2 100644
--- a/buildtools/svg-viewbox-loader.js
+++ b/buildtools/svg-viewbox-loader.js
@@ -1,32 +1,79 @@
const simpleHTMLTokenizer = require('simple-html-tokenizer');
+const generate = require('./generate-xml-from-tokens.js');
module.exports = function(source) {
this.cacheable(true);
let tokens = simpleHTMLTokenizer.tokenize(source);
tokens = tokens.map((tag) => {
- let width = undefined;
- let height = undefined;
if (tag.type === 'StartTag' && tag.tagName === 'svg') {
+ let width = undefined;
+ let height = undefined;
+ let x = 0;
+ let y = 0;
for (const attribute of tag.attributes) {
if (attribute[0] === 'width') {
- width = parseFloat(attribute[1]);
+ try {
+ width = parseFloat(attribute[1]);
+ } catch (e) {
+ console.warn('Unable to read width: ' + attribute[1]);
+ }
}
if (attribute[0] === 'height') {
- height = parseFloat(attribute[1]);
+ try {
+ height = parseFloat(attribute[1]);
+ } catch (e) {
+ console.warn('Unable to read height: ' + attribute[1]);
+ }
+ }
+ if (attribute[0] === 'x') {
+ try {
+ x = parseFloat(attribute[1]);
+ } catch (e) {
+ console.warn('Unable to read x: ' + attribute[1]);
+ }
+ }
+ if (attribute[0] === 'y') {
+ try {
+ y = parseFloat(attribute[1]);
+ } catch (e) {
+ console.warn('Unable to read y: ' + attribute[1]);
+ }
+ }
+ if (attribute[0] === 'viewBox') {
+ try {
+ const attrs = attribute[1].split(' ');
+ x = parseFloat(attrs[0]);
+ y = parseFloat(attrs[1]);
+ width = parseFloat(attrs[2]);
+ height = parseFloat(attrs[3]);
+ } catch (e) {
+ console.warn('Unable to read viewbox: ' + attribute[1]);
+ }
}
}
if (width !== undefined && height != undefined) {
tag.attributes = tag.attributes.filter((attribute) => {
- return attribute[0] !== 'width' && attribute[0] != 'height'
- })
- tag.attributes.push(['viewBox', `0 0 ${width} ${height}`, true]);
- tag.attributes.push(['height', '1em', true]);
- tag.attributes.push(['width', `${width / height}em`, true]);
+ return attribute[0] !== 'width' && attribute[0] != 'height' && attribute[0] != 'viewBox';
+ });
+ if (x) {
+ tag.attributes.push(['x', x, true]);
+ }
+ if (y) {
+ tag.attributes.push(['y', y, true]);
+ }
+ if (this.resourceQuery.search(/inline/) >= 0) {
+ tag.attributes.push(['width', width, true]);
+ tag.attributes.push(['height', height, true]);
+ } else {
+ tag.attributes.push(['viewBox', `0 0 ${width} ${height}`, true]);
+ tag.attributes.push(['height', '1em', true]);
+ tag.attributes.push(['width', `${width / height}em`, true]);
+ }
}
}
return tag;
- })
+ });
- return simpleHTMLTokenizer.generate(tokens)
+ return generate(tokens);
};
diff --git a/buildtools/webpack.commons.js b/buildtools/webpack.commons.js
index b399607f9462..a7d0ca142ee8 100644
--- a/buildtools/webpack.commons.js
+++ b/buildtools/webpack.commons.js
@@ -61,19 +61,6 @@ const htmlRule = {
use: 'ejs-loader',
};
-const svgRule = {
- test: /\.svg$/,
- use: [
- {
- loader: 'svg-inline-loader',
- options: {
- removeSVGTagAttrs: false,
- },
- },
- './buildtools/svg-viewbox-loader',
- 'svgo-loader',
- ]
-};
function get_comp(firsts, lasts) {
return (f1, f2) => {
@@ -142,7 +129,6 @@ const config = function(hardSourceConfig, babelLoaderCacheDirectory) {
cssRule,
sassRule,
htmlRule,
- svgRule,
ngeoRule,
otherRule,
]
diff --git a/buildtools/webpack.dev.js b/buildtools/webpack.dev.js
index db241759887d..313e6f9a0a32 100644
--- a/buildtools/webpack.dev.js
+++ b/buildtools/webpack.dev.js
@@ -12,6 +12,33 @@ const resourcesRule = {
}
};
+const svgRule = {
+ test: /\.svg$/,
+ oneOf: [{
+ resourceQuery: /url/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[ext]'
+ },
+ },
+ 'svgo-loader',
+ ]
+ }, {
+ use: [
+ {
+ loader: 'svg-inline-loader',
+ options: {
+ removeSVGTagAttrs: false,
+ },
+ },
+ './buildtools/svg-viewbox-loader',
+ 'svgo-loader',
+ ]
+ }]
+};
+
new webpack.LoaderOptionsPlugin({
debug: false
});
@@ -19,12 +46,14 @@ new webpack.LoaderOptionsPlugin({
module.exports = {
mode: 'development',
+ // devtool: 'eval',
output: {
filename: '[name].js'
},
module: {
rules: [
resourcesRule,
+ svgRule,
]
},
};
diff --git a/buildtools/webpack.prod.js b/buildtools/webpack.prod.js
index 7b192008dc34..ba3a5386c613 100644
--- a/buildtools/webpack.prod.js
+++ b/buildtools/webpack.prod.js
@@ -12,6 +12,44 @@ const resourcesRule = {
}
};
+const svgRule = {
+ test: /\.svg$/,
+ oneOf: [{
+ resourceQuery: /url/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[hash:6].[ext]'
+ },
+ },
+ 'svgo-loader',
+ ]
+ }, {
+ resourceQuery: /inline/,
+ use: [
+ {
+ loader: 'svg-inline-loader',
+ options: {
+ removeSVGTagAttrs: false,
+ },
+ },
+ 'svgo-loader',
+ ]
+ }, {
+ use: [
+ {
+ loader: 'svg-inline-loader',
+ options: {
+ removeSVGTagAttrs: false,
+ },
+ },
+ './buildtools/svg-viewbox-loader',
+ 'svgo-loader',
+ ]
+ }]
+};
+
module.exports = function(TerserPluginCache) {
return {
mode: 'production',
@@ -24,6 +62,7 @@ module.exports = function(TerserPluginCache) {
module: {
rules: [
resourcesRule,
+ svgRule,
]
},
optimization: {
diff --git a/contribs/gmf/apps/desktop_alt/Controller.js b/contribs/gmf/apps/desktop_alt/Controller.js
index b7cb4a1bf62a..1cb553c01b86 100644
--- a/contribs/gmf/apps/desktop_alt/Controller.js
+++ b/contribs/gmf/apps/desktop_alt/Controller.js
@@ -20,7 +20,11 @@ import ngeoRoutingModule from 'ngeo/routing/module.js';
import EPSG2056 from '@geoblocks/proj/src/EPSG_2056.js';
import EPSG21781 from '@geoblocks/proj/src/EPSG_21781.js';
import ngeoStatemanagerWfsPermalink from 'ngeo/statemanager/WfsPermalink.js';
-import {Circle, Fill, Stroke, Style} from 'ol/style';
+import Style from 'ol/style/Style.js';
+import Circle from 'ol/style/Circle.js';
+import Fill from 'ol/style/Fill.js';
+import Stroke from 'ol/style/Stroke.js';
+import Icon from 'ol/style/Icon.js';
import Raven from 'raven-js/src/raven.js';
import RavenPluginsAngular from 'raven-js/plugins/angular.js';
@@ -194,4 +198,18 @@ const module = angular.module('Appdesktop_alt', [
module.controller('AlternativeDesktopController', Controller);
+
+module.value('gmfPermalinkOptions', /** @type {import('gmf/permalink/Permalink.js').PermalinkOptions} */ ({
+ crosshairStyle: [
+ new Style({
+ image: new Icon({
+ src: 'data:image/svg+xml;base64,' + btoa(require('./image/crosshair.svg?inline')),
+ // Also working
+ // src: require('./image/crosshair.svg?url'),
+ imgSize: [22, 22],
+ })
+ })
+ ]
+}));
+
export default module;
diff --git a/contribs/gmf/apps/desktop_alt/image/crosshair.svg b/contribs/gmf/apps/desktop_alt/image/crosshair.svg
new file mode 100644
index 000000000000..ad2c93477f28
--- /dev/null
+++ b/contribs/gmf/apps/desktop_alt/image/crosshair.svg
@@ -0,0 +1,17 @@
+
+
diff --git a/contribs/gmf/apps/desktop_alt/image/logo.png b/contribs/gmf/apps/desktop_alt/image/logo.png
deleted file mode 100644
index a07d43d5b7a8..000000000000
Binary files a/contribs/gmf/apps/desktop_alt/image/logo.png and /dev/null differ
diff --git a/contribs/gmf/apps/desktop_alt/image/logo.svg b/contribs/gmf/apps/desktop_alt/image/logo.svg
new file mode 100644
index 000000000000..e211bc9e7556
--- /dev/null
+++ b/contribs/gmf/apps/desktop_alt/image/logo.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/contribs/gmf/apps/desktop_alt/index.html.ejs b/contribs/gmf/apps/desktop_alt/index.html.ejs
index 8aecd7a461b0..99745c51fcd7 100644
--- a/contribs/gmf/apps/desktop_alt/index.html.ejs
+++ b/contribs/gmf/apps/desktop_alt/index.html.ejs
@@ -17,7 +17,7 @@
This example shows different ways to include an SVG in the application using Webpack.
+In a map:
+ +In the HTML:
+Font (2rem): <%=require("./font.svg")%>.
+Font (4rem): <%=require("./font.svg")%>.
+Inline (?inline): <%=require("./inline.svg?inline")%>.
+URL (?url): " />
+Note for Inkscape, in the document property - Page:
+Note: in font, and in inline mode, CSS rules can be used.
+ + diff --git a/examples/svg.js b/examples/svg.js new file mode 100644 index 000000000000..81c374bccc43 --- /dev/null +++ b/examples/svg.js @@ -0,0 +1,75 @@ +import angular from 'angular'; +import './svg.css'; +import EPSG21781 from '@geoblocks/proj/src/EPSG_21781.js'; + +import Map from 'ol/Map.js'; +import View from 'ol/View.js'; +import LayerVector from 'ol/layer/Vector.js'; +import SourceVector from 'ol/source/Vector.js'; +import Feature from 'ol/Feature.js'; +import Point from 'ol/geom/Point.js'; +import Style from 'ol/style/Style.js'; +import Icon from 'ol/style/Icon.js'; + +import MapModule from 'ngeo/map/module.js'; + + +/** @type {!angular.IModule} **/ +const appmodule = angular.module('app', [ + MapModule.name, +]); + + +/** + * @constructor + * @ngInject + * @hidden + */ +function MainController() { + const source = new SourceVector(); + const feature1 = new Feature({ + geometry: new Point([599000, 200000]) + }); + feature1.setStyle([new Style({ + image: new Icon({ + // @ts-ignore: For Webpack + src: 'data:image/svg+xml;base64,' + btoa(require('./inline.svg?inline')), + // For IE compatibility + imgSize: [65, 65] + }) + })]); + source.addFeature(feature1); + + const feature2 = new Feature({ + geometry: new Point([601000, 200000]) + }); + feature2.setStyle([new Style({ + image: new Icon({ + // @ts-ignore: For Webpack + src: require('./url.svg?url'), + // For IE compatibility + imgSize: [65, 65] + }) + })]); + source.addFeature(feature2); + + this.map = new Map({ + layers: [ + new LayerVector({ + source + }) + ], + view: new View({ + projection: EPSG21781, + resolutions: [200, 100, 50, 20, 10, 5, 2.5, 2, 1], + center: [600000, 200000], + zoom: 4 + }) + }); +} + + +appmodule.controller('MainController', MainController); + + +export default module; diff --git a/examples/url.svg b/examples/url.svg new file mode 100644 index 000000000000..12e4593221f6 --- /dev/null +++ b/examples/url.svg @@ -0,0 +1,80 @@ + + + +