UNPKG

@meta2d/core

Version:

@meta2d/core: Powerful, Beautiful, Simple, Open - Web-Based 2D At Its Best .

221 lines 8.6 kB
import { calcRightBottom, getRect, translateRect } from '../rect'; export class ViewMap { parent; box; boxWidth = 320; boxHeight = 180; ratio = this.boxWidth / this.boxHeight; padding = 5; img; isShow; isDown; view; // 可视区域外框 timer; constructor(parent) { this.parent = parent; this.box = document.createElement('div'); this.img = new Image(); this.view = document.createElement('div'); this.box.appendChild(this.img); this.box.appendChild(this.view); this.parent.externalElements?.parentElement.appendChild(this.box); this.box.className = 'meta2d-map'; this.box.onmousedown = this.onMouseDown; this.box.onmousemove = this.onMouseMove; this.box.onmouseup = this.onMouseUp; this.box.onwheel = this.onWheel; let sheet; for (let i = 0; i < document.styleSheets.length; i++) { if (document.styleSheets[i].title === 'le5le/map') { sheet = document.styleSheets[i]; } } if (!sheet) { let style = document.createElement('style'); style.type = 'text/css'; style.title = 'le5le.com/map'; document.head.appendChild(style); style = document.createElement('style'); style.type = 'text/css'; document.head.appendChild(style); sheet = style.sheet; sheet.insertRule(`.meta2d-map{display:flex;width:${this.boxWidth + 2 * this.padding}px;height:${this.boxHeight + 2 * this.padding}px;padding:${this.padding}px;background:#f4f4f4;border:1px solid #ffffff;box-shadow: 0px 0px 14px 0px rgba(0,10,38,0.30);border-radius:8px;position:absolute;z-index:9999;right:0;bottom:0;justify-content:center;align-items:center;cursor:default;user-select:none;overflow: hidden;}`); sheet.insertRule('.meta2d-map img{max-width:100%;max-height:100%;pointer-events: none;}'); sheet.insertRule('.meta2d-map div{pointer-events: none;border:1px solid #1890ff;position:absolute}'); } } show() { this.box.style.display = 'flex'; const data = this.parent.store.data; if (data.pens.length) { this.img.style.display = 'block'; this.img.src = this.parent.toPng(0, undefined, true); this.setView(); } else { this.img.style.display = 'none'; } this.isShow = true; } hide() { this.box.style.display = 'none'; this.isShow = false; } setView() { const data = this.parent.store.data; if (data.pens.length) { let rect = getRect(data.pens); const vW = this.parent.store.data.width || this.parent.store.options.width; const vH = this.parent.store.data.height || this.parent.store.options.height; if (vW && vH) { //大屏 rect = { x: this.parent.store.data.origin.x, y: this.parent.store.data.origin.y, width: vW * this.parent.store.data.scale, height: vH * this.parent.store.data.scale, }; } else { clearTimeout(this.timer); this.timer = setTimeout(() => { if (this.parent.store.bkImg) { this.img.src = this.parent.toPng(0, undefined, true); } }, 300); } // rect += data.x y 得到相对坐标 translateRect(rect, data.x, data.y); const rectRatio = rect.width / rect.height; if (rectRatio > this.ratio) { // 上下留白,扩大高度 const height = rect.width / this.ratio; rect.y -= (height - rect.height) / 2; rect.height = height; calcRightBottom(rect); } else { // 左右留白,扩大宽度 const width = rect.height * this.ratio; rect.x -= (width - rect.width) / 2; rect.width = width; calcRightBottom(rect); } const canvasRect = this.parent.canvasRect; let left = 0, top = 0; if (rect.x < 0) { left = -rect.x / rect.width; } else if (rect.x + rect.width > canvasRect.width) { let space = 0; if (canvasRect.width > rect.width) { // 均已左上角为起点,这种场景需要剪掉一个留白 space = canvasRect.width - rect.width; } left = (-rect.x + space) / rect.width; } if (rect.y < 0) { top = -rect.y / rect.height; } else if (rect.y + rect.height > canvasRect.height) { let space = 0; if (canvasRect.height > rect.height) { space = canvasRect.height - rect.height; } top = (-rect.y + space) / rect.height; } const width = canvasRect.width > rect.width ? 1 : canvasRect.width / rect.width; const height = canvasRect.height > rect.height ? 1 : canvasRect.height / rect.height; this.view.style.left = this.padding + left * this.boxWidth + 'px'; this.view.style.width = width * this.boxWidth + 'px'; this.view.style.top = this.padding + top * this.boxHeight + 'px'; this.view.style.height = height * this.boxHeight + 'px'; } } onMouseDown = (e) => { e.preventDefault(); e.stopPropagation(); this.isDown = true; }; onMouseMove = (e) => { e.preventDefault(); e.stopPropagation(); if (this.isDown) { try { this.parent.gotoView(e.offsetX / this.box.clientWidth, e.offsetY / this.box.clientHeight); } catch (e) { console.warn(e.message); this.isDown = false; } } }; onMouseUp = (e) => { e.preventDefault(); e.stopPropagation(); try { this.parent.gotoView(e.offsetX / this.box.clientWidth, e.offsetY / this.box.clientHeight); } catch (e) { console.warn(e.message); } finally { this.isDown = false; } }; onWheel = (e) => { //放大镜缩放 let scaleOff = 0.015; if (this.parent.store.options.scaleOff) { scaleOff = this.parent.store.options.scaleOff; if (e.deltaY > 0) { scaleOff = -this.parent.store.options.scaleOff; } } else { let isMac = /mac os /i.test(navigator.userAgent); if (isMac) { if (!e.ctrlKey) { scaleOff *= e.wheelDeltaY / 240; } else if (e.deltaY > 0) { scaleOff *= -1; } } else { let offset = 0.2; if (e.deltaY.toString().indexOf('.') !== -1) { offset = 0.01; } if (e.deltaY > 0) { scaleOff = -offset; } else { scaleOff = offset; } } } let { offsetX: x, offsetY: y } = e; const width = this.parent.store.data.width || this.parent.store.options.width; const height = this.parent.store.data.height || this.parent.store.options.height; if (width && height) { //大屏 x = (x / this.boxWidth) * width * this.parent.store.data.scale + this.parent.store.data.origin.x + this.parent.store.data.x; y = (y / this.boxHeight) * height * this.parent.store.data.scale + this.parent.store.data.origin.y + this.parent.store.data.y; } else { const rect = this.parent.parent.getRect(); x = (x / this.boxWidth) * rect.width + rect.x + this.parent.store.data.x; y = (y / this.boxHeight) * rect.height + rect.y + this.parent.store.data.y; } this.parent.scale(this.parent.store.data.scale + scaleOff, { x, y }); }; } //# sourceMappingURL=map.js.map