main.js

import Vue from 'vue'
import 'vueui-widgets/dist/index.css'
import VueUI from 'vueui-widgets'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.use(VueUI) Vue.config.productionTip = false new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

组件.vue

<template>
<div class="mycanvas-container">
<div class="left">
<p>展示视口</p>
<div class="myshow">
<img :src="mysrc" alt width="100%" />
<!-- <div id="canvas" style="width:100%;height:100%" class="mycanvas"></div> -->
</div>
</div>
<div class="center">
<p>操作视口</p>
<div class="myedit" ref="myedit" @mousedown.prevent="onMousedown" @mousemove="onMousemove" @contextmenu.prevent="">
<!-- <img src="@/assets/jia.svg" alt=""> -->
<img :src="mysrc" />
<span
class="myedit-span"
v-for="(item, index) in mydata"
:key="index"
:style="getSpanStyle(item)"
@contextmenu.prevent="onContextmenu(item, $event)"
></span>
<!-- <div id="canvas" style="width:100%;height:100%" class="mycanvas"></div> -->
</div>
</div>
<div class="right">
<img src alt class="mybutton" />
<input v-show="0" ref="file" type="file" class="mybutton" @change="onChange" />
<button class="mybutton" @click="selectFile">导入图片</button>
<button class="mybutton">新增标注</button>
<button class="mybutton">修改标注</button>
<button class="mybutton">删除</button>
<button class="mybutton">保存</button>
</div>
<div class="myMenu" v-show="mymenu.current" :style="mymenu.style">
<!-- <button @click="onRemoveItem">删除</button> -->
<ui-button type="primary" @click="onRemoveItem">删除</ui-button>
<ui-select></ui-select>
<select name="" id="">
<option value="1">ceshi</option>
</select>
</div>
</div>
</template> <script>
import jiaIcon from "./jia.svg";
export default {
data() {
return {
mysrc: "",
mydata: [],
mymenu: { current: null, style: { left: 0, top: 0 } }
};
},
mounted() {
document.addEventListener('mouseup', this.onMouseup)
},
beforeDestroy() {
document.removeEventListener('mouseup', this.onMouseup)
},
methods: {
getXY(e) {
let rect = this.$refs.myedit.getBoundingClientRect()
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
},
// 上传图片1
onChange(e) {
this.mysrc = window.URL.createObjectURL(e.target.files[0]);
e.target.value = ''
},
// 上传图片2,
selectFile() {
this.$refs.file.click();
},
onMousedown(e) {
this.mymenu.current = null
let { x, y } = this.getXY(e)
this.currentItem = { x, y, w: 0, h: 0, now: Date.now() }
this.startPos = { x, y }
this.mydata.push(this.currentItem)
},
onMousemove(e) {
if (!this.currentItem) return;
let { x, y } = this.getXY(e)
this.currentItem.w = Math.abs(x - this.startPos.x)
this.currentItem.h = Math.abs(y - this.startPos.y)
},
onMouseup(e) {
this.currentItem = this.startPos = null;
this.mydata = this.mydata.filter(_ => _.w > 10 && _.h > 10)
},
onContextmenu(item, e) {
this.mymenu = {
current: item,
style: {
top: e.clientY + 'px',
left: e.clientX + 'px'
}
}
},
onRemoveItem() {
this.mydata.splice(this.mydata.indexOf(this.mymenu.current), 1)
this.mymenu = { ...this.mymenu, current: null }
},
getSpanStyle(item) {
return {
width: `${item.w}px`,
height: `${item.h}px`,
top: `${item.y}px`,
left: `${item.x}px`
};
}
}
};
</script>
<style lang="less" scoped>
// 设置绘图样式1
body {
user-select: none;
} .myMenu {
position: fixed;
top: 400px;
left: 400px;
width: 100px;
padding: 8px 0;
background-color: #fff;
> * {
width: 100%;
}
} #canvas > div {
/* border: 2px solid green; */
position: absolute;
background-color: transparent;
} #canvas > div > span {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: simsun;
font-size: 9pt;
} // 设置绘图样式2 .mycanvas-container {
display: flex;
justify-content: center;
align-items: center; .left,
.center,
.right {
width: 300px;
// height: 520px;
margin: 20px; p {
text-align: center;
} .myshow,
.myedit {
width: 300px;
// height: 500px;
border: 1px solid #000;
position: relative;
.myedit-span {
position: absolute;
border: 1px dashed #fff;
background: url("./jia.svg") no-repeat center center;
background-size: contain;
} .mycanvas {
border: 1px solid pink;
position: absolute;
top: 0;
left: 0;
} img {
width: 100%;
}
}
} .right {
width: 150px;
display: flex;
justify-content: center;
align-items: left;
flex-direction: column; .mybutton {
margin-top: 20px;
display: block;
}
}
}
</style>

