|
@@ -0,0 +1,422 @@
|
|
|
+<template>
|
|
|
+ <div class="map-layer" @mousemove.stop.prevent="move" @mouseup="upMove">
|
|
|
+ <input type="file" @change="imageChange" directory webkitdirectory multiple>
|
|
|
+ <div ref="map" class="map" v-once @mousemove="moveHandle" @mousedown="mapStartHandle"></div>
|
|
|
+ <div class="ctrls" :style="boxStyle" @mousedown.stop.prevent="startMove($event, 'move')"></div>
|
|
|
+ <div class="cctrls" v-if="box.tl">
|
|
|
+ <span class="tl" :style="{left: box.tl.x + 'px', top: box.tl.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'tl')"></span>
|
|
|
+ <span class="tc" :style="{left: box.tc.x + 'px', top: box.tc.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'tc')"></span>
|
|
|
+ <span class="tr" :style="{left: box.tr.x + 'px', top: box.tr.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'tr')"></span>
|
|
|
+ <span class="rc" :style="{left: box.rc.x + 'px', top: box.rc.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'rc')"></span>
|
|
|
+ <span class="lc" :style="{left: box.lc.x + 'px', top: box.lc.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'lc')"></span>
|
|
|
+ <span class="br" :style="{left: box.br.x + 'px', top: box.br.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'br')"></span>
|
|
|
+ <span class="bl" :style="{left: box.bl.x + 'px', top: box.bl.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'bl')"></span>
|
|
|
+ <span class="bc" :style="{left: box.bc.x + 'px', top: box.bc.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'scale', 'bc')"></span>
|
|
|
+ <span class="cc" :style="{left: box.cc.x + 'px', top: box.cc.y + 'px'}" @mousedown.prevent.stop="startMove($event, 'rotate')"></span>
|
|
|
+ </div>
|
|
|
+ <div class="box-info" v-if="boxPos.tl">
|
|
|
+ <div v-for="(item, key) in boxPos" :key="key">
|
|
|
+ <span>{{key}}</span>
|
|
|
+ <span>{{item}}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { initMap } from './core'
|
|
|
+import {
|
|
|
+ getCanvasToScreenPos,
|
|
|
+ getScreenToCanvasPos
|
|
|
+} from './util'
|
|
|
+
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ isHover: false,
|
|
|
+ box: {},
|
|
|
+ left: 0,
|
|
|
+ top: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async imageChange(e) {
|
|
|
+ let imagesArray = []
|
|
|
+ if (e.target.files.length > 0) {
|
|
|
+ const formatError = () => {
|
|
|
+ e.target.value = null
|
|
|
+ console.log(imagesXYZ)
|
|
|
+ alert('目录不规范 请上传 z/x/y.png 格式目录,且在最底级目录放置图片文件')
|
|
|
+ }
|
|
|
+ let imagesXYZ = {}
|
|
|
+ for (let file of e.target.files) {
|
|
|
+ let locals = file.webkitRelativePath.split(/[\\|//]/)
|
|
|
+ if (locals.length < 3) return formatError()
|
|
|
+ let current = imagesXYZ
|
|
|
+ for (let i = 0; i < locals.length; i++) {
|
|
|
+ let dir = locals[i]
|
|
|
+
|
|
|
+ if (i !== locals.length - 1) {
|
|
|
+ if (!current[dir]) {
|
|
|
+ current[dir] = i === locals.length - 2 ? [] : {}
|
|
|
+ }
|
|
|
+ current = current[dir]
|
|
|
+
|
|
|
+ if (i === locals.length - 3) {
|
|
|
+ current.key = 'z'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i === locals.length - 1) {
|
|
|
+ current.push(file)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ (function analysis (updateXYZ) {
|
|
|
+ if (updateXYZ.key === 'z') {
|
|
|
+ imagesXYZ = updateXYZ
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const names = Object.keys(updateXYZ).sort((a, b) => b - a)
|
|
|
+ names.forEach(key => {
|
|
|
+ if (key !== names[0]) {
|
|
|
+ delete updateXYZ[key]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ analysis(updateXYZ[names[0]])
|
|
|
+ })(imagesXYZ);
|
|
|
+
|
|
|
+ if (!(imagesXYZ && imagesXYZ.key === 'z' && !Array.isArray(imagesXYZ))) {
|
|
|
+ return formatError()
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let key in imagesXYZ) {
|
|
|
+ if (!Array.isArray(imagesXYZ[key]) && key !== 'key') {
|
|
|
+ return formatError()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ delete imagesXYZ.key
|
|
|
+
|
|
|
+ Object.keys(imagesXYZ).sort((a, b) => a - b).forEach(key => {
|
|
|
+ imagesArray.push(
|
|
|
+ imagesXYZ[key].sort((a, b) => parseInt(a.name) - parseInt(b))
|
|
|
+ )
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ imagesArray = [[e.target.files[0]]]
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ this.transfroms = []
|
|
|
+ this.args = {
|
|
|
+ draw: (ctx) => {
|
|
|
+ this.transfroms.forEach(transform => {
|
|
|
+ transform.forEach(({translate, scale, rotate, center}) => {
|
|
|
+ // 设置绘制颜色
|
|
|
+ center && ctx.translate(center.x, center.y)
|
|
|
+ translate && ctx.translate(translate.x, translate.y)
|
|
|
+ rotate && ctx.rotate(rotate * (Math.PI / 180))
|
|
|
+ scale && ctx.scale(scale[0], scale[1])
|
|
|
+ center && ctx.translate(-center.x, -center.y)
|
|
|
+ // if (center) {
|
|
|
+ // ctx.fillStyle = "geend";
|
|
|
+ // // 绘制成矩形
|
|
|
+ // ctx.fillRect(center.x, center.y, 100, 100);
|
|
|
+ // }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.updateBox(this.imgCanvas.imgBox)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ file: imagesArray,
|
|
|
+ lon: 113.59963069739054,
|
|
|
+ lat: 22.364821730960752,
|
|
|
+ translate: {x: 0, y: 0},
|
|
|
+ scale: [1, 1],
|
|
|
+ direction: 0
|
|
|
+ }
|
|
|
+ this.imgCanvas = await this.map.loadImage(this.args)
|
|
|
+ } catch(e) {
|
|
|
+ alert(e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ updateBox() {
|
|
|
+ const calcPos = pos => getCanvasToScreenPos(this.imgCanvas, pos)
|
|
|
+ this.box = {
|
|
|
+ tl: this.imgCanvas.posToReal(calcPos({x: 0, y: 0})),
|
|
|
+ tc: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width / 2, y: 0})),
|
|
|
+ tr: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width, y: 0})),
|
|
|
+ rc: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width, y: this.imgCanvas.imgData.height / 2})),
|
|
|
+ lc: this.imgCanvas.posToReal(calcPos({x: 0, y: this.imgCanvas.imgData.height / 2})),
|
|
|
+ br: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width, y: this.imgCanvas.imgData.height})),
|
|
|
+ bl: this.imgCanvas.posToReal(calcPos({x: 0, y: this.imgCanvas.imgData.height})),
|
|
|
+ bc: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width / 2, y: this.imgCanvas.imgData.height})),
|
|
|
+ cc: this.imgCanvas.posToReal(calcPos({x: this.imgCanvas.imgData.width / 2, y: this.imgCanvas.imgData.height / 2})),
|
|
|
+ }
|
|
|
+
|
|
|
+ let maxX = this.box.tl.x
|
|
|
+ let minX = this.box.tl.x
|
|
|
+ let maxY = this.box.tl.y
|
|
|
+ let minY = this.box.tl.y
|
|
|
+ Object.values(this.box).forEach(({x, y}) => {
|
|
|
+ x > maxX && (maxX = x)
|
|
|
+ y > maxY && (maxY = y)
|
|
|
+ x < minX && (minX = x)
|
|
|
+ y < minY && (minY = y)
|
|
|
+ })
|
|
|
+ this.box.width = Math.abs(maxX - minX)
|
|
|
+ this.box.height = Math.abs(maxY - minY)
|
|
|
+ },
|
|
|
+ mapStartHandle() {
|
|
|
+ this.mapDown = true
|
|
|
+ },
|
|
|
+ moveHandle(e) {
|
|
|
+ if (!this.imgCanvas || !this.imgCanvas.imgBox) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.moveing && this.oper) {
|
|
|
+ this.move(e)
|
|
|
+ } else {
|
|
|
+ this.mapDown && this.imgCanvas.imageLayer.refresh()
|
|
|
+ // const [start, end] = this.box
|
|
|
+
|
|
|
+ // this.isHover = e.clientX > start.x && e.clientX < end.x &&
|
|
|
+ // e.clientY > start.y && e.clientY < end.y
|
|
|
+ }
|
|
|
+ },
|
|
|
+ startMove(ev, oper, dir) {
|
|
|
+ this.startTransform = {
|
|
|
+ ...this.args
|
|
|
+ }
|
|
|
+ this.transfroms.push([])
|
|
|
+ this.moveing = true
|
|
|
+ this.oper = oper
|
|
|
+ this.dir = dir
|
|
|
+ this.startMovePos = {
|
|
|
+ x: ev.clientX,
|
|
|
+ y: ev.clientY
|
|
|
+ }
|
|
|
+ },
|
|
|
+ move(ev) {
|
|
|
+ if (!this.moveing) return;
|
|
|
+ const transfrom = this.transfroms[this.transfroms.length - 1]
|
|
|
+ const start = getScreenToCanvasPos(
|
|
|
+ this.imgCanvas,
|
|
|
+ this.startMovePos
|
|
|
+ )
|
|
|
+ const end = getScreenToCanvasPos(
|
|
|
+ this.imgCanvas,
|
|
|
+ { x: ev.clientX, y: ev.clientY }
|
|
|
+ )
|
|
|
+ const move = {
|
|
|
+ x: end.x - start.x,
|
|
|
+ y: end.y - start.y
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (this.oper === 'move') {
|
|
|
+ transfrom.push({ translate: move })
|
|
|
+ } else if (this.oper === 'scale'){
|
|
|
+ const width = this.imgCanvas.position[2]
|
|
|
+ const height = this.imgCanvas.position[3]
|
|
|
+ let xScale, yScale
|
|
|
+
|
|
|
+ switch(this.dir) {
|
|
|
+ case 'tl':
|
|
|
+ xScale = (width - move.x) / width
|
|
|
+ yScale = (height - move.y) / height
|
|
|
+ if (xScale > 0.1 && yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, yScale],
|
|
|
+ center: {x: this.imgCanvas.position[2], y: this.imgCanvas.position[3]}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'tc':
|
|
|
+ yScale = (height - move.y) / height
|
|
|
+ if (yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [1, yScale],
|
|
|
+ center: {x: 0, y: this.imgCanvas.position[3]}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'tr':
|
|
|
+ xScale = (width + move.x) / width
|
|
|
+ yScale = (height - move.y) / height
|
|
|
+ if (xScale > 0.1 && yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, yScale],
|
|
|
+ center: {x: 0, y: this.imgCanvas.position[3]}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'rc':
|
|
|
+ xScale = (width + move.x) / width
|
|
|
+ if (xScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, 1],
|
|
|
+ center: {x: 0, y: this.imgCanvas.position[3]}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'lc':
|
|
|
+ xScale = (width - move.x) / width
|
|
|
+ if (xScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, 1],
|
|
|
+ center: {x: this.imgCanvas.position[2], y: this.imgCanvas.position[3]}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'br':
|
|
|
+ xScale = (width + move.x) / width
|
|
|
+ yScale = (height + move.y) / height
|
|
|
+ if (xScale > 0.1 && yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, yScale],
|
|
|
+ center: {x: 0, y: 0}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'bl':
|
|
|
+ xScale = (width - move.x) / width
|
|
|
+ yScale = (height + move.y) / height
|
|
|
+ if (xScale > 0.1 && yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [xScale, yScale],
|
|
|
+ center: {x: this.imgCanvas.position[2], y: 0}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'bc':
|
|
|
+ yScale = (height + move.y) / height
|
|
|
+ if (yScale > 0.1) {
|
|
|
+ transfrom.push({
|
|
|
+ scale: [1, yScale],
|
|
|
+ center: {x: 0, y: 0}
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if (this.oper === 'rotate') {
|
|
|
+ let move = ev.clientX - this.startMovePos.x
|
|
|
+ let height = this.imgCanvas.position[3]
|
|
|
+ let width = this.imgCanvas.position[2]
|
|
|
+ let center = {x: width / 2, y: height / 2}
|
|
|
+
|
|
|
+ // let zrotate = transfrom.
|
|
|
+ transfrom.push({
|
|
|
+ rotate: move / 3,
|
|
|
+ center: center
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.startMovePos = {
|
|
|
+ x: ev.clientX,
|
|
|
+ y: ev.clientY
|
|
|
+ }
|
|
|
+ this.imgCanvas.imageLayer.refresh()
|
|
|
+ },
|
|
|
+ upMove() {
|
|
|
+ this.moveing = false
|
|
|
+ this.mapDown = false
|
|
|
+ this.oper = null
|
|
|
+ this.dir = null
|
|
|
+ this.startMovePos = null
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ boxStyle() {
|
|
|
+ if (this.box && Object.keys(this.box).length) {
|
|
|
+ const box = this.box
|
|
|
+ return {
|
|
|
+ width: box.width + 20 + 'px',
|
|
|
+ height: box.height + 20 + 'px',
|
|
|
+ left: box.cc.x + 'px',
|
|
|
+ top: box.cc.y + 'px'
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ boxPos() {
|
|
|
+ if (this.box && Object.keys(this.box).length) {
|
|
|
+ const ret = {}
|
|
|
+ for (let key in this.box) {
|
|
|
+ if (key !== 'width' && key !== 'height') {
|
|
|
+ ret[key] = this.map.screenToLatlan(this.box[key])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret
|
|
|
+ } else {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ window.appLoadedListener(() => {
|
|
|
+ this.map = initMap(this.$refs.map)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.map-layer,
|
|
|
+.map {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+input {
|
|
|
+ z-index: 99;
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.test {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 90;
|
|
|
+ width: 10px;
|
|
|
+ height: 20px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: gold;
|
|
|
+}
|
|
|
+
|
|
|
+.ctrls {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 9;
|
|
|
+ --margin: 10px;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+}
|
|
|
+
|
|
|
+.cctrls span {
|
|
|
+ z-index: 10;
|
|
|
+ position: absolute;
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: red;
|
|
|
+ cursor: pointer;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+}
|
|
|
+
|
|
|
+.box-info {
|
|
|
+ padding: 10px;
|
|
|
+ color: #fff;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+}
|
|
|
+</style>
|