• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iTowns / itowns / 5691913681

pending completion
5691913681

push

github

mgermerie
chore: update three to r154

3933 of 5864 branches covered (67.07%)

Branch coverage included in aggregate %.

7778 of 9456 relevant lines covered (82.25%)

1619.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.68
/src/Converter/Feature2Texture.js
1
import * as THREE from 'three';
1✔
2
import { FEATURE_TYPES } from 'Core/Feature';
1✔
3
import Extent from 'Core/Geographic/Extent';
1✔
4
import Coordinates from 'Core/Geographic/Coordinates';
1,733!
5

6
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1✔
7
const matrix = svg.createSVGMatrix();
1✔
8

9
function drawPolygon(ctx, vertices, indices = [{ offset: 0, count: 1 }], style = {}, size, extent, invCtxScale, canBeFilled) {
3!
10
    if (vertices.length === 0) {
3!
11
        return;
×
12
    }
13

14
    if (style.length) {
3!
15
        for (const s of style) {
×
16
            _drawPolygon(ctx, vertices, indices, s, size, extent, invCtxScale, canBeFilled);
×
17
        }
×
18
    } else {
19
        _drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale, canBeFilled);
3✔
20
    }
21
}
22

23
function _drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale, canBeFilled) {
24
    // build contour
25
    ctx.beginPath();
3✔
26
    for (const indice of indices) {
4✔
27
        if (indice.extent && Extent.intersectsExtent(indice.extent, extent)) {
4!
28
            const offset = indice.offset * size;
4✔
29
            const count = offset + indice.count * size;
4✔
30
            ctx.moveTo(vertices[offset], vertices[offset + 1]);
4✔
31
            for (let j = offset + size; j < count; j += size) {
4✔
32
                ctx.lineTo(vertices[j], vertices[j + 1]);
12✔
33
            }
34
        }
35
    }
36

37
    // draw line or edge of polygon
3✔
38
    if (style.stroke) {
3!
39
        strokeStyle(style, ctx, invCtxScale);
3✔
40
        ctx.stroke();
3✔
41
    }
42

43
    // fill polygon only
44
    if (canBeFilled && style.fill) {
3!
45
        fillStyle(style, ctx, invCtxScale);
3✔
46
        ctx.fill();
3✔
47
    }
48
}
49

50
function fillStyle(style, ctx, invCtxScale) {
51
    if (style.fill.pattern && ctx.fillStyle.src !== style.fill.pattern.src) {
3!
52
        ctx.fillStyle = ctx.createPattern(style.fill.pattern, 'repeat');
×
53
        if (ctx.fillStyle.setTransform) {
×
54
            ctx.fillStyle.setTransform(matrix.scale(invCtxScale));
×
55
        } else {
56
            console.warn('Raster pattern isn\'t completely supported on Ie and edge');
×
57
        }
58
    } else if (ctx.fillStyle !== style.fill.color) {
3✔
59
        ctx.fillStyle = style.fill.color;
1✔
60
    }
61
    if (style.fill.opacity !== ctx.globalAlpha) {
3!
62
        ctx.globalAlpha = style.fill.opacity;
3✔
63
    }
64
}
65

66
function strokeStyle(style, ctx, invCtxScale) {
67
    if (ctx.strokeStyle !== style.stroke.color) {
3✔
68
        ctx.strokeStyle = style.stroke.color;
1✔
69
    }
70
    const width = (style.stroke.width || 2.0) * invCtxScale;
3!
71
    if (ctx.lineWidth !== width) {
3✔
72
        ctx.lineWidth = width;
1✔
73
    }
74
    const alpha = style.stroke.opacity == undefined ? 1.0 : style.stroke.opacity;
3!
75
    if (alpha !== ctx.globalAlpha && typeof alpha == 'number') {
3!
76
        ctx.globalAlpha = alpha;
3✔
77
    }
78
    if (ctx.lineCap !== style.stroke.lineCap) {
3!
79
        ctx.lineCap = style.stroke.lineCap;
×
80
    }
81
    ctx.setLineDash(style.stroke.dasharray.map(a => a * invCtxScale * 2));
3✔
82
}
83

84
function drawPoint(ctx, x, y, style = {}, invCtxScale) {
1!
85
    ctx.beginPath();
1✔
86
    const opacity = style.point.opacity == undefined ? 1.0 : style.point.opacity;
1!
87
    if (opacity !== ctx.globalAlpha) {
1!
88
        ctx.globalAlpha = opacity;
1✔
89
    }
90

91
    ctx.arc(x, y, (style.point.radius || 3.0) * invCtxScale, 0, 2 * Math.PI, false);
1!
92
    if (style.point.color) {
1!
93
        ctx.fillStyle = style.point.color;
1✔
94
        ctx.fill();
1✔
95
    }
96
    if (style.point.line) {
1!
97
        ctx.lineWidth = (style.point.width || 1.0) * invCtxScale;
1✔
98
        ctx.strokeStyle = style.point.line;
1✔
99
        ctx.stroke();
1✔
100
    }
101
}
102

103
const coord = new Coordinates('EPSG:4326', 0, 0, 0);
1✔
104

