UNPKG

@obliczeniowo/elementary

Version:
330 lines (326 loc) 14.7 kB
import * as i0 from '@angular/core'; import { Injectable } from '@angular/core'; import { ColorRGB, Point2D, TextTransform } from '@obliczeniowo/elementary/classes'; import { TextAlign, DrawingSvgInterface, Rect } from '@obliczeniowo/elementary/drawing'; import { DrawingPdfInterface } from '@obliczeniowo/elementary/drawing-pdf'; import * as i1 from '@obliczeniowo/elementary/files'; /* eslint-disable @typescript-eslint/no-unsafe-argument */ /** * Service that provide some extra functionality for mapbox library made to use maps in web applications */ class OblMapboxService { file; /** * Variable that contain table of layers id and properties that can be override from default one */ toOverride = [ { layerId: 'landcover_crop', fillOpacity: 0, fill: new ColorRGB(239, 233, 225), }, { layerId: 'landcover_grass', fillOpacity: 0, }, { layerId: 'water-shadow', fill: new ColorRGB(117, 207, 240), }, { layerId: 'road-shields-black', draw: { after: [], before: [ (feature, map, dc) => { const coords = feature.coords; let table = []; if (feature.type === 'MultiLineString') { const concat = coords.reduce((prev, curr) => [...prev, ...curr], []); table = concat.map((coord) => map.project(coord)); } else if (feature.type === 'LineString') { table = coords.map((coord) => map.project(coord)); } else if (typeof coords[0] === 'number') { table.push(map.project(coords)); } let last = table[0]; const newTable = []; newTable.push(last); for (let i = 1; i < table.length; i++) { const pt = table[i]; if (new Point2D(last.x, last.y) .subtract(new Point2D(pt.x, pt.y)) .sickLength() > 100000) { last = table[i]; newTable.push(last); } } newTable.forEach((pt) => { dc.drawRect(pt.x - 12, pt.y - 10, 24, 14, 1, '#000000', '#ffee00'); this.drawText(feature, dc, map, undefined, pt); }); }, ], }, }, { layerId: 'motorway-junction', draw: { after: [], before: [ (feature, map, dc) => { const coords = feature.coords; let table = []; if (feature.type === 'MultiLineString') { const concat = coords.reduce((prev, curr) => [...prev, ...curr], []); table = concat.map((coord) => map.project(coord)); } else if (feature.type === 'LineString') { table = coords.map((coord) => map.project(coord)); } else if (typeof coords[0] === 'number') { table.push(map.project(coords)); } let last = table[0]; const newTable = []; newTable.push(last); for (let i = 1; i < table.length; i++) { const pt = table[i]; if (new Point2D(last.x, last.y) .subtract(new Point2D(pt.x, pt.y)) .sickLength() > 100000) { last = table[i]; newTable.push(last); } } newTable.forEach((pt) => { dc.drawRect(pt.x - 12, pt.y - 10, 24, 14, 0, '#00aa00', '#007700'); this.drawText(feature, dc, map, undefined, pt); }); }, ], }, }, { layerId: 'road-shields-white', draw: { after: [], before: [ (feature, map, dc) => { const coords = feature.coords; let table = []; if (feature.type === 'MultiLineString') { const concat = coords.reduce((prev, curr) => [...prev, ...curr], []); table = concat.map((coord) => map.project(coord)); } else if (feature.type === 'LineString') { table = coords.map((coord) => map.project(coord)); } else if (typeof coords[0] === 'number') { table.push(map.project(coords)); } let last = table[0]; const newTable = []; newTable.push(last); for (let i = 1; i < table.length; i++) { const pt = table[i]; if (new Point2D(last.x, last.y) .subtract(new Point2D(pt.x, pt.y)) .sickLength() > 100000) { last = table[i]; newTable.push(last); } } newTable.forEach((pt) => { dc.drawRect(pt.x - 12, pt.y - 10, 24, 14, 0, '#ffffff', '#aa0000'); this.drawText(feature, dc, map, undefined, pt); }); }, ], }, }, ]; renderer; constructor(file, rendererFactory) { this.file = file; this.renderer = rendererFactory.createRenderer(null, null); } drawText(feature, dc, map, override, point) { if (feature.layer.layout['text-field']) { const { x, y } = point || map.project(feature.coords); const { // 'font-field': fontField, 'text-field': textField, // 'text-letter-spacing': textLetterSpacing, // 'text-max-angle': textMaxAngle, // 'text-padding': textPadding, // 'text-rotation-alignment': textRotationAlignment, 'text-size': textSize, 'text-max-width': maxTextWidth, } = feature.layer.layout; const { 'text-color': textColor, 'text-halo-color': textHaloColor, 'text-halo-width': textHaloWidth, } = feature.layer.paint; const color = override?.textColor || (textColor && new ColorRGB(textColor.r * 255, textColor.g * 255, textColor.b * 255) .getHexColorBase) || '#000000'; const haloColor = override?.haloColor || (textHaloColor && textHaloWidth) ? new ColorRGB(textHaloColor.r * 255, textHaloColor.g * 255, textHaloColor.b * 255).getHexColorBase : undefined; const coords = new Point2D(x, y); dc.setFontSize(textSize); dc.setTextAlign(TextAlign.CENTER); const text = TextTransform.prepare(textField, feature.properties); if (maxTextWidth) { this.drawSplittedText(dc, text, coords, color, haloColor, maxTextWidth); } else { if (haloColor) { dc.drawText(text, coords, '#ffffff', 0, { svgOnly: {}, style: { strokeWidth: 2, stroke: haloColor, }, }); } dc.drawText(text, coords, color, 0); } } } /** * Method to export mapbox layers to SVG file * @param map mapbox.map object */ exportToSvg(map, draw) { const w3 = 'http://www.w3.org/2000/svg'; const svg = this.renderer.createElement('svg', w3); const { width, height } = map.getCanvas(); svg.setAttribute('width', `${width}`); svg.setAttribute('height', `${height}`); svg.setAttribute('xmlns', w3); const dc = new DrawingSvgInterface(svg, this.renderer); this.draw(map, dc, draw); this.file.saveSvgFile(svg.outerHTML.replace(/&nbsp;/g, ' '), 'map'); } exportToPdf(map, draw) { const { width, height } = map.getCanvas(); const dc = new DrawingPdfInterface(new Rect(new Point2D(), new Point2D(width, height)), { orientation: 'landscape' }); this.draw(map, dc, draw); dc.save('map'); } draw(map, dc, draw) { const { width, height } = map.getCanvas(); const features = map .queryRenderedFeatures() .map((feature) => ({ coords: feature.geometry.coordinates, type: feature.geometry.type, layer: feature.layer, feature, properties: feature.properties, })) .reverse(); dc.drawRect(0, 0, width, height, 0, '#efe9e1', '#efe9e1'); const drawPolygon = (coords, layer, properties) => { const polygons = []; coords.forEach((polygon) => polygons.push(polygon .map((coords) => map.project(coords)) .map((coord) => new Point2D(coord.x, coord.y)))); const override = this.toOverride.find((item) => item.layerId === layer.id); const { paint } = layer; const lineColor = paint?.['line-color']; const transformedLineColor = (lineColor && new ColorRGB(lineColor.r * 255, lineColor.g * 255, lineColor.b * 255)) || undefined; const fillOpacity = override?.fillOpacity || (paint?.['fill-opacity'] && paint['fill-opacity']); const toWhite = (color, opacity) => color + (255 - color) * (1 - opacity) * ((lineColor && 1 - lineColor) || 1); const fillColor = paint?.['fill-color']; const transformedFillColor = override?.fill || (fillColor && new ColorRGB(toWhite(fillColor.r * 255, fillOpacity), toWhite(fillColor.g * 255, fillOpacity), toWhite(fillColor.b * 255, fillOpacity))) || undefined; const lineWidth = paint?.['line-width']; const lineOpacity = paint?.['line-opacity']; if (lineWidth === undefined && transformedFillColor === undefined) { return; } polygons.forEach((polygon) => dc.drawPolyline(polygon, lineWidth || 0, transformedLineColor?.getHexColorBase, { close: false, svgOnly: {}, style: { fill: transformedFillColor?.getHexColorBase, strokeOpacity: lineOpacity || 1, }, })); }; let currentLayer; features.forEach((feature) => { if (currentLayer !== feature.layer.id) { if (currentLayer) { dc.endGroup(); } currentLayer = feature.layer.id; dc.group({ name: currentLayer, }); } const override = this.toOverride.find((item) => item.layerId === feature.layer.id); override?.draw?.before.forEach((cb) => cb(feature, map, dc)); if (feature.type === 'Polygon') { drawPolygon(feature.coords, feature.layer, feature.properties); } else if (feature.type === 'MultiPolygon') { feature.coords.forEach((coords) => drawPolygon(coords, feature.layer, feature.properties)); } else if (feature.type === 'LineString') { drawPolygon([feature.coords], feature.layer, feature.properties); } else if (feature.type === 'MultiLineString') { drawPolygon(feature.coords, feature.layer, feature.properties); } else if (feature.layer.layout['text-field']) { this.drawText(feature, dc, map, override); } override?.draw?.after.forEach((cb) => cb(feature, map, dc)); }); if (currentLayer) { dc.endGroup(); } if (draw) { draw(dc); } } drawSplittedText(dc, text, position, color, haloColor, maxLength) { const strings = TextTransform.splitByLengthAndWords(text, maxLength); const fontSize = dc.getFontSize() * 1.2; strings.forEach((text, index) => { if (haloColor) { dc.drawText(text, position.add(new Point2D(0, index * fontSize)), color, 0, { svgOnly: {}, style: { strokeWidth: 2, stroke: haloColor, }, }); } dc.drawText(text, position.add(new Point2D(0, index * fontSize)), color, 0); }); return strings.length * fontSize; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: OblMapboxService, deps: [{ token: i1.OblFileService }, { token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: OblMapboxService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: OblMapboxService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i1.OblFileService }, { type: i0.RendererFactory2 }] }); /** * Generated bundle index. Do not edit. */ export { OblMapboxService }; //# sourceMappingURL=obliczeniowo-elementary-mapbox.mjs.map