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. static 关键字分析

    在java中static 关键字用途很广,可以修饰成员变量 方法 甚至类(静态内部类),这里不分析static 修饰类 static修饰的内容的运行顺序 java的程序执行之前有一个类的加载的过程,在 ...

  2. iphoneApp Fidder设置

    使用iphone 打开fidder 按照如上配置 安装完毕 然后访问计算机地址- 比如我的计算机ip地址是 192.168.2.10那么我需要在我的safari浏览器中输入192.168.2.10:8 ...

  3. JS数据结构与算法-栈结构

    一.认识栈结构 栈也是一种非常常见的数据结构,并且在程序中的应用非常广泛 数组 我们知道数组是一种线性结构,并且可以在数组的任意位置插入和删除数据. 但是有时候,我们为了实现某些功能,必须对这种任意性 ...

  4. 将Oracle数据库迁移到达梦数据库

    公司某产品在项目现场上常用到的数据库有Oracle和达梦. 做性能测试需要根据项目现场预埋大量的基础数据和业务数据,耗费时间.精力.故完成Oracle数据库的性能测试之后,采用直接将Oracle数据库 ...

  5. mybatis一对多映射分页的问题

    一对多可能会出现分页错误 条数不对的问题 解决方法: 将主表分页查询一次 SELECT aa.id,aa.name,bb.name FROM (SELECT * from tab1 ORDER BY ...

  6. WPF之XAML

    XAML是WPF技术中专门用于设计UI的语言.优点在于: (1)XAML可以设计出专业的UI和动画--好用. (2)简单易懂,易学. (3)设计师可以直接参与软件设计,随时沟通,无须二次转化--高效. ...

  7. 第2-3-2章 环境搭建-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5. 文件服务开发 5.1 环境搭建 5.1.1 数据库环境搭建 5.1.2 Nacos环境搭建 5.1.3 Nginx环境搭建 5.1.4 maven工程环境搭建 5. 文件服务开发 全套代码 ...

  8. 修改api-server支持的NodePort端口映射范围

    创建svc资源报错显示:provided port is not in the valid range. The range of valid ports is 30000-32767 k8s集群默认 ...

  9. laravel的_token传值 ; header中传_token

    laravel框架中只要是涉及到post传值都需要传 _token ,这是框架中为了防止crsf攻击所做的安全措施,那么我们用到ajax中的post 方式传值时,也需要在所传数据中添加一个_token ...

  10. mingw编译opencv动态链接库和静态链接库及使用方法

    前言 我一直不知道编译的过程以及cmake, make 这些工具是干什么的,所有抽时间研究了一下. 简单来说就是 cmake 是根据 CMakeLists.txt 用来生成 makefile文件的.而 ...