105
function drawFeature(ctx, feature, extent, style, invCtxScale) {
106
    const extentDim = extent.planarDimensions();
2✔
107
    const scaleRadius = extentDim.x / ctx.canvas.width;
2✔
108
    const globals = { zoom: extent.zoom };
2✔
109

110
    for (const geometry of feature.geometries) {
6✔
111
        if (Extent.intersectsExtent(geometry.extent, extent)) {
4!
112
            const context = { globals, properties: () => geometry.properties };
12✔
113
            const contextStyle = (geometry.properties.style || style).drawingStylefromContext(context);
4!
114

115
            if (contextStyle) {
4!
116
                if (
4✔
117
                    feature.type === FEATURE_TYPES.POINT
5✔
118
                    && contextStyle.point
119
                ) {
120
                    // cross multiplication to know in the extent system the real size of
121
                    // the point
122
                    const px = (Math.round(contextStyle.point.radius * invCtxScale) || 3 * invCtxScale) * scaleRadius;
1!
123
                    for (const indice of geometry.indices) {
1✔
124
                        const offset = indice.offset * feature.size;
1✔
125
                        const count = offset + indice.count * feature.size;
1✔
126
                        for (let j = offset; j < count; j += feature.size) {
1✔
127
                            coord.setFromArray(feature.vertices, j);
1✔
128
                            if (extent.isPointInside(coord, px)) {
1!
129
                                drawPoint(ctx, feature.vertices[j], feature.vertices[j + 1], contextStyle, invCtxScale);
1✔
130
                            }
131
                        }
132
                    }
1✔
133
                } else {
134
                    drawPolygon(ctx, feature.vertices, geometry.indices, contextStyle, feature.size, extent, invCtxScale, (feature.type == FEATURE_TYPES.POLYGON));
3✔
135
                }
136
            }
137
        }
138
    }
2✔
139
}
140

141
const origin = new THREE.Vector3();
1✔
142
const dimension = new THREE.Vector3(0, 0, 1);
1✔
143
const scale = new THREE.Vector3();
1✔
144
const quaternion = new THREE.Quaternion();
1✔
145
const world2texture = new THREE.Matrix4();
1✔
146
const feature2texture = new THREE.Matrix4();
1✔
147
const worldTextureOrigin = new THREE.Vector3();
1✔
148

149
const featureExtent = new Extent('EPSG:4326', 0, 0, 0, 0);
1✔
150

151
export default {
1✔
152
    // backgroundColor is a THREE.Color to specify a color to fill the texture
153
    // with, given there is no feature passed in parameter
154
    createTextureFromFeature(collection, extent, sizeTexture, style = {}, backgroundColor) {
1!
155
        let texture;
156

157
        if (collection) {
1!
158
            // A texture is instancied drawn canvas
159
            // origin and dimension are used to transform the feature's coordinates to canvas's space
160
            extent.planarDimensions(dimension);
1✔
161
            const c = document.createElement('canvas');
1✔
162

163
            coord.crs = extent.crs;
1✔
164

165
            c.width = sizeTexture;
1✔
166
            c.height = sizeTexture;
1✔
167
            const ctx = c.getContext('2d');
1✔
168
            if (backgroundColor) {
1!
169
                ctx.fillStyle = backgroundColor.getStyle();
×
170
                ctx.fillRect(0, 0, sizeTexture, sizeTexture);
×
171
            }
172
            ctx.globalCompositeOperation = style.globalCompositeOperation || 'source-over';
1✔
173
            ctx.imageSmoothingEnabled = false;
1✔
174
            ctx.lineJoin = 'round';
1✔
175

176
            // transform extent to feature projection
177
            extent.as(collection.crs, featureExtent);
1✔
178
            // transform extent to local system
179
            featureExtent.applyMatrix4(collection.matrixWorldInverse);
1✔
180

181
            // compute matrix transformation `world2texture` to convert coordinates to texture coordinates
182
            if (collection.isInverted) {
1!
183
                worldTextureOrigin.set(extent.west, extent.north, 0);
×
184
                scale.set(ctx.canvas.width, -ctx.canvas.height, 1.0).divide(dimension);
×
185
            } else {
186
                worldTextureOrigin.set(extent.west, extent.south, 0);
1✔
187
                scale.set(ctx.canvas.width, ctx.canvas.height, 1.0).divide(dimension);
1✔
188
            }
189

190
            world2texture.compose(worldTextureOrigin.multiply(scale).negate(), quaternion, scale);
1✔
191

192
            // compute matrix transformation `feature2texture` to convert features coordinates to texture coordinates
193
            feature2texture.multiplyMatrices(world2texture, collection.matrixWorld);
1✔
194
            feature2texture.decompose(origin, quaternion, scale);
1✔
195

196
            ctx.setTransform(scale.x, 0, 0, scale.y, origin.x, origin.y);
1✔
197

198
            // to scale line width and radius circle
199
            const invCtxScale = Math.abs(1 / scale.x);
1✔
200

201
            // Draw the canvas
1✔
202
            for (const feature of collection.features) {
2✔
203
                drawFeature(ctx, feature, featureExtent, feature.style || style, invCtxScale);
2!
204
            }
1✔
205

206
            texture = new THREE.CanvasTexture(c);
1✔
207
            texture.flipY = collection.isInverted;
1✔
208
        } else if (backgroundColor) {
×
209
            const data = new Uint8Array(3);
×
210
            data[0] = backgroundColor.r * 255;
×
211
            data[1] = backgroundColor.g * 255;
×
212
            data[2] = backgroundColor.b * 255;
×
213
            texture = new THREE.DataTexture(data, 1, 1, THREE.RGBAFormat);
×
214
        } else {
215
            texture = new THREE.Texture();
×
216
        }
217

218
        return texture;
1✔
219
    },
220
};
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc