| | |
| | | template: ` |
| | | <div style="width: 100%; height: 100%; position: relative;"> |
| | | <div ref="pixiView"></div> |
| | | <div style="position: absolute; top: 20px; right: 50px;"> |
| | | <div v-show="shelfTooltip.visible" |
| | | :style="shelfTooltipStyle()"> |
| | | {{ shelfTooltip.text }} |
| | | </div> |
| | | <div style="position: absolute; top: 20px; right: 50px; text-align: right;"> |
| | | <div>FPS:{{mapFps}}</div> |
| | | <div style="margin-top: 6px; display: flex; gap: 6px; justify-content: flex-end;"> |
| | | <button type="button" @click="rotateMap" style="padding: 2px 8px; font-size: 12px; cursor: pointer;">旋转</button> |
| | | <button type="button" @click="toggleMirror" style="padding: 2px 8px; font-size: 12px; cursor: pointer;">{{ mapMirrorX ? '取消镜像' : '镜像' }}</button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | `, |
| | |
| | | pixiCrnMap: new Map(), |
| | | pixiDualCrnMap: new Map(), |
| | | pixiRgvMap: new Map(), |
| | | mapRoot: null, |
| | | mapRotation: 0, |
| | | mapMirrorX: false, |
| | | mapContentSize: { width: 0, height: 0 }, |
| | | mapConfigCodes: { |
| | | rotate: 'map_canvas_rotation', |
| | | mirror: 'map_canvas_mirror_x' |
| | | }, |
| | | pixiShelfMap: new Map(), |
| | | pixiTrackMap: new Map(), |
| | | pixiDevpTextureMap: new Map(), |
| | |
| | | crnList: [], |
| | | dualCrnList: [], |
| | | rgvList: [], |
| | | locListMap: new Map(), |
| | | locListLoaded: false, |
| | | locListLoading: false, |
| | | mapRowOffsets: [], |
| | | mapRowHeights: [], |
| | | mapColOffsets: [], |
| | | mapColWidths: [], |
| | | mapRowColOffsets: [], |
| | | mapRowColWidths: [], |
| | | mapRowShelfCells: [], |
| | | hoveredShelfCell: null, |
| | | hoverPointer: { x: 0, y: 0 }, |
| | | hoverRaf: null, |
| | | objectsContainer: null, |
| | | objectsContainer2: null, |
| | | tracksContainer: null, |
| | |
| | | graphicsCrnTrack: null, |
| | | graphicsRgvTrack: null, |
| | | graphicsRgv: null, |
| | | shelfTooltip: { |
| | | visible: false, |
| | | x: 0, |
| | | y: 0, |
| | | text: '', |
| | | item: null |
| | | }, |
| | | shelfTooltipMinScale: 0.4, |
| | | timer: null, |
| | | adjustLabelTimer: null, |
| | | isSwitchingFloor: false |
| | |
| | | mounted() { |
| | | this.currentLev = this.lev || 1; |
| | | this.createMap(); |
| | | this.loadMapTransformConfig(); |
| | | this.loadLocList(); |
| | | this.connectWs(); |
| | | |
| | | setTimeout(() => { |
| | |
| | | }, |
| | | beforeDestroy() { |
| | | if (this.timer) { clearInterval(this.timer); } |
| | | |
| | | if (this.hoverRaf) { cancelAnimationFrame(this.hoverRaf); this.hoverRaf = null; } |
| | | if (this.pixiApp) { this.pixiApp.destroy(true, { children: true }); } |
| | | window.removeEventListener('resize', this.resizeToContainer); |
| | | if (this.wsReconnectTimer) { clearTimeout(this.wsReconnectTimer); this.wsReconnectTimer = null; } |
| | |
| | | this.shelvesContainer = new PIXI.ParticleContainer(10000, { scale: true, position: true, rotation: false, uvs: false, alpha: false }); |
| | | this.tracksContainer.autoResize = true; |
| | | this.shelvesContainer.autoResize = true; |
| | | this.pixiApp.stage.addChild(this.tracksGraphics); |
| | | this.pixiApp.stage.addChild(this.tracksContainer); |
| | | this.pixiApp.stage.addChild(this.shelvesContainer); |
| | | this.pixiApp.stage.addChild(this.objectsContainer); |
| | | this.pixiApp.stage.addChild(this.objectsContainer2); |
| | | this.mapRoot = new PIXI.Container(); |
| | | this.pixiApp.stage.addChild(this.mapRoot); |
| | | this.mapRoot.addChild(this.tracksGraphics); |
| | | this.mapRoot.addChild(this.tracksContainer); |
| | | this.mapRoot.addChild(this.shelvesContainer); |
| | | this.mapRoot.addChild(this.objectsContainer); |
| | | this.mapRoot.addChild(this.objectsContainer2); |
| | | this.pixiApp.renderer.roundPixels = true; |
| | | this.hoveredShelfCell = null; |
| | | this.hoverPointer = { x: 0, y: 0 }; |
| | | this.hoverRaf = null; |
| | | |
| | | |
| | | //*******************拖动画布******************* |
| | | |
| | | //*******************shelf hover******************* |
| | | this.pixiApp.renderer.plugins.interaction.on('pointermove', (event) => { |
| | | if (!this.isShelfTooltipAllowed()) { this.hideShelfTooltip(); return; } |
| | | if (!this.map || !this.mapRoot) { return; } |
| | | const pos = event.data.global; |
| | | this.hoverPointer.x = pos.x; |
| | | this.hoverPointer.y = pos.y; |
| | | if (this.hoverRaf) { return; } |
| | | this.hoverRaf = requestAnimationFrame(() => { |
| | | this.hoverRaf = null; |
| | | this.updateShelfHoverFromPointer(this.hoverPointer); |
| | | }); |
| | | }); |
| | | this.pixiApp.view.addEventListener('mouseleave', () => { |
| | | this.hoveredShelfCell = null; |
| | | this.hideShelfTooltip(); |
| | | }); |
| | | //*******************shelf hover******************* |
| | | let stageOriginalPos; |
| | | let mouseDownPoint; |
| | | let touchBlank = false; |
| | |
| | | const globalPos = event.data.global; |
| | | stageOriginalPos = [this.pixiApp.stage.position.x, this.pixiApp.stage.position.y]; |
| | | mouseDownPoint = [globalPos.x, globalPos.y]; |
| | | if (!event.target) { touchBlank = true; } |
| | | if (!event.target || (event.target && event.target._kind === 'shelf')) { touchBlank = true; } |
| | | }); |
| | | this.pixiApp.renderer.plugins.interaction.on('pointermove', (event) => { |
| | | const globalPos = event.data.global; |
| | |
| | | } |
| | | }); |
| | | this.pixiApp.renderer.plugins.interaction.on('pointerup', () => { touchBlank = false; }); |
| | | //*******************拖动画布******************* |
| | | |
| | | |
| | | //*******************缩放画布******************* |
| | | this.pixiApp.view.addEventListener('wheel', (event) => { |
| | |
| | | const rect = this.pixiApp.view.getBoundingClientRect(); |
| | | const sx = event.clientX - rect.left; |
| | | const sy = event.clientY - rect.top; |
| | | const oldZoom = this.pixiApp.stage.scale.x; |
| | | const oldZoomX = this.pixiApp.stage.scale.x || 1; |
| | | const oldZoomY = this.pixiApp.stage.scale.y || 1; |
| | | const oldZoomAbs = Math.abs(oldZoomX) || 1; |
| | | const delta = event.deltaY; |
| | | let newZoom = oldZoom * 0.999 ** delta; |
| | | const worldX = (sx - this.pixiApp.stage.position.x) / oldZoom; |
| | | const worldY = (sy - this.pixiApp.stage.position.y) / oldZoom; |
| | | const newPosX = sx - worldX * newZoom; |
| | | const newPosY = sy - worldY * newZoom; |
| | | this.pixiApp.stage.setTransform(newPosX, newPosY, newZoom, newZoom, 0, 0, 0, 0, 0); |
| | | let newZoomAbs = oldZoomAbs * 0.999 ** delta; |
| | | const mirrorX = this.mapMirrorX ? -1 : 1; |
| | | const newZoomX = mirrorX * newZoomAbs; |
| | | const newZoomY = newZoomAbs; |
| | | const worldX = (sx - this.pixiApp.stage.position.x) / oldZoomX; |
| | | const worldY = (sy - this.pixiApp.stage.position.y) / oldZoomY; |
| | | const newPosX = sx - worldX * newZoomX; |
| | | const newPosY = sy - worldY * newZoomY; |
| | | this.pixiApp.stage.setTransform(newPosX, newPosY, newZoomX, newZoomY, 0, 0, 0, 0, 0); |
| | | this.scheduleAdjustLabels(); |
| | | }); |
| | | //*******************缩放画布******************* |
| | |
| | | changeFloor(lev) { |
| | | this.currentLev = lev; |
| | | this.isSwitchingFloor = true; |
| | | this.hideShelfTooltip(); |
| | | this.hoveredShelfCell = null; |
| | | this.mapRowOffsets = []; |
| | | this.mapRowHeights = []; |
| | | this.mapColOffsets = []; |
| | | this.mapColWidths = []; |
| | | if (this.adjustLabelTimer) { clearTimeout(this.adjustLabelTimer); this.adjustLabelTimer = null; } |
| | | this.objectsContainer.removeChildren(); |
| | | this.objectsContainer2.removeChildren(); |
| | |
| | | this.getMap(); |
| | | }, |
| | | createMapData(map) { |
| | | this.hideShelfTooltip(); |
| | | this.hoveredShelfCell = null; |
| | | this.mapRowOffsets = []; |
| | | this.mapRowHeights = []; |
| | | this.mapColOffsets = []; |
| | | this.mapColWidths = []; |
| | | if (window.gsap) { |
| | | this.pixiStaMap && this.pixiStaMap.forEach((s) => { try { window.gsap.killTweensOf(s); } catch (e) {} }); |
| | | this.pixiCrnMap && this.pixiCrnMap.forEach((s) => { try { window.gsap.killTweensOf(s); } catch (e) {} }); |
| | |
| | | let val = row[colIndex]; |
| | | let cellWidth = val.width; |
| | | let cellHeight = val.height; |
| | | val.rowIndex = rowIndex; |
| | | val.colIndex = colIndex; |
| | | if (val.isMergedPart) { |
| | | val.posX = anchorX; |
| | | val.posY = yOffsets[rowIndex]; |
| | |
| | | } |
| | | }); |
| | | |
| | | this.buildShelfHitGrid(map, rowHeightScaled, yOffsets); |
| | | |
| | | this.drawTracks(map); |
| | | |
| | | map.forEach((item, index) => { |
| | | this.pixiStageList[index] = [item.length]; |
| | | for (let idx = 0; idx < item.length; idx++) { |
| | | let val = item[idx]; |
| | | val.rowIndex = index; |
| | | val.colIndex = idx; |
| | | if (val.type === 'merge') { continue; } |
| | | if (val.type == undefined || val.type === 'none') { continue; } |
| | | if (this.isTrackType(val)) { |
| | |
| | | sprite.textObj = text; |
| | | sprite.position.set(item.posX, item.posY); |
| | | sprite.interactive = true; // 必须要设置才能接收事件 |
| | | sprite.buttonMode = true; // 让光标在hover时变为手型指针 |
| | | sprite.buttonMode = true; // 让光标在hover时变为手型指事件 |
| | | sprite.on('pointerdown', () => { |
| | | if (window.gsap) { window.gsap.killTweensOf(sprite); } |
| | | sprite.alpha = 1; |
| | |
| | | sprite.textObj = text; |
| | | sprite.position.set(item.posX, item.posY); |
| | | sprite.interactive = true; // 必须要设置才能接收事件 |
| | | sprite.buttonMode = true; // 让光标在hover时变为手型指针 |
| | | sprite.buttonMode = true; // 让光标在hover时变为手型指事件 |
| | | sprite.on('pointerdown', () => { |
| | | if (window.gsap) { window.gsap.killTweensOf(sprite); } |
| | | sprite.alpha = 1; |
| | |
| | | if (bottom > contentH) { contentH = bottom; } |
| | | } |
| | | } |
| | | const vw = this.pixiApp.view.width; |
| | | const vh = this.pixiApp.view.height; |
| | | let scale = Math.min(vw / contentW, vh / contentH) * 0.95; |
| | | if (!isFinite(scale) || scale <= 0) { scale = 1; } |
| | | const posX = (vw - contentW * scale) / 2; |
| | | const posY = (vh - contentH * scale) / 2; |
| | | this.pixiApp.stage.setTransform(posX, posY, scale, scale, 0, 0, 0, 0, 0); |
| | | this.adjustLabelScale(); |
| | | this.mapContentSize = { width: contentW, height: contentH }; |
| | | this.applyMapTransform(true); |
| | | this.map = map; |
| | | this.isSwitchingFloor = false; |
| | | }, |
| | |
| | | getTrackSiteNo(obj) { |
| | | if (this.isJson(obj)) { let data = JSON.parse(obj); if (data.trackSiteNo == null || data.trackSiteNo == undefined) { return -1; } return data.trackSiteNo; } else { return -1; } |
| | | }, |
| | | buildShelfHitGrid(map, rowHeights, rowOffsets) { |
| | | if (!map || !Array.isArray(map)) { return; } |
| | | this.mapRowOffsets = Array.isArray(rowOffsets) ? rowOffsets.slice() : []; |
| | | this.mapRowHeights = Array.isArray(rowHeights) ? rowHeights.slice() : []; |
| | | const rowColOffsets = []; |
| | | const rowColWidths = []; |
| | | const rowShelfCells = new Array(map.length); |
| | | let maxCols = 0; |
| | | for (let r = 0; r < map.length; r++) { |
| | | const row = map[r]; |
| | | if (row && row.length > maxCols) { maxCols = row.length; } |
| | | rowShelfCells[r] = []; |
| | | } |
| | | const colWidths = new Array(maxCols); |
| | | for (let c = 0; c < maxCols; c++) { |
| | | let w = null; |
| | | for (let r = 0; r < map.length; r++) { |
| | | const cell = map[r] && map[r][c]; |
| | | if (!cell) { continue; } |
| | | if (cell.cellWidth != null && cell.cellWidth !== '') { |
| | | const base = Number(cell.cellWidth); |
| | | if (isFinite(base) && base > 0) { w = base / 40; break; } |
| | | } |
| | | } |
| | | colWidths[c] = (w && isFinite(w) && w > 0) ? w : 25; |
| | | } |
| | | const colOffsets = new Array(maxCols); |
| | | let xCursor = 0; |
| | | for (let c = 0; c < maxCols; c++) { |
| | | colOffsets[c] = xCursor; |
| | | xCursor += colWidths[c]; |
| | | } |
| | | for (let r = 0; r < map.length; r++) { |
| | | const row = map[r]; |
| | | if (!row || row.length === 0) { |
| | | rowColOffsets[r] = []; |
| | | rowColWidths[r] = []; |
| | | continue; |
| | | } |
| | | const widths = new Array(row.length); |
| | | for (let c = 0; c < row.length; c++) { |
| | | const cell = row[c]; |
| | | let w = null; |
| | | if (cell && cell.cellWidth != null && cell.cellWidth !== '') { |
| | | const base = Number(cell.cellWidth); |
| | | if (isFinite(base) && base > 0) { w = base / 40; } |
| | | } |
| | | widths[c] = (w && isFinite(w) && w > 0) ? w : 25; |
| | | } |
| | | const offsets = new Array(row.length); |
| | | let x = 0; |
| | | for (let c = 0; c < row.length; c++) { |
| | | offsets[c] = x; |
| | | x += widths[c]; |
| | | } |
| | | rowColOffsets[r] = offsets; |
| | | rowColWidths[r] = widths; |
| | | } |
| | | this.mapColWidths = colWidths; |
| | | this.mapColOffsets = colOffsets; |
| | | this.mapRowColOffsets = rowColOffsets; |
| | | this.mapRowColWidths = rowColWidths; |
| | | this.mapRowShelfCells = rowShelfCells; |
| | | |
| | | for (let r = 0; r < map.length; r++) { |
| | | const row = map[r]; |
| | | if (!row) { continue; } |
| | | for (let c = 0; c < row.length; c++) { |
| | | const cell = row[c]; |
| | | if (!cell || cell.type !== 'shelf') { continue; } |
| | | const startRow = this.findIndexByOffsets(this.mapRowOffsets, this.mapRowHeights, cell.posY + 0.01); |
| | | const endRow = this.findIndexByOffsets(this.mapRowOffsets, this.mapRowHeights, cell.posY + cell.height - 0.01); |
| | | if (startRow < 0) { continue; } |
| | | const last = endRow >= 0 ? endRow : startRow; |
| | | for (let rr = startRow; rr <= last; rr++) { |
| | | if (!rowShelfCells[rr]) { rowShelfCells[rr] = []; } |
| | | rowShelfCells[rr].push(cell); |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | findIndexByOffsets(offsets, sizes, value) { |
| | | if (!offsets || !sizes || offsets.length === 0) { return -1; } |
| | | for (let i = 0; i < offsets.length; i++) { |
| | | const start = offsets[i]; |
| | | const end = start + (sizes[i] || 0); |
| | | if (value >= start && value < end) { return i; } |
| | | } |
| | | return -1; |
| | | }, |
| | | updateShelfHoverFromPointer(globalPos) { |
| | | if (!this.map || !this.mapRoot) { return; } |
| | | if (!this.mapRowOffsets.length || !this.mapColOffsets.length) { return; } |
| | | const local = this.mapRoot.toLocal(new PIXI.Point(globalPos.x, globalPos.y)); |
| | | const rowIndex = this.findIndexByOffsets(this.mapRowOffsets, this.mapRowHeights, local.y); |
| | | if (rowIndex < 0) { if (this.hoveredShelfCell) { this.hoveredShelfCell = null; this.hideShelfTooltip(); } return; } |
| | | let cell = null; |
| | | if (this.mapRowShelfCells && this.mapRowShelfCells[rowIndex]) { |
| | | const list = this.mapRowShelfCells[rowIndex]; |
| | | for (let i = 0; i < list.length; i++) { |
| | | const it = list[i]; |
| | | if (!it) { continue; } |
| | | if (local.x >= it.posX && local.x < it.posX + it.width && |
| | | local.y >= it.posY && local.y < it.posY + it.height) { |
| | | cell = it; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | if (!cell || cell.type !== 'shelf') { if (this.hoveredShelfCell) { this.hoveredShelfCell = null; this.hideShelfTooltip(); } return; } |
| | | if (this.hoveredShelfCell !== cell) { |
| | | this.hoveredShelfCell = cell; |
| | | this.shelfTooltip.item = cell; |
| | | this.shelfTooltip.text = this.getShelfArrangeInfo(cell); |
| | | this.shelfTooltip.visible = true; |
| | | } |
| | | this.updateShelfTooltipPositionByGlobal(globalPos); |
| | | }, |
| | | normalizeLocTypeKey(value) { |
| | | if (value == null) { return null; } |
| | | const str = String(value).trim(); |
| | | if (!str) { return null; } |
| | | const parts = str.split('-').filter(p => p !== ''); |
| | | if (parts.length >= 3) { return parts.slice(0, parts.length - 1).join('-'); } |
| | | return str; |
| | | }, |
| | | loadLocList() { |
| | | if (!window.$ || typeof baseUrl === 'undefined') { return; } |
| | | if (this.locListLoading) { return; } |
| | | this.locListLoading = true; |
| | | $.ajax({ |
| | | url: baseUrl + "/console/map/locList", |
| | | headers: { 'token': localStorage.getItem('token') }, |
| | | dataType: 'json', |
| | | method: 'GET', |
| | | success: (res) => { |
| | | if (res && !Array.isArray(res)) { |
| | | if (res.code === 403) { parent.location.href = baseUrl + "/login"; return; } |
| | | if (res.code !== 200) { return; } |
| | | } |
| | | const list = Array.isArray(res) ? res : (res && res.code === 200 ? res.data : null); |
| | | if (!list || !Array.isArray(list)) { return; } |
| | | const map = new Map(); |
| | | list.forEach((item) => { |
| | | if (!item) { return; } |
| | | const locType = item.locType != null ? item.locType : item.loc_type; |
| | | if (locType != null && locType !== '') { |
| | | const normalizedType = this.normalizeLocTypeKey(locType); |
| | | if (normalizedType && !map.has(normalizedType)) { map.set(normalizedType, item); } |
| | | } |
| | | }); |
| | | this.locListMap = map; |
| | | this.locListLoaded = true; |
| | | if (this.shelfTooltip.visible) { |
| | | this.shelfTooltip.text = this.getShelfArrangeInfo(this.shelfTooltip.item); |
| | | } |
| | | }, |
| | | complete: () => { |
| | | this.locListLoading = false; |
| | | } |
| | | }); |
| | | }, |
| | | showShelfTooltip(e, item) { |
| | | if (!item) { return; } |
| | | if (!this.isShelfTooltipAllowed()) { this.hideShelfTooltip(); return; } |
| | | if (!this.locListLoaded && !this.locListLoading) { this.loadLocList(); } |
| | | this.shelfTooltip.item = item; |
| | | this.shelfTooltip.text = this.getShelfArrangeInfo(item); |
| | | this.updateShelfTooltipPosition(e); |
| | | this.shelfTooltip.visible = true; |
| | | }, |
| | | updateShelfTooltipPosition(e) { |
| | | if (!e || !e.data || !e.data.global) { return; } |
| | | this.updateShelfTooltipPositionByGlobal(e.data.global); |
| | | }, |
| | | updateShelfTooltipPositionByGlobal(globalPos) { |
| | | if (!this.isShelfTooltipAllowed()) { this.hideShelfTooltip(); return; } |
| | | if (!globalPos) { return; } |
| | | this.shelfTooltip.x = globalPos.x + 12; |
| | | this.shelfTooltip.y = globalPos.y + 12; |
| | | }, |
| | | hideShelfTooltip() { |
| | | this.shelfTooltip.visible = false; |
| | | this.shelfTooltip.item = null; |
| | | }, |
| | | isShelfTooltipAllowed() { |
| | | return this.getStageAbsScale() >= this.shelfTooltipMinScale; |
| | | }, |
| | | getStageAbsScale() { |
| | | if (!this.pixiApp || !this.pixiApp.stage) { return 1; } |
| | | return Math.abs(this.pixiApp.stage.scale.x || 1); |
| | | }, |
| | | updateShelfTooltipVisibilityByScale() { |
| | | if (this.shelfTooltip.visible && !this.isShelfTooltipAllowed()) { |
| | | this.hideShelfTooltip(); |
| | | this.hoveredShelfCell = null; |
| | | } |
| | | }, |
| | | getShelfArrangeInfo(item) { |
| | | const parts = []; |
| | | const matchKey = this.getShelfMatchKey(item); |
| | | if (matchKey != null) { parts.push('坐标:' + matchKey); } |
| | | const locInfo = (matchKey != null) ? this.locListMap.get(matchKey) : null; |
| | | if (locInfo) { |
| | | const locNo = locInfo.locNo != null ? locInfo.locNo : locInfo.loc_no; |
| | | const displayLocNo = this.stripLocLayer(locNo); |
| | | if (displayLocNo != null) { parts.push('排列:' + displayLocNo); } |
| | | } |
| | | return parts.join(' '); |
| | | }, |
| | | getShelfMatchKey(item) { |
| | | if (!item) { return null; } |
| | | const direct = item.locType != null ? item.locType : (item.loc_type != null ? item.loc_type : null); |
| | | const directKey = this.normalizeLocTypeKey(direct); |
| | | if (directKey) { return directKey; } |
| | | const rowIndex = item.rowIndex; |
| | | const colIndex = item.colIndex; |
| | | if (rowIndex == null || colIndex == null) { return null; } |
| | | const key0 = rowIndex + '-' + colIndex; |
| | | if (this.locListLoaded && this.locListMap && this.locListMap.size > 0) { |
| | | if (this.locListMap.has(key0)) { return key0; } |
| | | } |
| | | return null; |
| | | }, |
| | | stripLocLayer(locNo) { |
| | | if (locNo == null) { return null; } |
| | | const str = String(locNo).trim(); |
| | | if (!str) { return null; } |
| | | const parts = str.split('-').filter(p => p !== ''); |
| | | if (parts.length >= 3) { return parts.slice(0, parts.length - 1).join('-'); } |
| | | return str; |
| | | }, |
| | | shelfTooltipStyle() { |
| | | return { |
| | | position: 'absolute', |
| | | left: this.shelfTooltip.x + 'px', |
| | | top: this.shelfTooltip.y + 'px', |
| | | background: 'rgba(0,0,0,0.75)', |
| | | color: '#ffffff', |
| | | padding: '4px 8px', |
| | | borderRadius: '4px', |
| | | fontSize: '12px', |
| | | pointerEvents: 'none', |
| | | whiteSpace: 'nowrap', |
| | | zIndex: 10 |
| | | }; |
| | | }, |
| | | adjustLabelScale() { |
| | | const s = this.pixiApp && this.pixiApp.stage ? (this.pixiApp.stage.scale.x || 1) : 1; |
| | | const s = this.pixiApp && this.pixiApp.stage ? Math.abs(this.pixiApp.stage.scale.x || 1) : 1; |
| | | const minPx = 14; |
| | | const vw = this.pixiApp.view.width; |
| | | const vh = this.pixiApp.view.height; |
| | | const pos = this.pixiApp.stage.position; |
| | | const margin = 50; |
| | | const mirrorSign = this.mapMirrorX ? -1 : 1; |
| | | const inverseRotation = -((this.mapRotation % 360) * Math.PI / 180); |
| | | const tmpPoint = new PIXI.Point(); |
| | | this.pixiStaMap && this.pixiStaMap.forEach((sprite) => { |
| | | const textObj = sprite && sprite.textObj; |
| | | if (!textObj) { return; } |
| | |
| | | let scale = minPx / (base * s); |
| | | if (!isFinite(scale)) { scale = 1; } |
| | | scale = Math.max(0.8, Math.min(scale, 3)); |
| | | textObj.scale.set(scale); |
| | | textObj.scale.set(scale * mirrorSign, scale); |
| | | textObj.rotation = inverseRotation; |
| | | textObj.position.set(sprite.width / 2, sprite.height / 2); |
| | | const sx = pos.x + sprite.x * s; |
| | | const sy = pos.y + sprite.y * s; |
| | | const on = sx >= -margin && sy >= -margin && sx <= vw + margin && sy <= vh + margin; |
| | | sprite.getGlobalPosition(tmpPoint); |
| | | const on = tmpPoint.x >= -margin && tmpPoint.y >= -margin && tmpPoint.x <= vw + margin && tmpPoint.y <= vh + margin; |
| | | textObj.visible = (s >= 0.25) && on; |
| | | }); |
| | | this.pixiCrnMap && this.pixiCrnMap.forEach((sprite) => { |
| | |
| | | let scale = minPx / (base * s); |
| | | if (!isFinite(scale)) { scale = 1; } |
| | | scale = Math.max(0.8, Math.min(scale, 3)); |
| | | textObj.scale.set(scale); |
| | | textObj.scale.set(scale * mirrorSign, scale); |
| | | textObj.rotation = inverseRotation; |
| | | textObj.position.set(sprite.width / 2, sprite.height / 2); |
| | | const sx = pos.x + sprite.x * s; |
| | | const sy = pos.y + sprite.y * s; |
| | | const on = sx >= -margin && sy >= -margin && sx <= vw + margin && sy <= vh + margin; |
| | | sprite.getGlobalPosition(tmpPoint); |
| | | const on = tmpPoint.x >= -margin && tmpPoint.y >= -margin && tmpPoint.x <= vw + margin && tmpPoint.y <= vh + margin; |
| | | textObj.visible = (s >= 0.25) && on; |
| | | }); |
| | | this.pixiDualCrnMap && this.pixiDualCrnMap.forEach((sprite) => { |
| | |
| | | let scale = minPx / (base * s); |
| | | if (!isFinite(scale)) { scale = 1; } |
| | | scale = Math.max(0.8, Math.min(scale, 3)); |
| | | textObj.scale.set(scale); |
| | | textObj.scale.set(scale * mirrorSign, scale); |
| | | textObj.rotation = inverseRotation; |
| | | textObj.position.set(sprite.width / 2, sprite.height / 2); |
| | | const sx = pos.x + sprite.x * s; |
| | | const sy = pos.y + sprite.y * s; |
| | | const on = sx >= -margin && sy >= -margin && sx <= vw + margin && sy <= vh + margin; |
| | | sprite.getGlobalPosition(tmpPoint); |
| | | const on = tmpPoint.x >= -margin && tmpPoint.y >= -margin && tmpPoint.x <= vw + margin && tmpPoint.y <= vh + margin; |
| | | textObj.visible = (s >= 0.25) && on; |
| | | }); |
| | | this.pixiRgvMap && this.pixiRgvMap.forEach((sprite) => { |
| | |
| | | let scale = minPx / (base * s); |
| | | if (!isFinite(scale)) { scale = 1; } |
| | | scale = Math.max(0.8, Math.min(scale, 3)); |
| | | textObj.scale.set(scale); |
| | | textObj.scale.set(scale * mirrorSign, scale); |
| | | textObj.rotation = inverseRotation; |
| | | textObj.position.set(sprite.width / 2, sprite.height / 2); |
| | | const sx = pos.x + sprite.x * s; |
| | | const sy = pos.y * s + pos.y; |
| | | const on = sx >= -margin && sy >= -margin && sx <= vw + margin && sy <= vh + margin; |
| | | sprite.getGlobalPosition(tmpPoint); |
| | | const on = tmpPoint.x >= -margin && tmpPoint.y >= -margin && tmpPoint.x <= vw + margin && tmpPoint.y <= vh + margin; |
| | | textObj.visible = (s >= 0.25) && on; |
| | | }); |
| | | }, |
| | | rotateMap() { |
| | | this.mapRotation = (this.mapRotation + 90) % 360; |
| | | this.applyMapTransform(true); |
| | | this.saveMapTransformConfig(); |
| | | }, |
| | | toggleMirror() { |
| | | this.mapMirrorX = !this.mapMirrorX; |
| | | this.applyMapTransform(true); |
| | | this.saveMapTransformConfig(); |
| | | }, |
| | | parseRotation(value) { |
| | | const num = parseInt(value, 10); |
| | | if (!isFinite(num)) { return 0; } |
| | | const rot = ((num % 360) + 360) % 360; |
| | | return (rot === 90 || rot === 180 || rot === 270) ? rot : 0; |
| | | }, |
| | | parseMirror(value) { |
| | | if (value === true || value === false) { return value; } |
| | | if (value == null) { return false; } |
| | | const str = String(value).toLowerCase(); |
| | | return str === '1' || str === 'true' || str === 'y'; |
| | | }, |
| | | loadMapTransformConfig() { |
| | | if (!window.$ || typeof baseUrl === 'undefined') { return; } |
| | | $.ajax({ |
| | | url: baseUrl + "/config/listAll/auth", |
| | | headers: { 'token': localStorage.getItem('token') }, |
| | | dataType: 'json', |
| | | method: 'GET', |
| | | success: (res) => { |
| | | if (!res || res.code !== 200 || !Array.isArray(res.data)) { |
| | | if (res && res.code === 403) { parent.location.href = baseUrl + "/login"; } |
| | | return; |
| | | } |
| | | const byCode = {}; |
| | | res.data.forEach((item) => { |
| | | if (item && item.code) { byCode[item.code] = item; } |
| | | }); |
| | | const rotateCfg = byCode[this.mapConfigCodes.rotate]; |
| | | const mirrorCfg = byCode[this.mapConfigCodes.mirror]; |
| | | if (rotateCfg && rotateCfg.value != null) { |
| | | this.mapRotation = this.parseRotation(rotateCfg.value); |
| | | } |
| | | if (mirrorCfg && mirrorCfg.value != null) { |
| | | this.mapMirrorX = this.parseMirror(mirrorCfg.value); |
| | | } |
| | | if (rotateCfg == null || mirrorCfg == null) { |
| | | this.createMapTransformConfigIfMissing(rotateCfg, mirrorCfg); |
| | | } |
| | | if (this.mapContentSize && this.mapContentSize.width > 0) { |
| | | this.applyMapTransform(true); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | createMapTransformConfigIfMissing(rotateCfg, mirrorCfg) { |
| | | if (!window.$ || typeof baseUrl === 'undefined') { return; } |
| | | const createList = []; |
| | | if (!rotateCfg) { |
| | | createList.push({ |
| | | name: '地图旋转', |
| | | code: this.mapConfigCodes.rotate, |
| | | value: String(this.mapRotation || 0), |
| | | type: 1, |
| | | status: 1, |
| | | selectType: 'map' |
| | | }); |
| | | } |
| | | if (!mirrorCfg) { |
| | | createList.push({ |
| | | name: '地图镜像', |
| | | code: this.mapConfigCodes.mirror, |
| | | value: this.mapMirrorX ? '1' : '0', |
| | | type: 1, |
| | | status: 1, |
| | | selectType: 'map' |
| | | }); |
| | | } |
| | | createList.forEach((cfg) => { |
| | | $.ajax({ |
| | | url: baseUrl + "/config/add/auth", |
| | | headers: { 'token': localStorage.getItem('token') }, |
| | | method: 'POST', |
| | | data: cfg |
| | | }); |
| | | }); |
| | | }, |
| | | saveMapTransformConfig() { |
| | | if (!window.$ || typeof baseUrl === 'undefined') { return; } |
| | | const updateList = [ |
| | | { code: this.mapConfigCodes.rotate, value: String(this.mapRotation || 0) }, |
| | | { code: this.mapConfigCodes.mirror, value: this.mapMirrorX ? '1' : '0' } |
| | | ]; |
| | | $.ajax({ |
| | | url: baseUrl + "/config/updateBatch", |
| | | headers: { 'token': localStorage.getItem('token') }, |
| | | data: JSON.stringify(updateList), |
| | | dataType: 'json', |
| | | contentType: 'application/json;charset=UTF-8', |
| | | method: 'POST' |
| | | }); |
| | | }, |
| | | getTransformedContentSize() { |
| | | const size = this.mapContentSize || { width: 0, height: 0 }; |
| | | const w = size.width || 0; |
| | | const h = size.height || 0; |
| | | const rot = ((this.mapRotation % 360) + 360) % 360; |
| | | const swap = rot === 90 || rot === 270; |
| | | return { width: swap ? h : w, height: swap ? w : h }; |
| | | }, |
| | | fitStageToContent() { |
| | | if (!this.pixiApp || !this.mapContentSize) { return; } |
| | | const size = this.getTransformedContentSize(); |
| | | const contentW = size.width || 0; |
| | | const contentH = size.height || 0; |
| | | if (contentW <= 0 || contentH <= 0) { return; } |
| | | const vw = this.pixiApp.view.width; |
| | | const vh = this.pixiApp.view.height; |
| | | let scale = Math.min(vw / contentW, vh / contentH) * 0.95; |
| | | if (!isFinite(scale) || scale <= 0) { scale = 1; } |
| | | const baseW = this.mapContentSize.width || contentW; |
| | | const baseH = this.mapContentSize.height || contentH; |
| | | const mirrorX = this.mapMirrorX ? -1 : 1; |
| | | const scaleX = scale * mirrorX; |
| | | const scaleY = scale; |
| | | const posX = (vw / 2) - (baseW / 2) * scaleX; |
| | | const posY = (vh / 2) - (baseH / 2) * scaleY; |
| | | this.pixiApp.stage.setTransform(posX, posY, scaleX, scaleY, 0, 0, 0, 0, 0); |
| | | }, |
| | | applyMapTransform(fitToView) { |
| | | if (!this.mapRoot || !this.mapContentSize) { return; } |
| | | const contentW = this.mapContentSize.width || 0; |
| | | const contentH = this.mapContentSize.height || 0; |
| | | if (contentW <= 0 || contentH <= 0) { return; } |
| | | this.mapRoot.pivot.set(contentW / 2, contentH / 2); |
| | | this.mapRoot.position.set(contentW / 2, contentH / 2); |
| | | this.mapRoot.rotation = (this.mapRotation % 360) * Math.PI / 180; |
| | | this.mapRoot.scale.set(1, 1); |
| | | if (fitToView) { this.fitStageToContent(); } |
| | | this.scheduleAdjustLabels(); |
| | | }, |
| | | scheduleAdjustLabels() { |
| | | if (this.adjustLabelTimer) { clearTimeout(this.adjustLabelTimer); } |
| | | this.adjustLabelTimer = setTimeout(() => { |
| | | this.adjustLabelScale(); |
| | | this.updateShelfTooltipVisibilityByScale(); |
| | | this.adjustLabelTimer = null; |
| | | }, 20); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |