<template>
|
<div class="position-box pr p10">
|
<div class="position-box" id="drawMap" ref="drawMap"></div>
|
<b-button-group vertical class="zoomBtnGroup" size="sm">
|
<b-button variant="primary" @click="zoomBig" title="放大"><span class="fa fa-plus"></span></b-button>
|
<div class="border-top"></div>
|
<b-button variant="primary" @click="pantoHome" title="重置位置" ><span class="fa fa-circle"></span></b-button>
|
<div class="border-top"></div>
|
<b-button variant="primary" @click="zoomSmall" title="缩小"><span class="fa fa-minus"></span></b-button>
|
</b-button-group>
|
</div>
|
</template>
|
<script>
|
import Two from 'two.js'
|
// import { isHasImgFn } from '@/components/common/util.js'
|
import { addEvent, drag, addWheel } from './svgDIYMapEvent.js'
|
const xmlns = 'http://www.w3.org/2000/svg'
|
export default {
|
name: 'svgDIYMapModel',
|
props: {
|
mapInfo: {
|
default: null,
|
type: Object
|
},
|
iconArr: {
|
default: null,
|
type: Array
|
},
|
iconSize: {
|
default: () => {
|
return { width: 50, height: 50 }
|
},
|
type: Object
|
},
|
delIconSize: {
|
default: 20,
|
type: Number
|
},
|
isIconEdit: {
|
default: false,
|
type: Boolean
|
},
|
alarmDeviceList: {
|
default: null,
|
type: Array
|
},
|
unonlineDeviceList: {
|
default: null,
|
type: Array
|
}
|
},
|
data() {
|
return {
|
svgMap: null, // 地图对象
|
mapLayer: null, // 图层
|
mapImg: null, // 图层 图片
|
iconLayer: null, // 图标层
|
iconObjArr: [] // 地图对象
|
}
|
},
|
computed: {
|
mapUrl() {
|
return this.mapInfo && this.mapInfo.url ? this.mapInfo.url : ''
|
},
|
imgSize() {
|
return this.mapInfo && this.mapInfo.revJson
|
? JSON.parse(this.mapInfo.revJson)
|
: null
|
}
|
},
|
methods: {
|
svgMapInit() {
|
this.$refs.drawMap.innerHTML = ''
|
/* 图片加载开启loding */
|
this.$store.commit('HANDLE_LOADING_OPEN')
|
// 创建two对象
|
const params = {
|
width: this.$refs.drawMap.scrollWidth,
|
height: this.$refs.drawMap.scrollHeight
|
}
|
/* 初始化地图图片大小 */
|
const imgH =
|
this.imgSize && this.imgSize.height ? this.imgSize.height : '0'
|
const imgW = this.imgSize && this.imgSize.width ? this.imgSize.width : '0'
|
/* 创建地图对象 */
|
this.svgMap = new Two(params).appendTo(this.$refs.drawMap)
|
const xmlns = 'http://www.w3.org/2000/svg'
|
this.mapImg = document.createElementNS(xmlns, 'image')
|
this.mapImg.href.baseVal = 'httpImage/' + this.mapUrl
|
this.mapImg.setAttributeNS(null, 'x', 0)
|
this.mapImg.setAttributeNS(null, 'y', 0)
|
this.mapImg.setAttributeNS(null, 'height', imgH)
|
this.mapImg.setAttributeNS(null, 'width', imgW)
|
// 创建地图 图层
|
this.mapLayer = this.svgMap.makeGroup()
|
|
// 创建地图 图标层
|
this.iconLayer = this.svgMap.makeGroup()
|
// this.mapLayer.center()
|
// this.iconLayer.center()
|
this.svgMap.update()
|
document
|
.querySelector('#' + this.mapLayer._renderer.elem.id)
|
.appendChild(this.mapImg)
|
document.querySelector(
|
'#' + this.mapLayer._renderer.elem.id
|
).style.cursor =
|
'all-scroll'
|
// this.svgMap.update()
|
/* 图片加载成功后 关闭loding */
|
this.mapImg.onload = e => {
|
this.$store.commit('HANDLE_LOADING_CLOSE')
|
}
|
// 添加滚轮放大事件
|
addWheel(document.querySelector('#drawMap svg'), dir => {
|
if (dir) {
|
// 向下 transform: scale(1.2);
|
this.zoomSmall()
|
} else {
|
// 向上
|
this.zoomBig()
|
}
|
})
|
// 添加拖拽事件
|
drag(this.mapLayer, '#drawMap svg', json => {
|
this.mapLayer.translation.set(json.x, json.y)
|
this.iconLayer.translation.set(json.x, json.y)
|
this.svgMap.update()
|
this.$emit('dragMapLayerFn', json)
|
})
|
},
|
/* 放大 */
|
zoomBig() {
|
// 改变图层比例
|
this.mapLayer.scale += 0.1
|
// 改变图标位置
|
this.iconObjArr.map(iteam => {
|
iteam.translation.set(
|
iteam.x * this.mapLayer.scale - this.iconSize.width / 2,
|
iteam.y * this.mapLayer.scale - this.iconSize.height / 2
|
)
|
})
|
this.svgMap.update()
|
this.$emit('zoomMapLayerFn', this.mapLayer.scale)
|
},
|
/* 缩小 */
|
zoomSmall() {
|
if (this.mapLayer.scale > 0.3) {
|
this.mapLayer.scale -= 0.1
|
this.iconObjArr.map(iteam => {
|
iteam.translation.set(
|
iteam.x * this.mapLayer.scale - this.iconSize.width / 2,
|
iteam.y * this.mapLayer.scale - this.iconSize.height / 2
|
)
|
})
|
this.svgMap.update()
|
this.$emit('zoomMapLayerFn', this.mapLayer.scale)
|
} else {
|
this.$notify({
|
group: 'foo',
|
type: 'warn',
|
title: '抱歉,真的不能再小了',
|
text: '地图已经缩到最小,不能再小了'
|
})
|
}
|
},
|
pantoHome() {
|
this.mapLayer.scale = 1
|
this.iconObjArr.map(iteam => {
|
iteam.translation.set(
|
iteam.x * 1 - this.iconSize.width / 2,
|
iteam.y * 1 - this.iconSize.height / 2
|
)
|
})
|
this.mapLayer.translation.set(0, 0)
|
this.iconLayer.translation.set(0, 0)
|
this.svgMap.update()
|
},
|
|
/* 绘制icon */
|
iconListInit(arr) {
|
if (
|
arr &&
|
this.svgMap &&
|
this.mapLayer &&
|
this.mapImg &&
|
this.iconLayer
|
) {
|
document.querySelector(
|
'#' + this.iconLayer._renderer.elem.id
|
).innerHTML =
|
''
|
for (let iteam of arr) {
|
this.drawIcon(iteam)
|
}
|
}
|
},
|
drawIcon(json) {
|
if (!json || !json.position) {
|
return false
|
}
|
|
const oIcon = document.createElementNS(xmlns, 'image')
|
oIcon.href.baseVal =
|
json && json.icon
|
? '/static/img/map/' + json.icon + '_online' + '.png'
|
: '/static/img/map/camera_device.png'
|
oIcon.setAttributeNS(null, 'x', 0)
|
oIcon.setAttributeNS(
|
null,
|
'y',
|
-this.iconSize.height / 2
|
) /* 设置图标底部中心 */
|
oIcon.setAttributeNS(null, 'height', this.iconSize.height)
|
oIcon.setAttributeNS(null, 'width', this.iconSize.width)
|
|
const position =
|
json && json.position ? JSON.parse(json.position) : { x: 0, y: 0 }
|
const iconGroup = this.svgMap.makeGroup(oIcon)
|
/* 保存部分对象 */
|
iconGroup.data = json
|
iconGroup.x = position.x
|
iconGroup.y = position.y
|
iconGroup.state = '_online' // 用于标记状态 _unonline _online _alarm
|
iconGroup.translation.set(
|
position.x * this.mapLayer.scale - this.iconSize.width / 2,
|
position.y * this.mapLayer.scale - this.iconSize.height / 2
|
)
|
|
this.iconLayer.add(iconGroup)
|
this.iconObjArr.push(iconGroup)
|
this.svgMap.update()
|
|
document
|
.querySelector('#' + iconGroup._renderer.elem.id)
|
.appendChild(oIcon)
|
document.querySelector('#' + iconGroup._renderer.elem.id).style.cursor =
|
'pointer'
|
/* 编辑模式 */
|
if (this.isIconEdit) {
|
/* let title = new Two.Text(`${json.deviceName}(${json.cameraType})`, 0, 0, 'normal')
|
iconGroup.add(title) */
|
// 编辑模式 添加删除
|
const oDelIcon = document.createElementNS(xmlns, 'image')
|
oDelIcon.href.baseVal = '/static/img/map/mapDel.png'
|
oDelIcon.setAttributeNS(
|
null,
|
'x',
|
this.iconSize.width - this.delIconSize
|
)
|
oDelIcon.setAttributeNS(null, 'y', -this.iconSize.height / 2)
|
oDelIcon.setAttributeNS(null, 'height', this.delIconSize)
|
oDelIcon.setAttributeNS(null, 'width', this.delIconSize)
|
document
|
.querySelector('#' + iconGroup._renderer.elem.id)
|
.appendChild(oDelIcon)
|
// 编辑模式 添加del事件
|
addEvent(oDelIcon, 'click', e => {
|
this.$emit('iconIteamDelFn', {
|
data: iconGroup.data,
|
id: iconGroup.data.id
|
})
|
})
|
// 编辑模式 添加拖拽事件
|
drag(iconGroup, '', json => {
|
// iconGroup.translation.set(json.x, json.y)
|
// this.svgMap.update()
|
this.$emit('iconIteamDragFn', {
|
x: (json.x + this.iconSize.width / 2) / this.mapLayer.scale,
|
y: (json.y + this.iconSize.height / 2) / this.mapLayer.scale,
|
iconGroup,
|
data: iconGroup.data
|
})
|
})
|
} else {
|
/* 非编辑模式 */
|
// 添加点击事件
|
addEvent(
|
document.querySelector('#' + iconGroup._renderer.elem.id),
|
'click',
|
e => {
|
this.$emit('iconIteamFn', iconGroup)
|
}
|
)
|
}
|
},
|
|
initIcon(iteam) {
|
if (!iteam) {
|
return false
|
}
|
let unonlineDevice = []
|
if (this.unonlineDeviceList) {
|
unonlineDevice = this.unonlineDeviceList.map(iteam => iteam.deviceId)
|
}
|
const id = iteam.data && iteam.data.id ? iteam.data.id : null
|
const iCon = document.querySelector('#' + iteam._renderer.elem.id)
|
if (this.unonlineDeviceList && unonlineDevice.indexOf(id) !== -1) {
|
if (iCon && iteam.state !== '_unonline') {
|
iteam.state = '_unonline'
|
const iConiTeam = iCon.getElementsByTagNameNS(xmlns, 'image')[0]
|
iConiTeam.setAttributeNS(
|
null,
|
'href',
|
iteam.data && iteam.data.icon
|
? '/static/img/map/' + iteam.data.icon + '.png'
|
: '/static/img/map/camera_device.png'
|
)
|
}
|
} else {
|
if (iCon && iteam.state !== '_online') {
|
iteam.state = '_online'
|
const iConiTeam = iCon.getElementsByTagNameNS(xmlns, 'image')[0]
|
iConiTeam.setAttributeNS(
|
null,
|
'href',
|
iteam.data && iteam.data.icon
|
? '/static/img/map/' + iteam.data.icon + '_online' + '.png'
|
: '/static/img/map/camera_device.png'
|
)
|
}
|
}
|
}
|
},
|
created() {},
|
mounted() {
|
// this.svgMapInit()
|
},
|
watch: {
|
mapInfo: {
|
handler(newVal, oldVal) {
|
this.$nextTick(() => {
|
this.svgMapInit()
|
})
|
},
|
deep: true,
|
immediate: true
|
},
|
iconArr: {
|
handler(newVal, oldVal) {
|
if (newVal && newVal !== oldVal) {
|
this.iconListInit(newVal)
|
}
|
},
|
deep: true,
|
immediate: true
|
},
|
alarmDeviceList: {
|
handler(newVal, oldVal) {
|
if (newVal && newVal !== oldVal) {
|
const alarmDeviceIds = newVal.map(iteam => iteam.deviceId)
|
this.iconObjArr.map(iteam => {
|
const id = iteam.data && iteam.data.id ? iteam.data.id : null
|
const iCon = document.querySelector('#' + iteam._renderer.elem.id)
|
if (alarmDeviceIds.indexOf(id) !== -1) {
|
if (iCon && iteam.state !== '_alarm') {
|
iteam.state = '_alarm'
|
const iConiTeam = iCon.getElementsByTagNameNS(xmlns, 'image')[0]
|
iConiTeam.setAttributeNS(
|
null,
|
'href',
|
iteam.data && iteam.data.icon
|
? '/static/img/map/' + iteam.data.icon + '_alarm' + '.png'
|
: '/static/img/map/camera_device.png'
|
)
|
}
|
} else {
|
this.initIcon(iteam)
|
}
|
})
|
}
|
},
|
// deep: true,
|
immediate: true
|
}
|
}
|
}
|
</script>
|
<style scoped lang="scss">
|
.position-box {
|
// position: absolute;
|
position: relative;
|
overflow: hidden;
|
height: 100%;
|
width: 100%;
|
background: #fff;
|
}
|
.zoomBtnGroup {
|
position: absolute;
|
bottom: 10px;
|
right: 10px;
|
}
|
g img {
|
-moz-user-select: none;
|
-webkit-user-select: none;
|
user-select: none;
|
}
|
</style>
|