|
@@ -0,0 +1,377 @@
|
|
|
+<template>
|
|
|
+ <div class="myCanvas">
|
|
|
+ <div class="menu" v-show="showMenu" @mouseleave="showMenu = false" :style="{top: menuY + 'px', left: menuX + 'px'}">
|
|
|
+ <p v-show="!showDel" @click="addForm.show = true">添加标记点</p>
|
|
|
+ <!-- <p v-show="showDel" @click="editForm.show = true">修改此标记点</p> -->
|
|
|
+ <p v-show="showDel" @click="del">移除此标记点</p>
|
|
|
+ <p @click="showMenu = false">取消</p>
|
|
|
+ </div>
|
|
|
+ <div class="img">
|
|
|
+ <span v-for="(item, index) in marks" :key="index" :id="item.id" :style="{left: item.x + 'px', top: item.y + 'px'}">{{item.mark_num}}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 添加标记弹窗 -->
|
|
|
+ <el-dialog title="添加标记点" class="form" :visible.sync="addForm.show" width="30%" :before-close="() => {}" :show-close="false">
|
|
|
+ <el-input v-model="addForm.title" placeholder="请输入标记内容"></el-input>
|
|
|
+ <el-input v-model="addForm.content" style="margin-top: 20px" placeholder="请输入详细描述"></el-input>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="cancelAdd" size="small">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="add" size="small">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 修改标记弹窗 -->
|
|
|
+ <el-dialog title="修改标记点" class="form" :visible.sync="editForm.show" width="30%" :before-close="() => {}" :show-close="false">
|
|
|
+ <el-input v-model="editForm.title" placeholder="请输入标记内容"></el-input>
|
|
|
+ <el-input v-model="editForm.content" style="margin-top: 20px" placeholder="请输入详细描述"></el-input>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="cancelEdit" size="small">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="editForm.show = false" size="small">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ export default {
|
|
|
+ name: 'myCanvas',
|
|
|
+ props: ['url', 'datas', 'imgId'],
|
|
|
+ data (){
|
|
|
+ return {
|
|
|
+ marks: [],
|
|
|
+ box: {
|
|
|
+ width: 0,
|
|
|
+ height: 0
|
|
|
+ },
|
|
|
+ img: {
|
|
|
+ width: 0,
|
|
|
+ height: 0
|
|
|
+ },
|
|
|
+ scale: 1,
|
|
|
+ maxScale: 2,
|
|
|
+ minScale: 0.3,
|
|
|
+ scaleUnit: 0.1,
|
|
|
+ top: 0,
|
|
|
+ transTop: 0,
|
|
|
+ left: 0,
|
|
|
+ transLeft: 0,
|
|
|
+ transUnit: 2,
|
|
|
+ showMenu: false,
|
|
|
+ menuX: 0,
|
|
|
+ menuY: 0,
|
|
|
+ showDel: false,
|
|
|
+ addForm: {
|
|
|
+ show: false,
|
|
|
+ title: '',
|
|
|
+ content: ''
|
|
|
+ },
|
|
|
+ editForm: {
|
|
|
+ show: false,
|
|
|
+ title: '',
|
|
|
+ content: ''
|
|
|
+ },
|
|
|
+ currentMarkId: 0,
|
|
|
+ currentMArkPosX: 0,
|
|
|
+ currentMArkPosY: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted (){
|
|
|
+ // 获取图片地址
|
|
|
+ let timer = setInterval(() => {
|
|
|
+ if(this.url){
|
|
|
+ clearInterval(timer);
|
|
|
+ this.init();
|
|
|
+
|
|
|
+ // 标注
|
|
|
+ this.marks = this.datas;
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 初始化图片
|
|
|
+ init (){
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let box = document.querySelector('.myCanvas');
|
|
|
+ let img = document.querySelector('.img');
|
|
|
+ // 容器尺寸
|
|
|
+ this.box = {
|
|
|
+ width: box.clientWidth,
|
|
|
+ height: box.clientHeight
|
|
|
+ }
|
|
|
+
|
|
|
+ // 图片尺寸
|
|
|
+ let image = new Image();
|
|
|
+ image.onload = () => {
|
|
|
+ this.img = {
|
|
|
+ width: image.clientWidth,
|
|
|
+ height: image.clientHeight
|
|
|
+ }
|
|
|
+ this.defaultSize();
|
|
|
+ }
|
|
|
+ image.src = this.url;
|
|
|
+ img.appendChild(image);
|
|
|
+ box.appendChild(img);
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 控制图片默认尺寸
|
|
|
+ defaultSize (){
|
|
|
+ // 如果图片宽度大于容器宽度,缩小一半
|
|
|
+ console.log(this.img, this.box)
|
|
|
+ if(this.img.width > this.box.width){
|
|
|
+ this.img.width = this.img.width/2;
|
|
|
+ this.img.height = this.img.height/2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果高度大于容器高度,缩小一半
|
|
|
+ if(this.img.height > this.box.height){
|
|
|
+ this.img.width = this.img.width/2;
|
|
|
+ this.img.height = this.img.height/2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 位置
|
|
|
+ this.defaultPosition();
|
|
|
+ },
|
|
|
+ // 控制图片默认位置
|
|
|
+ defaultPosition (){
|
|
|
+ this.top = this.box.height/2 - this.img.height/2;
|
|
|
+ this.left = this.box.width/2 - this.img.width/2;
|
|
|
+
|
|
|
+ // 确认图片尺寸
|
|
|
+ this.$nextTick(() => {
|
|
|
+ document.querySelector('.img img').style.cssText = `width: ${this.img.width}px; height: ${this.img.height}px`;
|
|
|
+ })
|
|
|
+
|
|
|
+ // 设置图片
|
|
|
+ this.mouseSlide();
|
|
|
+ },
|
|
|
+ // 监听鼠标滚轮操作
|
|
|
+ mouseSlide (){
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let img = document.querySelector('.img');
|
|
|
+ img.onmouseover = () => {
|
|
|
+ img.onmousewheel = (e) => {
|
|
|
+ this.scale = e.deltaY > 0 ? this.scale - this.scaleUnit : this.scale + this.scaleUnit;
|
|
|
+
|
|
|
+ // 超大 && 超小
|
|
|
+ if(this.scale > this.maxScale){
|
|
|
+ this.scale = this.scale - this.scaleUnit;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(this.scale < this.minScale){
|
|
|
+ this.scale = this.scale + this.scaleUnit;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.set();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.draw();
|
|
|
+ },
|
|
|
+ // 监听拖拽操作
|
|
|
+ draw (){
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let img = document.querySelector('.img');
|
|
|
+
|
|
|
+ // 右键菜单
|
|
|
+ img.oncontextmenu = (e) => {
|
|
|
+ this.showDel = e.path[0].nodeName == 'SPAN' ? true : false;
|
|
|
+ if(this.showDel){
|
|
|
+ this.currentMarkId = e.target.id;
|
|
|
+ }
|
|
|
+ this.menuX = e.pageX - 220 - 20;
|
|
|
+ this.menuY = e.pageY - 50 - 20;
|
|
|
+ this.currentMArkPosX = e.offsetX;
|
|
|
+ this.currentMArkPosY = e.offsetY;
|
|
|
+ this.showMenu = true;
|
|
|
+ document.querySelector('.menu').focus();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 点击移动
|
|
|
+ img.onmousedown = (e) => {
|
|
|
+ if(this.showMenu){
|
|
|
+ this.showMenu = false;
|
|
|
+ }
|
|
|
+ e.preventDefault();
|
|
|
+ let cando = true;
|
|
|
+ if(e.button == 2){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ let x = e.screenX;
|
|
|
+ let y = e.screenY;
|
|
|
+
|
|
|
+ img.onmousemove = (ee) => {
|
|
|
+ if(!cando) return;
|
|
|
+ cando = false;
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ if(ee.screenX > x){
|
|
|
+ this.left += ee.screenX - x;
|
|
|
+ }else{
|
|
|
+ this.left -= x - ee.screenX;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(ee.screenY > y){
|
|
|
+ this.top += ee.screenY - y;
|
|
|
+ }else{
|
|
|
+ this.top -= y - ee.screenY;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.set();
|
|
|
+ cando = true;
|
|
|
+ x = ee.screenX;
|
|
|
+ y = ee.screenY;
|
|
|
+ }, 10);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 取消移动
|
|
|
+ img.onmouseup = () => {
|
|
|
+ img.onmousemove = null;
|
|
|
+ }
|
|
|
+ img.onmouseleave = () => {
|
|
|
+ img.onmousemove = null;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.set();
|
|
|
+ },
|
|
|
+ // 渲染图片
|
|
|
+ set (){
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let img = document.querySelector('.img');
|
|
|
+ img.style.cssText = `
|
|
|
+ transform: scale(${this.scale});
|
|
|
+ width: ${this.img.width}px;
|
|
|
+ height: ${this.img.height}px;
|
|
|
+ top: ${this.top}px;
|
|
|
+ left: ${this.left}px;
|
|
|
+ `;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 添加标记点
|
|
|
+ add (){
|
|
|
+ // 计算 num
|
|
|
+ let num = 0;
|
|
|
+ this.marks.map(item => {
|
|
|
+ if(item.mark_num >= num){
|
|
|
+ num = Number(item.mark_num);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ num++;
|
|
|
+
|
|
|
+ // 添加的数据
|
|
|
+ let data = {
|
|
|
+ user: JSON.parse(localStorage.getItem('designer_user')).id,
|
|
|
+ project: this.$route.query.id,
|
|
|
+ img: this.imgId,
|
|
|
+ title: this.addForm.title,
|
|
|
+ text: this.addForm.content,
|
|
|
+ num,
|
|
|
+ x: this.currentMArkPosX,
|
|
|
+ y: this.currentMArkPosY
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$ajax.post('/marks/add/', data).then(result => {
|
|
|
+ this.marks.push(result);
|
|
|
+ this.addForm = {
|
|
|
+ show: false,
|
|
|
+ title: '',
|
|
|
+ content: ''
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 取消添加标记点
|
|
|
+ cancelAdd (){
|
|
|
+ this.addForm = {
|
|
|
+ show: false,
|
|
|
+ title: '',
|
|
|
+ content: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 取消修改标记点
|
|
|
+ cancelEdit (){
|
|
|
+ this.addForm = {
|
|
|
+ show: false,
|
|
|
+ title: '',
|
|
|
+ content: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 删除标记点
|
|
|
+ del (){
|
|
|
+ this.$ajax.get(`/marks/del/?id=${this.currentMarkId}`).then(result => {
|
|
|
+ let index = 0;
|
|
|
+ this.marks.map((item, i) =>{
|
|
|
+ if(item.id == this.currentMarkId){
|
|
|
+ index = i;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.marks.splice(index, 1);
|
|
|
+ this.$message.success('移除成功');
|
|
|
+ this.showDel = false;
|
|
|
+ this.currentMarkId = 0;
|
|
|
+ this.showMenu = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+ @import url('../tools/common.less');
|
|
|
+ .myCanvas{
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ .menu{
|
|
|
+ width: 140px;
|
|
|
+ background: #ffffff;
|
|
|
+ box-shadow: 0px 3px 7px 0px rgba(0,0,0,0.0500);
|
|
|
+ border-radius: 5px;
|
|
|
+ overflow: hidden;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 999;
|
|
|
+ padding: 10px 0;
|
|
|
+ p{
|
|
|
+ padding: 10px 15px;
|
|
|
+ color: #797979;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ p:hover{
|
|
|
+ color: @color;
|
|
|
+ background: rgb(233, 239, 247);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .img{
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 10;
|
|
|
+ background: red;
|
|
|
+ transition: transform 0.3s;
|
|
|
+ span{
|
|
|
+ display: inline-block;
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ font-size: 12px;
|
|
|
+ background: #FD4F4F;
|
|
|
+ border-radius: 50%;
|
|
|
+ line-height: 30px;
|
|
|
+ text-align: center;
|
|
|
+ color: #ffffff;
|
|
|
+ position: absolute;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .form{
|
|
|
+ height: 80%;
|
|
|
+ padding-bottom: 20%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|