diff --git a/src/Core/Style.js b/src/Core/Style.js index 6a09ffe300..bd57ad4c19 100644 --- a/src/Core/Style.js +++ b/src/Core/Style.js @@ -212,14 +212,14 @@ function defineStyleCategory(style, category, userValue) { return value; } style[category] = {}; - value = userValue; - if (userValue instanceof Function) { // always true + value = { ...userValue }; + if (userValue instanceof Function) { value = readExpression(userValue, style.context); } defaultRules[category].keys.forEach((key) => { - defineStyleProperty(style, category, key, value[key], defaultRules[category].defaultValue[key]); + defineStyleProperty(style, category, key, value[key], defaultRules[category].defaultValue?.[key]);// zoom has no defaultValue }); - defaultRules[category].ifKeys.forEach((key) => { + defaultRules[category].ifKeys?.forEach((key) => { // zoom, stroke, text and icon have no ifKeys if (value[key] != undefined) { defineStyleProperty(style, category, key, value[key]); } @@ -545,93 +545,17 @@ class Style { params.text = params.text || {}; params.icon = params.icon || {}; - if (params.zoom instanceof Function) { - defineStyleCategory(this, 'zoom', params.zoom); - } else { - this.zoom = {}; - defineStyleProperty(this, 'zoom', 'min', params.zoom.min); - defineStyleProperty(this, 'zoom', 'max', params.zoom.max); - } - - if (params.fill instanceof Function) { - defineStyleCategory(this, 'fill', params.fill); - } else { - this.fill = {}; - defineStyleProperty(this, 'fill', 'color', params.fill.color); - defineStyleProperty(this, 'fill', 'opacity', params.fill.opacity, 1.0); - defineStyleProperty(this, 'fill', 'pattern', params.fill.pattern); - defineStyleProperty(this, 'fill', 'base_altitude', params.fill.base_altitude, baseAltitudeDefault); - if (params.fill.extrusion_height) { - defineStyleProperty(this, 'fill', 'extrusion_height', params.fill.extrusion_height); - } - } - - if (params.stroke instanceof Function) { - defineStyleCategory(this, 'stroke', params.stroke); - } else { - this.stroke = {}; - defineStyleProperty(this, 'stroke', 'color', params.stroke.color); - defineStyleProperty(this, 'stroke', 'opacity', params.stroke.opacity, 1.0); - defineStyleProperty(this, 'stroke', 'width', params.stroke.width, 1.0); - defineStyleProperty(this, 'stroke', 'dasharray', params.stroke.dasharray, []); - defineStyleProperty(this, 'stroke', 'base_altitude', params.stroke.base_altitude, baseAltitudeDefault); - } - - if (params.point instanceof Function) { - defineStyleCategory(this, 'point', params.point); - } else { - this.point = {}; - defineStyleProperty(this, 'point', 'color', params.point.color); - defineStyleProperty(this, 'point', 'line', params.point.line); - defineStyleProperty(this, 'point', 'opacity', params.point.opacity, 1.0); - defineStyleProperty(this, 'point', 'radius', params.point.radius, 2.0); - defineStyleProperty(this, 'point', 'width', params.point.width, 0.0); - defineStyleProperty(this, 'point', 'base_altitude', params.point.base_altitude, baseAltitudeDefault); - if (params.point.model) { - defineStyleProperty(this, 'point', 'model', params.point.model); - } + if (params.icon.key) { + console.warn("'icon.key' is deprecated: use 'icon.id' instead"); + params.icon.id = params.icon.key; } - if (params.text instanceof Function) { - defineStyleCategory(this, 'text', params.text); - } else { - this.text = {}; - defineStyleProperty(this, 'text', 'field', params.text.field); - defineStyleProperty(this, 'text', 'zOrder', params.text.zOrder, 'auto'); - defineStyleProperty(this, 'text', 'color', params.text.color, '#000000'); - defineStyleProperty(this, 'text', 'anchor', params.text.anchor, 'center'); - defineStyleProperty(this, 'text', 'offset', params.text.offset, [0, 0]); - defineStyleProperty(this, 'text', 'padding', params.text.padding, 2); - defineStyleProperty(this, 'text', 'size', params.text.size, 16); - defineStyleProperty(this, 'text', 'placement', params.text.placement, 'point'); - defineStyleProperty(this, 'text', 'rotation', params.text.rotation, 'auto'); - defineStyleProperty(this, 'text', 'wrap', params.text.wrap, 10); - defineStyleProperty(this, 'text', 'spacing', params.text.spacing, 0); - defineStyleProperty(this, 'text', 'transform', params.text.transform, 'none'); - defineStyleProperty(this, 'text', 'justify', params.text.justify, 'center'); - defineStyleProperty(this, 'text', 'opacity', params.text.opacity, 1.0); - defineStyleProperty(this, 'text', 'font', params.text.font, ['Open Sans Regular', 'Arial Unicode MS Regular', 'sans-serif']); - defineStyleProperty(this, 'text', 'haloColor', params.text.haloColor, '#000000'); - defineStyleProperty(this, 'text', 'haloWidth', params.text.haloWidth, 0); - defineStyleProperty(this, 'text', 'haloBlur', params.text.haloBlur, 0); - } - - if (params.icon instanceof Function) { - defineStyleCategory(this, 'icon', params.icon); - } else { - this.icon = {}; - defineStyleProperty(this, 'icon', 'source', params.icon.source); - if (params.icon.key) { - console.warn("'icon.key' is deprecated: use 'icon.id' instead"); - params.icon.id = params.icon.key; - } - defineStyleProperty(this, 'icon', 'id', params.icon.id); - defineStyleProperty(this, 'icon', 'cropValues', params.icon.cropValues); - defineStyleProperty(this, 'icon', 'anchor', params.icon.anchor, 'center'); - defineStyleProperty(this, 'icon', 'size', params.icon.size, 1); - defineStyleProperty(this, 'icon', 'color', params.icon.color); - defineStyleProperty(this, 'icon', 'opacity', params.icon.opacity, 1.0); - } + defineStyleCategory(this, 'zoom', params.zoom); + defineStyleCategory(this, 'fill', params.fill); + defineStyleCategory(this, 'stroke', params.stroke); + defineStyleCategory(this, 'point', params.point); + defineStyleCategory(this, 'text', params.text); + defineStyleCategory(this, 'icon', params.icon); } setContext(ctx) { diff --git a/test/unit/style.js b/test/unit/style.js index 75239efa86..3f58a801e2 100644 --- a/test/unit/style.js +++ b/test/unit/style.js @@ -32,35 +32,34 @@ describe('Style', function () { stubFetcherTexture.restore(); }); - const styleOpt = { - fill: { - color: 'blue', - opacity: { - stops: [[10, '{opacity}']], // Mapbox vectorTile - }, - pattern: { - // Mock MapBox StyleExpression() instance - expression: { evaluate: () => 'pattern' }, + it('Instanciate style from styleOpt and context', function _it() { + const styleOpt = { + fill: { + color: 'blue', + opacity: { + stops: [[10, '{opacity}']], // Mapbox vectorTile + }, + pattern: { + // Mock MapBox StyleExpression() instance + expression: { evaluate: () => 'pattern' }, + }, + extrusion_height: { + stops: [[10, (p, ctx) => 10 + ctx.coordinates.z]], + }, }, - extrusion_height: { - stops: [[10, (p, ctx) => 10 + ctx.coordinates.z]], + }; + const ctx = { + coordinates: { z: -2 }, + properties: { + opacity: -3, }, - }, - }; - const ctx = { - coordinates: { z: -2 }, - properties: { - opacity: -3, - }, - }; - - const style = new Style(styleOpt); - style.point.color = 'red'; - style.setContext(ctx); - // mock StyleContext() instance - style.context.featureStyle = { stroke: { color: 'pink' } }; + }; + const style = new Style(styleOpt); + style.point.color = 'red'; + style.setContext(ctx); + // mock StyleContext() instance + style.context.featureStyle = { stroke: { color: 'pink' } }; - it('Instanciate style from styleOpt and context', function _it() { // no default value assert.equal(style.point.line, undefined); // defaultValue is value @@ -82,6 +81,44 @@ describe('Style', function () { assert.equal(style.stroke.color, 'pink'); }); + it('Instanciate style from fct at category level', function _it() { + const fill = () => ({ + color: 'blue', + opacity: { + stops: [[10, '{opacity}']], // Mapbox vectorTile + }, + pattern: { + // Mock MapBox StyleExpression() instance + expression: { evaluate: () => 'pattern' }, + }, + extrusion_height: { + stops: [[10, (p, ctx) => 10 + ctx.coordinates.z]], + }, + }); + const styleOpt = { + fill, + }; + const ctx = { + coordinates: { z: -2 }, + properties: { + opacity: -3, + }, + }; + const style = new Style(styleOpt); + style.setContext(ctx); + // mock StyleContext() instance + style.context.featureStyle = { stroke: { color: 'pink' } }; + + // userValue + assert.equal(style.fill.color, fill().color); + // userValue with stops & {} + assert.equal(style.fill.opacity, ctx.properties.opacity); + // userValue as MapBox expression + assert.equal(style.fill.pattern, fill().pattern.expression.evaluate()); + // userValue with stops & function + assert.equal(style.fill.extrusion_height, fill().extrusion_height.stops[0][1](2, ctx)); + }); + describe('applyToCanvasPolygon()', () => { const styleOpt = { point: {},