| | |
| | | import ctuLoadedFullBattery from '/map/agv/ctuLoadedFullBattery.svg'; |
| | | |
| | | let app, mapContainer, themeMode; |
| | | let selectedSprite, effectCircle, effectTicker; |
| | | let selectedSprite, effectOverlay, effectTicker; |
| | | let tooltip; |
| | | |
| | | export function getApp() { |
| | |
| | | } |
| | | |
| | | export const showSelectedEffect = (sprite) => { |
| | | if (!sprite) { |
| | | return; |
| | | } |
| | | // area |
| | | if (sprite.data?.type === DEVICE_TYPE.AREA) { |
| | | const { start, end } = sprite.data || {}; |
| | | const hasBounds = start && end; |
| | | const minX = hasBounds ? Math.min(start.x, end.x) : 0; |
| | | const maxX = hasBounds ? Math.max(start.x, end.x) : 0; |
| | | const minY = hasBounds ? Math.min(start.y, end.y) : 0; |
| | | const maxY = hasBounds ? Math.max(start.y, end.y) : 0; |
| | | const width = hasBounds ? Math.abs(maxX - minX) : Math.abs(sprite.width); |
| | | const height = hasBounds ? Math.abs(maxY - minY) : Math.abs(sprite.height); |
| | | const centerX = hasBounds ? (minX + maxX) / 2 : sprite.x; |
| | | const centerY = hasBounds ? (minY + maxY) / 2 : sprite.y; |
| | | const color = DEVICE_SELECTED_EFFECT_COLOR[DEVICE_TYPE.AREA] || (themeMode === 'light' ? '#747d8c' : '#718093'); |
| | | const lineWidth = Math.max(2, 4 / Math.abs(mapContainer.scale.x || 1)); |
| | | |
| | | effectOverlay = new PIXI.Graphics(); |
| | | effectOverlay.lineStyle(lineWidth, color, 1); |
| | | effectOverlay.drawRect(-width / 2, -height / 2, width, height); |
| | | effectOverlay.position.set(centerX, centerY); |
| | | effectOverlay.zIndex = sprite.zIndex + 1; |
| | | effectOverlay.blendMode = PIXI.BLEND_MODES.NORMAL; |
| | | mapContainer.addChild(effectOverlay); |
| | | |
| | | selectedSprite = sprite; |
| | | effectTicker = null; |
| | | return; |
| | | } |
| | | |
| | | // others |
| | | if (!sprite?.texture || !sprite?.texture?.valid) { |
| | | return; |
| | | } |
| | |
| | | |
| | | const alpha = 1; |
| | | |
| | | effectCircle = new PIXI.Graphics(); |
| | | effectCircle.beginFill(color, alpha); |
| | | effectCircle.drawCircle(0, 0, radius); |
| | | effectCircle.endFill(); |
| | | effectCircle.position.set(sprite.x, sprite.y); |
| | | effectCircle.zIndex = -1; |
| | | effectCircle.blendMode = PIXI.BLEND_MODES.NORMAL; |
| | | effectOverlay = new PIXI.Graphics(); |
| | | effectOverlay.beginFill(color, alpha); |
| | | effectOverlay.drawCircle(0, 0, radius); |
| | | effectOverlay.endFill(); |
| | | effectOverlay.position.set(sprite.x, sprite.y); |
| | | effectOverlay.zIndex = -1; |
| | | effectOverlay.blendMode = PIXI.BLEND_MODES.NORMAL; |
| | | |
| | | mapContainer.addChild(effectCircle); |
| | | mapContainer.addChild(effectOverlay); |
| | | |
| | | selectedSprite = sprite; |
| | | |
| | |
| | | scalingUp = true; |
| | | } |
| | | } |
| | | effectCircle.scale.set(pulseScale); |
| | | effectCircle.position.set(sprite.x, sprite.y); |
| | | effectOverlay.scale.set(pulseScale); |
| | | effectOverlay.position.set(sprite.x, sprite.y); |
| | | }; |
| | | |
| | | app.ticker.add(effectTicker); |
| | |
| | | app.ticker.remove(effectTicker); |
| | | effectTicker = null; |
| | | } |
| | | if (effectCircle) { |
| | | mapContainer?.removeChild(effectCircle); |
| | | effectCircle = null; |
| | | if (effectOverlay) { |
| | | mapContainer?.removeChild(effectOverlay); |
| | | effectOverlay = null; |
| | | } |
| | | selectedSprite = null; |
| | | }; |
| | | |
| | | export const updateEffect = () => { |
| | | if (!selectedSprite || !effectCircle) { |
| | | return; |
| | | } |
| | | effectCircle.position.set(selectedSprite.x, selectedSprite.y); |
| | | }; |
| | | |
| | | export const showRoutes = (curZone, setShowRoutes, setLoading) => { |
| | |
| | | |
| | | let areaDrawingCleanup = null; |
| | | const AREA_COLOR = 0x3498db; |
| | | const AREA_BORDER_COLOR = 0x6c7a89; |
| | | |
| | | const addAreaLabel = (draft, text, from, to) => { |
| | | const centerX = (from.x + to.x) / 2; |
| | |
| | | draft.addChild(label); |
| | | }; |
| | | |
| | | export const loadAreas = (curZone) => { |
| | | export const loadAreas = (curZone, setCurSprite) => { |
| | | if (!mapContainer) return; |
| | | clearAreas(); |
| | | fetchAreaList(curZone).then((areas) => { |
| | | areas.forEach((area) => { |
| | | const { name, color, id } = area || {}; |
| | | const start = area?.start || (area?.startX != null ? { x: area.startX, y: area.startY } : null); |
| | | const end = area?.end || (area?.endX != null ? { x: area.endX, y: area.endY } : null); |
| | | if (!start || !end || !name) { |
| | | const start = area?.start; |
| | | const end = area?.end; |
| | | if (!start || !end || !name || !id) { |
| | | return; |
| | | } |
| | | const g = createAreaGraphic({ name, start, end, color, id }); |
| | | if (g) { |
| | | mapContainer.addChild(g); |
| | | const graphics = createAreaGraphic({ name, start, end, color, id }, setCurSprite); |
| | | if (graphics) { |
| | | mapContainer.addChild(graphics); |
| | | } |
| | | }); |
| | | }); |
| | |
| | | } |
| | | }; |
| | | |
| | | const createAreaGraphic = ({ name, start, end, color, id }) => { |
| | | const createAreaGraphic = ({ name, start, end, color, id }, setCurSprite) => { |
| | | if (!mapContainer) return null; |
| | | const from = start || { x: 0, y: 0 }; |
| | | const to = end || { x: 0, y: 0 }; |
| | |
| | | const draft = new PIXI.Graphics(); |
| | | draft.name = id ? `area_${id}` : 'area_' + generateID(); |
| | | draft.zIndex = DEVICE_Z_INDEX.AREA; |
| | | draft.lineStyle(4 / Math.abs(mapContainer.scale.x || 1), areaColor, 0.8); |
| | | draft.lineStyle(2 / Math.abs(mapContainer.scale.x || 1), AREA_BORDER_COLOR, 0.9); |
| | | draft.beginFill(areaColor, 0.18); |
| | | draft.drawRect( |
| | | Math.min(from.x, to.x), |
| | |
| | | ); |
| | | draft.endFill(); |
| | | addAreaLabel(draft, name, from, to); |
| | | draft.data = { ...(draft.data || {}), type: DEVICE_TYPE.AREA, name, color: areaColor, id }; |
| | | draft.data = { ...(draft.data || {}), type: DEVICE_TYPE.AREA, name, color: areaColor, id, start: from, end: to }; |
| | | draft.eventMode = 'static'; |
| | | draft.cursor = 'pointer'; |
| | | if (setCurSprite) { |
| | | draft.off('click'); |
| | | draft.on('click', () => setCurSprite(draft)); |
| | | } |
| | | return draft; |
| | | }; |
| | | |
| | | export const startAreaDrawing = ({ promptText, onComplete, onFinish } = {}) => { |
| | | export const startAreaDrawing = ({ promptText, onComplete, onFinish, setCurSprite } = {}) => { |
| | | if (!mapContainer || !mapContainer.parent) { |
| | | return false; |
| | | } |
| | |
| | | const drawRect = (from, to) => { |
| | | draft.clear(); |
| | | const strokeColor = areaColor; |
| | | draft.lineStyle(4 / Math.abs(mapContainer.scale.x || 1), strokeColor, 0.8); |
| | | draft.lineStyle(2 / Math.abs(mapContainer.scale.x || 1), AREA_BORDER_COLOR, 0.9); |
| | | draft.beginFill(strokeColor, 0.18); |
| | | draft.drawRect( |
| | | Math.min(from.x, to.x), |
| | |
| | | } |
| | | |
| | | addAreaLabel(draft, areaName, startPoint, endPoint); |
| | | draft.data = { ...(draft.data || {}), type: DEVICE_TYPE.AREA, name: areaName, color: areaColor }; |
| | | draft.data = { ...(draft.data || {}), type: DEVICE_TYPE.AREA, name: areaName, color: areaColor, start: startPoint, end: endPoint }; |
| | | draft.eventMode = 'static'; |
| | | draft.cursor = 'pointer'; |
| | | if (setCurSprite) { |
| | | draft.off('click'); |
| | | draft.on('click', () => setCurSprite(draft)); |
| | | } |
| | | |
| | | if (onComplete) { |
| | | onComplete({ |
| | |
| | | stage.on('pointerup', handleUp); |
| | | return true; |
| | | }; |
| | | |
| | | export const cancelAreaDrawing = () => { |
| | | if (areaDrawingCleanup) { |
| | | areaDrawingCleanup(); |
| | | } |
| | | }; |