UNPKG

ns-mapbox-gl-export

Version:

This module adds control which can export PDF and images.

455 lines 20.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DPI = exports.PageOrientation = exports.Size = exports.Unit = exports.Format = void 0; const jspdf_1 = require("jspdf"); require("jspdf-autotable"); const file_saver_1 = require("file-saver"); const mapbox_gl_1 = __importStar(require("mapbox-gl")); require("js-loading-overlay"); const fabric_1 = require("fabric"); exports.Format = { JPEG: 'jpg', PNG: 'png', PDF: 'pdf', SVG: 'svg', }; exports.Unit = { in: 'in', mm: 'mm', }; exports.Size = { '4.1 x 5.8 (A6)': [148, 105], '4.9 x 6.9 (B6)': [176, 125], '5.8 x 8.3 (A5)': [210, 148], '6.9 x 9.8 (B5)': [250, 176], '8.3 x 11.7 (A4)': [297, 210], '8.5 x 11 (LETTER)': [279, 216], '9.8 x 13.9 (B4)': [353, 250], '11.7 x 16.5 (A3)': [420, 297], '11 x 17 (TABLOID)': [420, 297], '13.9 x 19.7 (B3)': [500, 353], '16.5 x 23.4 (A2)': [594, 420], '19.7 x 27.8 (B2)': [707, 500], '22 x 34 (D)': [863, 558], '24 x 36 (E)': [914, 609], }; exports.PageOrientation = { Landscape: 'landscape', Portrait: 'portrait', }; exports.DPI = { 72: 72, 96: 96, 200: 200, 300: 300, 400: 400, }; class MapGenerator { constructor(map, size = exports.Size['8.3 x 11.7 (A4)'], dpi = 300, format = exports.Format.PNG.toString(), unit = exports.Unit.mm, accessToken, logoURL, adjustment) { this.padTo2Digits = (num) => num.toString().padStart(2, '0'); this.formatDate = (date) => [ this.padTo2Digits(date.getMonth() + 1), this.padTo2Digits(date.getDate()), date.getFullYear(), ].join('/'); this.map = map; this.width = size[0]; this.height = size[1]; this.dpi = dpi; this.format = format; this.unit = unit; this.accessToken = accessToken; this.logoURL = logoURL; this.adjustment = adjustment; } generate(loader, fName, pdfOptions, callback) { try { const this_ = this; if (loader) { JsLoadingOverlay.show({ overlayBackgroundColor: '#5D5959', overlayOpacity: '0.6', spinnerIcon: 'ball-spin', spinnerColor: '#5733d6', spinnerSize: '2x', overlayIDName: 'overlay', spinnerIDName: 'spinner', offsetX: 0, offsetY: 0, containerID: null, lockScroll: false, overlayZIndex: 9998, spinnerZIndex: 9999, }); } const actualPixelRatio = window.devicePixelRatio; Object.defineProperty(window, 'devicePixelRatio', { get() { return this_.dpi / 96; }, }); const hidden = document.createElement('div'); hidden.className = 'hidden-map'; document.body.appendChild(hidden); const container = document.createElement('div'); container.style.width = this.toPixels(this.width); container.style.height = this.toPixels(this.height); hidden.appendChild(container); const style = this.map.getStyle(); if (style) { if (style.sources) { const sources = style.sources; Object.keys(sources).forEach((name) => { const src = sources[name]; Object.keys(src).forEach((key) => { if (!src[key]) delete src[key]; }); }); } } const mapScale = this.getMapScaleInFeets(this.map.getZoom()); const validStyle = style || 'mapbox://styles/mapbox/streets-v11'; const renderMap = new mapbox_gl_1.Map({ accessToken: this.accessToken || mapbox_gl_1.default.accessToken || '', container, style: validStyle, center: this.map.getCenter(), zoom: this.map.getZoom(), bearing: this.map.getBearing(), pitch: this.map.getPitch(), interactive: false, preserveDrawingBuffer: true, fadeDuration: 0, attributionControl: false, transformRequest: this.map._requestManager._transformRequestFn, }); const addImagesToRenderMap = () => { var _a, _b; const images = ((_b = (_a = renderMap.style) === null || _a === void 0 ? void 0 : _a.imageManager) === null || _b === void 0 ? void 0 : _b.images) || {}; if (images && Object.keys(images).length > 0) { Object.keys(images).forEach((key) => { if (!key || !images[key].data) return; if (!renderMap.hasImage(key)) { const image = images[key]; if (image && typeof image.width === 'number' && typeof image.height === 'number' && image.data instanceof Uint8Array) { renderMap.addImage(key, { width: image.width, height: image.height, data: image.data, }); } else { console.error(`Invalid image object structure for key: ${key}`); } } }); } renderMap.loadImage('https://geoviewer.io/img/ns_marker.png', (error, image) => { if (error) { console.error('Error loading image:', error); return; } if (!renderMap.hasImage('gl-draw-ns-marker')) { if (image) { renderMap.addImage('gl-draw-ns-marker', image, { sdf: true }); console.log('Image added successfully.'); } } else { console.log('Image already exists.'); } }); }; if (!renderMap.isStyleLoaded()) { console.log('Waiting for renderMap to load...'); renderMap.once('style.load', addImagesToRenderMap); } else { addImagesToRenderMap(); } renderMap.once('idle', () => { var _a; const canvas = renderMap.getCanvas(); const fileName = `${fName || 'map'}.${this_.format}`; switch (this_.format) { case exports.Format.PNG: this_.toPNG(canvas, fileName, callback); break; case exports.Format.JPEG: this_.toJPEG(canvas, fileName, callback); break; case exports.Format.PDF: this_.toPDF(renderMap, fileName, Object.assign({ scale: `1'' = ${mapScale.toString()} ft` }, pdfOptions), callback); break; case exports.Format.SVG: this_.toSVG(canvas, fileName, callback); break; default: console.error(`Invalid file format: ${this_.format}`); break; } renderMap.remove(); (_a = hidden.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(hidden); Object.defineProperty(window, 'devicePixelRatio', { get() { return actualPixelRatio; }, }); if (loader) { JsLoadingOverlay.hide(); } }); } catch (e) { if (loader) { JsLoadingOverlay.hide(); } console.error(e); } } toPNG(canvas, fileName, callback) { canvas.toBlob((blob) => { if (callback) callback(null, blob); else { (0, file_saver_1.saveAs)(blob, fileName); } }); } toJPEG(canvas, fileName, callback) { canvas.toBlob((blob) => { if (callback) { callback(null, blob); } else { const uri = canvas.toDataURL('image/jpeg', 0.85); const a = document.createElement('a'); a.href = uri; a.download = fileName; a.click(); a.remove(); } }, 'image/jpeg', 0.85); } toPDF(map, fileName, pdfOptions, callback) { try { const canvas = map.getCanvas(); const maxWidth = this.width - 20; const maxHeight = this.height - 55; const imageWidth = maxWidth; let imageHeight = (canvas.height / canvas.width) * imageWidth; let yPosition = 13 + (maxHeight - imageHeight) / 2; if (!(pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.hideTitle) && (pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.hideFooter)) { yPosition += 15; } if (this.height > this.width) { imageHeight += 12; yPosition -= 5; } const pdf = new jspdf_1.jsPDF({ orientation: this.width > this.height ? 'l' : 'p', unit: this.unit, compress: true, format: [this.width, this.height], }); const largePaperSize = ((this.width === 863 && this.height === 558) || (this.width === 558 && this.height === 863) || (this.width === 914 && this.height === 609) || (this.width === 609 && this.height === 914)); const imageData = largePaperSize ? canvas.toDataURL('image/jpeg', 0.9) : canvas.toDataURL('image/png'); pdf.addImage(imageData, largePaperSize ? 'JPEG' : 'PNG', 10, yPosition + (!(pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.hideTitle) ? 0 : 15), imageWidth, imageHeight, undefined, 'FAST'); if (!(pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.hideTitle)) { pdf.setFontSize(13); const width = pdf.internal.pageSize.getWidth(); const titleText = ((pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.title) || '').toString() || ' '; const titleHeight = 9; const padding = 2; pdf.setFillColor(255, 255, 255); pdf.rect(0, 0, width, titleHeight + padding * 2, 'F'); pdf.setTextColor(0, 0, 0); pdf.text(titleText, width / 2, titleHeight / 2 + padding, { align: 'center', maxWidth: this.width - 20, }); } if (!(pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.hideFooter)) { const columns = [ pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.scale, pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.subTitle, this.formatDate(new Date()), '', ]; const infoRow = [ 'This map may represent a visual display of related geographic information. Data provided here is not a guarantee of actual field conditions. To ensure complete accuracy, please contact the responsible staff for the most up-to-date information.', ]; const options = { theme: 'grid', tableLineColor: [0, 0, 0], tableLineWidth: 0.5, startY: this.height - 40, styles: { overflow: 'linebreak', fontSize: 12, fontStyle: 'bold', halign: 'center', valign: 'middle', }, headStyles: { fillColor: [255, 255, 255], textColor: [0, 0, 0], lineColor: [0, 0, 0], lineWidth: 0.5, minCellHeight: 25, cellWidth: (this.width - 20) / 4, }, bodyStyles: { minCellHeight: 100, lineColor: [0, 0, 0] }, margin: { top: 0, left: 10, right: 10, bottom: 0, }, didDrawCell: (data) => { var _a, _b, _c, _d; if (data.section === 'head' && data.column.index === 3 && (pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoBase64)) { const cellWidth = Number(data.cell.width); const cellHeight = data.cell.height; const logoWidth = ((_a = pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoSize) === null || _a === void 0 ? void 0 : _a.width) || 20; const logoHeight = ((_b = pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoSize) === null || _b === void 0 ? void 0 : _b.height) || 20; const x = data.cell.x + (cellWidth - logoWidth) / 2; const y = data.cell.y + (cellHeight - logoHeight) / 2; pdf.addImage(pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoBase64, 'PNG', x, y, logoWidth, logoHeight); } else if (data.section === 'head' && data.column.index === 3 && (this.logoURL || (pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logo))) { const img = new Image(); img.src = `${this.logoURL || (pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logo)}?${Math.random()}`; const cellWidth = typeof data.cell.width === 'number' ? data.cell.width : parseFloat(data.cell.width); const cellHeight = data.cell.height; const logoWidth = ((_c = pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoSize) === null || _c === void 0 ? void 0 : _c.width) || 20; const logoHeight = ((_d = pdfOptions === null || pdfOptions === void 0 ? void 0 : pdfOptions.logoSize) === null || _d === void 0 ? void 0 : _d.height) || 20; const xPosition = data.cell.x + (cellWidth - logoWidth) / 2; const yPosition = data.cell.y + (cellHeight - logoHeight) / 2; pdf.addImage(img, 'JPEG', xPosition, yPosition, logoWidth, logoHeight); } }, }; pdf.autoTable(columns, [], options); const informationRowOptions = Object.assign(Object.assign({}, options), { startY: pdf.autoTable.previous.finalY, bodyStyles: { minCellHeight: 10, lineColor: [0, 0, 0], fontSize: 8.5, halign: 'left', }, cellWidth: this.width - 20 }); pdf.autoTable([columns], [infoRow], informationRowOptions); } const { lng, lat } = map.getCenter(); pdf.setProperties({ title: 'Map PDF', subject: `center: [${lng}, ${lat}], zoom: ${map.getZoom()}`, creator: 'Nobel Systems Map Exporter', author: '(c)Nobel Systems', }); if (callback) { const pdfBlob = pdf.output('blob'); callback(null, pdfBlob); } else { pdf.save(fileName); } } catch (e) { console.error(e); } } toSVG(canvas, fileName, callback) { const uri = canvas.toDataURL('image/png'); fabric_1.fabric.Image.fromURL(uri, (image) => { const tmpCanvas = new fabric_1.fabric.Canvas('canvas'); const pxWidth = Number(this.toPixels(this.width, this.dpi).replace('px', '')); const pxHeight = Number(this.toPixels(this.height, this.dpi).replace('px', '')); image.scaleToWidth(pxWidth); image.scaleToHeight(pxHeight); tmpCanvas.setWidth(pxWidth); tmpCanvas.setHeight(pxHeight); tmpCanvas.add(image); const svg = tmpCanvas.toSVG({ x: 0, y: 0, width: pxWidth, height: pxHeight, viewBox: { x: 0, y: 0, width: pxWidth, height: pxHeight, }, }); if (callback) { const blob = new Blob([svg], { type: 'image/svg+xml' }); callback(null, blob); } else { const a = document.createElement('a'); a.href = `data:application/xml,${encodeURIComponent(svg)}`; a.download = fileName; a.click(); a.remove(); } }); } toPixels(length, conversionFactor = 96) { if (this.unit === exports.Unit.mm) { conversionFactor /= 25.4; } return `${conversionFactor * length}px`; } getMapScaleInFeets(zoom) { return Math.round(591657550.5 / Math.pow(2, (zoom + 1 + Number(this.adjustment))) / 12).toFixed(0); } } exports.default = MapGenerator; //# sourceMappingURL=map-generator.js.map