vue+div.canvas图像标注功能实现的更多相关文章

  1. 如何实现Canvas图像的拖拽、点击等操作

    上一篇Canvas的博文写完后,有位朋友希望能对Canvas绘制出来的图像进行点击.拖拽等操作,因为Canvas绘制出的图像能很好的美化.好像是想做炉石什么的游戏,我也没玩过. Canvas在我的理解 ...

  2. 【百度地图API】情人节求爱大作战——添加标注功能

    原文:[百度地图API]情人节求爱大作战--添加标注功能 任务描述: 2月2日是除夕,2月14立马来!即将到来的情人节,你想送TA一份什么礼物呢? 不如,在你们居住的地方,画个大大的桃心,表达你对TA ...

  3. OpenCV探索之路(二十五):制作简易的图像标注小工具

    搞图像深度学习的童鞋一定碰过图像数据标注的东西,当我们训练网络时需要训练集数据,但在网上又没有找到自己想要的数据集,这时候就考虑自己制作自己的数据集了,这时就需要对图像进行标注.图像标注是件很枯燥又很 ...

  4. 【开源】canvas图像裁剪、压缩、旋转

    前言 前段时间遇到了一个移动端对图像进行裁剪.压缩.旋转的需求. 考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子. 关于图像裁剪.压缩 在HTML5时代,canvas的功能已经非常强大了,可 ...

  5. Vue (二) --- Vue对象提供的属性功能

    --------------------------------------------不是井里没有水,而是你挖的不够深. 3. Vue对象提供的属性功能 3.1 过滤器 过滤器,就是vue允许开发者 ...

  6. vue 对象提供的属性功能、通过axio请求数据(2)

    1 Vue对象提供的属性功能 1.1 过滤器 过滤器,就是vue允许开发者自定义的文本格式化函数,可以使用在两个地方:输出内容和操作数据中. 1.1.1 使用Vue.filter()进行全局定义(全局 ...

  7. vue 使用canvas仿芝麻分信用表

    如图所示: 画布组件:dashboard.vue <template> <div> <canvas ref="canvas" v-if="c ...

  8. canvas图像裁剪、压缩、旋转

    转载于:http://www.cnblogs.com/dailc/p/7843204.html 前言 前段时间遇到了一个移动端对图像进行裁剪.压缩.旋转的需求.考虑到已有各轮子的契合度都不高,于是自己 ...

  9. vue教程2-07 微博评论功能

    vue教程2-07 微博评论功能 <!doctype html> <html> <head> <meta charset="utf-8"& ...

  10. PHP《将画布(canvas)图像保存成本地图片的方法》

    用PHP将网页上的Canvas图像保存到服务器上的方法 2014年6月27日 歪脖骇客 发表回复 8 在几年前HTML5还没有流行的时候,我们的项目经理曾经向我提出这样一个需求:让项目评审专家们在评审 ...

随机推荐

  1. C++ 不知树系列之初识树(树的邻接矩阵、双亲孩子表示法……)

    1. 前言 树是一种很重要的数据结构,最初对数据结构的定义就是指对树和图的研究,后来才广义化了数据结构这个概念.从而可看出树和图在数结构这一研究领域的重要性. 树和图重要的原因是,它让计算机能建模出现 ...

  2. Linux网络管理命令

    Linux网络管理命令 ifconfig 用于配置网卡ip地址信息等网络参数或显示网络接口状态,类似于windows的ipconfig命令. 可以用这个工具来临时性的配置网卡的IP地址.掩码.广播地址 ...

  3. nodered获取简单的时间

    1.添加simpletime 的节点 2. 添加一个inject节点用来每1s循环获取当点的信息 3.添加一个函数节点对simpletime发来的msg进行解析 var payload=msg;var ...

  4. Windows操作系统搭建Lsky Pro

    写在前面 本文主要介绍在Windows下部署兰空图床,以及安装过程, 非Windows系统可以参考本文章的安装流程,结合自己系统版本进行部署 图床用处 图床在日常的用处非常广泛,尤其对于经常写博客的人 ...

  5. 1.python基础使用

    1.git简介 git是一个免费的开源的分布式版本控制系统,可以快速高效的处理从小型到大型项目的所有事务 在实际工作中可以保留项目的所有版本,可以快速的实现版本的回滚和修改 git整体可以分为4个区域 ...

  6. ClickHouse(10)ClickHouse合并树MergeTree家族表引擎之ReplacingMergeTree详细解析

    目录 建表语法 数据处理策略 资料分享 参考文章 MergeTree拥有主键,但是它的主键却没有唯一键的约束.这意味着即便多行数据的主键相同,它们还是能够被正常写入.在某些使用场合,用户并不希望数据表 ...

  7. 2022春每日一题:Day 14

    题目:字符串归类 发现字符串长度总数不大,因此把每个字符串有的字母分离,存放到桶中,再枚举合并即可,时间复杂度O(len) 赛时代码: #include <cstdio> #include ...

  8. Git+Github协作开发流程

    采用合作开发者的方式进行协作开发,下面以zlcook和zlserver合作开发iqas-ios-record项目为例进行讲解,zlcook为项目创建者,zlserver为项目参与者.协作开发步骤如下: ...

  9. Go语言核心36讲47

    你好,我是郝林,今天我们继续分享使用os包中的API. 我们在上一篇文章中.从"os.File类型都实现了哪些io包中的接口"这一问题出发,介绍了一系列的相关内容.今天我们继续围绕 ...

  10. Armv8之Execution State 和 Exception Level(一)

    @ 目录 1. 典型的Exception Level使用模型 2.异常相关术语 3. Execution State 3.1 两种Execution State 3.2 决定Execution Sta ...