tcctyn-ui/src/views/systemTemplate/forestFire/Toolbar/Toolbar.vue

374 lines
9.9 KiB
Vue
Raw Normal View History

<template>
<div class="toolbar-container">
<div
class="toolbar-thumbnail"
:title="isOpen ? '收起工具栏' : '展开工具栏'"
@click="isOpen = !isOpen"
></div>
<div class="toolbar">
<!-- 一级工具菜单 -->
<div
v-for="tool in options"
:key="tool.id"
class="tool-wrapper"
:class="{'open': isOpen}"
>
<!-- 主工具按钮 -->
<div class="tool-button" @click="tool.name && bus.emit(`toolbar_${tool.name}`, params)">
<el-image class="tool-icon" :src="tool.icon" fit="contain" />
</div>
<!-- 主工具名称 (右侧淡入淡出) -->
<div class="tool-name main-name">{{ tool.label }}</div>
<!-- 二级工具菜单 (左侧淡入淡出) -->
<div v-if="tool.subtools && tool.subtools?.length > 0" class="toolbar submenu">
<!-- 遍历二级工具按钮 -->
<div
v-for="subtool in tool.subtools"
:key="subtool.id"
class="tool-wrapper"
>
<!-- 二级工具按钮 -->
<div class="tool-button" @click="subtool.name && bus.emit(`toolbar_${subtool.name}`, params)">
<el-image class="tool-icon" :src="subtool.icon" fit="contain" />
</div>
<!-- 二级工具名称 (左侧淡入淡出) -->
<div class="tool-name sub-name">{{ subtool.label }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import * as Cesium from 'cesium';
import { useDrawTool } from '@/components/CesiumMap/mixins/useDrawTool';
import { useEventBus } from '@/components/CesiumMap/mixins/useEventBus';
import { useMeasureTool } from '@/components/CesiumMap/mixins/useMeasureTool';
import {
drawLocation,
drawPolyline,
drawPolygon,
drawCurvePolygon,
drawStraightArrow,
drawWideArrow,
drawAttackArrow,
drawDoubleArrow,
drawMeasureDistance,
drawMeasureArea
} from './baseDraw'
import {
drawWatersource,
drawWarehouse
} from './forestFireDraw'
// 工具栏图标
import baseDrawIcon from "@/assets/icons/toolbar_base_draw.png";
import forestDrawIcon from "@/assets/icons/toolbar_forest_draw.png";
import weatherIcon from "@/assets/icons/toolbar_weather.png";
import toolbarClearIcon from '@/assets/icons/toolbar_clear.png';
// 基础绘制工具图标
import toolbarLocationIcon from '@/assets/icons/toolbar_location.png';
import toolbarPolylineIcon from '@/assets/icons/toolbar_polyline.png';
import toolbarPolygonIcon from '@/assets/icons/toolbar_polygon.png';
import toolbarCurvePolygonIcon from '@/assets/icons/toolbar_curve_polygon.png';
import toolbarStraightArrowIcon from '@/assets/icons/toolbar_straight_arrow.png';
import toolbarWideArrowIcon from '@/assets/icons/toolbar_wide_arrow.png';
import toolbarAttackArrowIcon from '@/assets/icons/toolbar_attack_arrow.png';
import toolbarDoubleArrowIcon from '@/assets/icons/toolbar_double_arrow.png';
import toolbarMeasureDistanceIcon from '@/assets/icons/toolbar_measure_distance.png';
import toolbarMeasureAreaIcon from '@/assets/icons/toolbar_measure_area.png';
// 森防绘制工具图标
import toolbarWarehouseIcon from '@/assets/icons/toolbar_warehouse.png';
import toolbarWatersourceIcon from '@/assets/icons/toolbar_watersource.png';
const props = defineProps({
viewer: {
default: null
}
})
// 初始化地图实例
let viewer = null
let drawTool = null
let measureTool = null
let bus = null
let toolbarLayer = null
let primitiveList = []
let params = {}
const isOpen = ref(false)
const options = ref([
{
id: 1,
icon: baseDrawIcon,
label: '基础绘制',
subtools: [
{
id: 11,
name: 'location',
label: '位置',
icon: toolbarLocationIcon
}, {
id: 12,
name: 'polyline',
label: '线',
icon: toolbarPolylineIcon
}, {
id: 13,
name: 'polygon',
label: '面',
icon: toolbarPolygonIcon
}, {
id: 14,
name: 'curvePolygon',
label: '曲面',
icon: toolbarCurvePolygonIcon
}, {
id: 15,
name: 'straightArrow',
label: '直箭头',
icon: toolbarStraightArrowIcon
}, {
id: 16,
name: 'wideArrow',
label: '宽箭头',
icon: toolbarWideArrowIcon
}, {
id: 17,
name: 'attackArrow',
label: '攻击箭头',
icon: toolbarAttackArrowIcon
}, {
id: 18,
name: 'doubleArrow',
label: '双箭头',
icon: toolbarDoubleArrowIcon
}, {
id: 19,
name: 'measureDistance',
label: '测距',
icon: toolbarMeasureDistanceIcon
}, {
id: 110,
name: 'measureArea',
label: '测面',
icon: toolbarMeasureAreaIcon
}
],
},
{
id: 2,
icon: forestDrawIcon,
label: '森防绘制',
subtools: [
{
name: 'warehouse',
label: '仓库',
icon: toolbarWarehouseIcon
}, {
name: 'watersource',
label: '水源',
icon: toolbarWatersourceIcon
}
]
},
{
id: 3,
icon: weatherIcon,
label: '气象效果',
},
{
id: 4,
icon: toolbarClearIcon,
label: '清空绘制',
name: 'clear',
}
]);
// 清除工具栏上的所有绘制实体
const toolbarClear = () => {
if (!viewer || !toolbarLayer) return;
// 清除所有绘制的实体
toolbarLayer.entities.removeAll();
// 清除所有绘制的图元
for (let index = primitiveList.length - 1; index >= 0; index--) {
const p = primitiveList[index];
if(viewer.scene.primitives.contains(p)) {
viewer.scene.primitives.remove(p);
primitiveList.splice(index, 1);
}
}
measureTool?.clear();
// 清除当前测量
if (measureTool) {
measureTool.abort();
}
// 清除当前绘制
if (drawTool) {
drawTool.abort();
}
};
watch(() => props.viewer, (v) => {
if (v) {
viewer = v;
// 添加绘制图层
toolbarLayer = new Cesium.CustomDataSource('toolbarLayer');
viewer.dataSources.add(toolbarLayer);
drawTool = useDrawTool(viewer);
measureTool = useMeasureTool(viewer);
// 绑定事件
params = {
drawTool,
measureTool,
viewer,
toolbarLayer,
primitiveList,
}
bus = useEventBus(viewer);
bus.on('toolbar_location', drawLocation);
bus.on('toolbar_polyline', drawPolyline);
bus.on('toolbar_polygon', drawPolygon);
bus.on('toolbar_curvePolygon', drawCurvePolygon);
bus.on('toolbar_straightArrow', drawStraightArrow);
bus.on('toolbar_wideArrow', drawWideArrow);
bus.on('toolbar_attackArrow', drawAttackArrow);
bus.on('toolbar_doubleArrow', drawDoubleArrow);
bus.on('toolbar_measureDistance', drawMeasureDistance);
bus.on('toolbar_measureArea', drawMeasureArea);
bus.on('toolbar_watersource', drawWatersource);
bus.on('toolbar_warehouse', drawWarehouse);
bus.on('toolbar_clear', toolbarClear);
}
}, { immediate: true });
</script>
<style lang="scss" scoped>
.toolbar-container {
display: flex;
flex-direction: column;
align-items: center;
.toolbar-thumbnail {
position: absolute;
width: 40px;
height: 40px;
background-image: url(../../../../assets/icons/toolbar_thumbnail.png);
cursor: pointer;
z-index: 1000;
}
.toolbar {
display: flex;
flex-direction: column;
padding: 10px;
z-index: 0;
/* 通用工具按钮样式 */
.tool-wrapper {
position: relative;
width: 32px;
height: 0px;
background-color: rgba(7, 111, 111, 0.7);
margin-bottom: 2px;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
transition-duration: 0.8s;
&.open {
height: 40px;
opacity: 1;
}
/* 图标 */
.tool-button {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
.tool-icon {
width: 20px;
height: 20px;
}
}
/* 名称 */
.tool-name {
position: absolute;
writing-mode: vertical-rl;
letter-spacing: 2px;
color: #8cf8fe;
white-space: nowrap;
z-index: 3;
opacity: 0; /* 默认隐藏 */
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease; /* 动画持续时间和缓动函数 */
}
&:first-child {
border-radius: 16px 16px 0 0;
margin-top: 12px;
padding-top: 12px;
}
&:last-child {
border-radius: 0 0 16px 16px;
padding-bottom: 5px;
}
&:hover {
background-color: rgba($color: #FFD700, $alpha: .5);
}
}
}
/* 主菜单名称(右侧) */
.main-name {
left: 100%;
transform: translateX(0px); /* 初始位置 */
}
.tool-wrapper:hover > .main-name {
opacity: 1;
transform: translateX(4px); /* 移动到最终位置 */
transition-delay: 0.2s; /* 延迟 */
}
/* 子菜单容器样式 */
.submenu {
position: absolute;
right: 100%;
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease; /* 动画持续时间和缓动函数 */
}
/* 二级工具名称的定位 (左侧) */
.sub-name {
right: 100%;
transform: translateX(0); /* 初始位置 */
}
/* 当主 tool-wrapper 被 hover 且包含二级菜单时,显示二级菜单 */
.tool-wrapper:hover > .submenu {
pointer-events: all;
transition-delay: 0.1s; /* 延迟 */
& > .tool-wrapper {
height: 40px;
opacity: 1;
}
}
/* 当二级 tool-wrapper 被 hover 时,显示二级工具名称 */
/* 注意这里的选择器,因为二级名称在二级 tool-wrapper 内部 */
.submenu > .tool-wrapper:hover > .sub-name {
opacity: 1;
transform: translateX(-8px); /* 移动到最终位置 */
transition-delay: 0.2s; /* 延迟 */
}
}
</style>