<template>
<div class="wh100 relative" id="elrdID">
<!-- 图片热区 -->
<img id="mapImg" style="opacity: 0.4" class="wh100" src="@/assets/images/mapImg.png" border="0" usemap="#planetmap" alt="Planets" />
<map v-if="state.render" name="planetmap" id="planetmap">
<area v-for="(item, index) in allPathData.allPath" shape="poly" :coords="coordsHandler(item)" href="test.html" @click.prevent="mapImgClick($event)" />
</map>
<!-- 开发环境下,绘制图片热区 -->
<canvas v-if="state.showCanvas" class="wh100 absolute" id="canvas" style="left: 0; top: 0">你的浏览器还不支持canvas</canvas>
<div v-if="state.showCanvas" class="absolute canvasBtn">
<G-button class="ml15" size="small" @click="getCoord">获取点坐标</G-button>
<G-button class="ml15" size="small" @click="exportCoords">导出所有点坐标</G-button>
<G-button class="ml15" size="small" @click="startPath">开始绘制多边形</G-button>
<G-button class="ml15" size="small" @click="closePath">保存本次形状</G-button>
<G-button class="ml15" size="small" @click="exportJSON">导出全部路径</G-button>
<G-button class="ml15" size="small" @click="clearPath">清空</G-button>
</div>
</div>
</template>
<script setup>
import * as elementResizeDetector from 'element-resize-detector'
import { reactive, watch, nextTick, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import allPathData from './path.json'
const state = reactive({
canvas: null,
context: null,
onpath: [],
// downCurrXY: '',
// upCurrXY: '',
showCanvas: false,
allPath: [],
currXY: '',
render: true,
mapImg: null,
initMIW: 1,
initMIH: 1,
allPathData: {},
coords: []
})
onMounted(() => {
let elrd = elementResizeDetector()
state.mapImg = document.getElementById('mapImg')
state.initMIW = state.mapImg.width
state.initMIH = state.mapImg.height
// 监听元素宽高
elrd.listenTo(document.getElementById('elrdID'), function (e) {
if (state.mapImg) {
state.render = false
nextTick(() => {
state.render = true
})
}
})
// 开发环境初始化canvas
if (process.env.NODE_ENV == 'development') {
state.showCanvas = true
nextTick(() => {
initCanvas()
})
}
})
function initCanvas() {
state.canvas = document.getElementById('canvas')
state.canvas.width = state.mapImg.width
state.canvas.height = state.mapImg.height
state.context = canvas.getContext('2d')
state.context.strokeStyle = 'orange'
state.context.lineWidth = selfAdaption(2)
// canvas测试坐标↓↓↓↓↓↓
state.context.beginPath()
let sdd = '579.9998214190047,299,594.0005714591854,330,713.0069468007215,352,741.0084468810829,274,615.0016965194565,254,578.999767844706,300'
let arr = sdd.split(',')
let { w, h } = { ...getProportion() }
arr.forEach((item, index) => {
if (index == 0) {
state.context.moveTo(arr[0] * w, arr[1] * h)
} else if (index % 2 == 0) {
state.context.lineTo(item * w, arr[index + 1] * h)
}
})
state.context.stroke()
// ↑↑↑↑↑↑↑↑↑↑↑
}
function getProportion() {
let w = state.mapImg ? state.mapImg.width / allPathData.imgInitWH.width : 1
let h = state.mapImg ? state.mapImg.height / allPathData.imgInitWH.height : 1
return { w, h }
}
function getCoord() {
state.canvas.removeEventListener('click', () => {})
state.canvas.addEventListener('click', e => {
let rect = canvas.getBoundingClientRect()
var x = (event.clientX - rect.left) * (state.canvas.width / rect.width)
var y = (event.clientY - rect.top) * (state.canvas.height / rect.height)
console.log('当前canvas坐标:', x, y)
state.coords.push({ x, y })
})
}
function exportCoords() {
exportHandler(state.coords)
}
function startPath() {
state.canvas.removeEventListener('click', () => {})
ElMessage({
message: '开始绘制多边形',
type: 'success'
})
state.context.beginPath()
state.onpath = []
state.canvas.addEventListener('click', e => {
let rect = canvas.getBoundingClientRect()
var x = (event.clientX - rect.left) * (state.canvas.width / rect.width)
var y = (event.clientY - rect.top) * (state.canvas.height / rect.height)
console.log('当前canvas坐标:', x, y)
if (state.currXY == '') {
state.context.moveTo(x, y)
state.onpath.push(x, y)
} else {
let xy = state.currXY.split('|')
state.context.moveTo(Number(xy[0]), Number(xy[1]))
state.context.lineTo(x, y)
state.context.stroke()
state.onpath.push(x, y)
}
state.currXY = x + '|' + y
})
}
function closePath() {
ElMessage({
message: '已保存本次闭合路径',
type: 'success'
})
state.allPath.push(state.onpath)
state.currXY = ''
state.onpath = []
state.canvas.removeEventListener('click', () => {})
// console.log(state.allPath, 'state.allPath')
}
function clearPath() {
state.allPath = []
state.onpath = []
state.context.clearRect(0, 0, state.canvas.width, state.canvas.height)
}
function exportJSON() {
let params = {
imgInitWH: {
width: state.mapImg.width,
height: state.mapImg.height
},
allPath: state.allPath
}
exportHandler(params)
}
function exportHandler(params) {
var data = JSON.stringify(params)
//encodeURIComponent解决中文乱码
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(data)
//通过创建a标签实现
let link = document.createElement('a')
link.href = uri
//对下载的文件命名
link.download = 'hotZonePath.json'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// 坐标自适应
function coordsHandler(strArr) {
if (strArr && strArr.length > 0) {
let numw = state.mapImg ? state.mapImg.width / state.initMIW : 1
let numh = state.mapImg ? state.mapImg.height / state.initMIH : 1
let { w, h } = { ...getProportion() }
let arr = strArr.map((item, index) => {
if (index % 2 == 0) {
return Number(item) * w
} else {
return Number(item) * h
}
})
return arr.join()
}
return ''
}
function mapImgClick(e) {
let str = `图片热区--当前坐标 ${e.offsetX},${e.offsetY}`
console.log(str)
}
function selfAdaption(res) {
let clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
if (!clientWidth) return
let fontSize = clientWidth / 1920
return res * fontSize
}
</script>
<style lang="less" scoped>
.canvasBtn {
right: 0;
top: 0;
}
</style>