提交 668ca2d6 authored 作者: Gorvey's avatar Gorvey

feat: update

上级 27eb1051
# 图片尺寸“是怎么转换”的
1. 原图尺寸
-
\ No newline at end of file
帮助我设计一个基于leafer-ui的画布编辑器
这是一个需要渲染一个底图,然后可以使用框选工具,在页面上框选一个区域,然后对这个区域进行一些标识,让用户使用时根据区域和信息进行业务互动
1. 请看src/api目录,有一个pageinfo.json,里面有底图,marklist.json是框选的数据
top,bottom是定位信息,里面的值是
\ No newline at end of file
......@@ -8,8 +8,20 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@leafer-in/editor": "^1.9.2",
"@leafer-in/export": "^1.9.2",
"@leafer-in/resize": "^1.9.2",
"@leafer-in/state": "^1.9.2",
"@leafer-in/view": "^1.9.2",
"@leafer-in/viewport": "^1.9.2",
"core-js": "^3.8.3",
"vue": "^2.6.14"
"dayjs": "^1.11.13",
"element-ui": "^2.15.14",
"konva": "^9.3.22",
"leafer-ui": "^1.9.2",
"lodash": "^4.17.21",
"vue": "^2.6.14",
"vue-konva": "^3.2.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
......
差异被折叠。
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<leafer></leafer>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
// import imageAnnotation from './pages/ai-pen-image-annotate/index.vue'
import leafer from './pages/leafer/index.vue'
export default {
name: 'App',
components: {
HelloWorld
leafer,
// imageAnnotation
}
}
</script>
......@@ -23,6 +23,6 @@ export default {
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
margin: 0;
}
</style>
差异被折叠。
{
"id": "68590e5fd004b1844225e304",
"bookName": "2025暑期测试教材v3(未铺码 转曲加出血).pdf",
"isbn": "",
"identifier": "3a61ff86bd3566abab0a8d43d0db44a8",
"pageID": 80261,
"PaperType": "Paper_Normal16KP",
"pageNumber": 1,
"pageTotal": 14,
"createTime": 1750666847,
"updateTime": 1750666847,
"url": "http://coresystem-dev.oss-cn-hangzhou.aliyuncs.com/sysFile/Paper_Normal16KP-80261.png",
"username": "",
"maskId": "68590e55d004b1844225e301",
"markCount": 45
}
\ No newline at end of file
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div class="annotate-list">
<detail-header class="p-x-16 m-b-24">我的批注</detail-header>
<el-scrollbar>
<div class="noData" v-if="!store.length">
<p class="nodata-txt">暂无批注</p>
</div>
<div class="annotate-item" v-for="v in store" :key="v.id">
<div class="flex items-center">
<div class="image-wrap">
<img :src="require(`../tools-image/${v.icon}.png`)" />
</div>
<div class="m-x-8">{{ v.label }}[{{ v.time }}]</div>
</div>
<div class="cursor-pointer" @click="delAnnotate(v)">
<i class="el-icon-delete text-14 gray-500"></i>
</div>
</div>
</el-scrollbar>
</div>
</template>
<script>
import { get } from 'lodash'
export default {
props: {
app: {
type: Object,
default: () => {}
}
},
data() {
return {}
},
computed: {
store() {
return get(this.app, 'store', [])
}
},
watch: {},
created() {},
mounted() {},
methods: {
delAnnotate(v) {
// eslint-disable-next-line vue/no-mutating-props
this.app.store = this.app.store.filter(item => item.id !== v.id)
this.app.saveStoreState()
}
}
}
</script>
<style lang="css" scoped>
.annotate-item {
display: flex;
align-items: center;
width: 100%;
justify-content: space-between;
}
.annotate-item + .annotate-item {
margin: 12px 0 0;
}
.annotate-list {
width: 320px;
height: calc(100vh - 50px - 40px);
background-color: #fff;
padding: 24px 0;
box-sizing: border-box;
}
.annotate-list .el-scrollbar {
height: calc(100vh - 50px - 40px - 60px - 20px);
}
.annotate-list :deep(.el-scrollbar .el-scrollbar__wrap) {
padding: 0 16px;
overflow-x: hidden;
}
.image-wrap {
width: 16px;
height: 16px;
}
.image-wrap img {
width: 100%;
height: 100%;
}
.noData {
text-align: center;
margin-top: 24px;
}
.noData .nodata-img {
width: 144px;
height: 100px;
}
.noData .nodata-txt {
color: #939699;
font-size: 14px;
}
</style>
<!--
* @Author: zengzhe
* @Date: 2024-08-19 09:29:54
* @LastEditors: zengzhe
* @LastEditTime: 2024-08-26 15:01:51
* @Description:
-->
<template>
<div v-show="configPanelVisible" class="config-panel">
<div
:class="{
active: isStrokeActive(v)
}"
@click="handleClickStroke(v)"
class="stroke-item"
v-for="v in strokeWidthList"
:key="v"
>
<div
:style="{
width: v + 'px',
height: v + 'px'
}"
class="stroke-item-inner"
></div>
</div>
<div
:class="{
active: isColorActive(v)
}"
@click="handleClickColor(v)"
class="color-item"
v-for="v in colorList"
:key="v"
>
<div
:style="{
background: v
}"
class="color-item-inner"
></div>
</div>
</div>
</template>
<script>
import { get } from 'lodash'
export default {
props: {
app: {
type: Object,
default: () => {}
}
},
data() {
return {
strokeWidthList: [1, 2, 4, 6, 8],
colorList: [
'#FA5151',
'#FFC300',
'#02C160',
'#0DAEFF',
'#6367F0',
'#000000',
'#FFFFFF'
]
}
},
computed: {
configPanelVisible() {
return (
get(this.app, 'activeTool', '') &&
get(this.app, 'activeTool.configPanelVisible', true)
)
}
},
watch: {},
created() {},
mounted() {},
methods: {
isStrokeActive(v) {
return get(this, 'app.panelConfig.strokeWidth') == v
},
isColorActive(v) {
return get(this, 'app.panelConfig.stroke') == v
},
handleClickStroke(v) {
// eslint-disable-next-line vue/no-mutating-props
this.app.panelConfig.strokeWidth = v
},
handleClickColor(v) {
// eslint-disable-next-line vue/no-mutating-props
this.app.panelConfig.stroke = v
}
}
}
</script>
<style lang="css" scoped>
.config-item {
width: 20px;
height: 20px;
}
.color-item-inner {
width: 20px;
height: 20px;
border-radius: 4px;
margin: 0 6px;
cursor: pointer;
}
.color-item.active .color-item-inner {
border: 1px solid #fff;
}
.stroke-item {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.stroke-item-inner {
background-color: #fff;
border-radius: 50%;
}
.stroke-item.active .stroke-item-inner {
border: 1px solid #fff;
background: var(--primary);
}
.config-panel {
user-select: none;
display: flex;
align-items: center;
height: 40px;
border-radius: 8px;
background: #303132;
position: fixed;
bottom: 64px;
left: 50%;
transform: translateX(-50%);
}
</style>
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="tools">
<div @click="undo" class="tool-item">
<el-tooltip effect="dark" content="回退" placement="top">
<img :src="require('../tools-image/tool-icon-1.png')" />
</el-tooltip>
</div>
<!-- <div @click="rotate('left')" class="tool-item">
<el-tooltip effect="dark" content="左旋" placement="top">
<img :src="require('../tools-image/tool-icon-2.png')" />
</el-tooltip>
</div>
<div @click="rotate('right')" class="tool-item">
<el-tooltip effect="dark" content="右旋" placement="top">
<img :src="require('../tools-image/tool-icon-3.png')" />
</el-tooltip>
</div> -->
<div class="divider"></div>
<div
:class="{ active: isActiveTool(v) }"
@click="onActive(v)"
class="tool-item"
v-for="v in toolGroups1"
:key="v.label"
>
<el-tooltip effect="dark" :content="v.label" placement="top">
<img :src="require(`../tools-image/${v.icon}.png`)" />
</el-tooltip>
</div>
<div class="divider"></div>
<div
:class="{ active: isActiveTool(v) }"
@click="onActive(v)"
class="tool-item"
v-for="v in toolGroups2"
:key="v.label"
>
<el-tooltip effect="dark" :content="v.label" placement="top">
<img :src="require(`../tools-image/${v.icon}.png`)" />
</el-tooltip>
</div>
<div class="divider"></div>
<div
:class="{ active: isActiveTool(v) }"
@click="onActive(v)"
class="tool-item"
v-for="v in toolGroups3"
:key="v.label"
>
<el-tooltip effect="dark" :content="v.label" placement="top">
<img :src="require(`../tools-image/${v.icon}.png`)" />
</el-tooltip>
</div>
</div>
</template>
<script>
import { toolGroups1, toolGroups2, toolGroups3 } from '../tools'
import { get } from 'lodash'
export default {
props: {
app: {
type: Object,
default: () => {}
}
},
data() {
return {
toolGroups1,
toolGroups2,
toolGroups3
}
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
rotate(val) {
let rotation = this.app.bgLayerConfig.rotation
if (val == 'right') {
//向右旋转
rotation += 90
} else {
// 向左旋转
if (rotation == 0 || rotation == 360) {
// 为了限制 rotation范围为0-360之间
// 不然一直向左 rotation会变为负数
rotation = 270
} else {
rotation += -90
}
}
this.app.setBgLayerRotate(rotation)
},
undo() {
this.app.undo()
},
isActiveTool(v) {
return get(this, 'app.activeTool.label') === v.label
},
onActive(v) {
// 再次选择,取消已选工具
if (this.app.activeTool == v) {
this.app.setActiveTool()
return
}
this.app.setActiveTool(v)
}
}
}
</script>
<style lang="css" scoped>
.tools {
display: flex;
align-items: center;
justify-content: center;
}
.tool-item {
width: 24px;
height: 24px;
transition: all 0.3s;
padding: 0 10px;
cursor: pointer;
}
.tool-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
.tool-item.active {
filter: invert(35%) sepia(93%) saturate(1246%) hue-rotate(188deg) brightness(97%) contrast(117%);
}
.divider {
width: 1px;
height: 16px;
background-color: #e1e3e5;
}
</style>
差异被折叠。
差异被折叠。
差异被折叠。
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="错红" transform="translate(-1022 -1046)">
<rect id="矩形_3230" data-name="矩形 3230" width="24" height="24" transform="translate(1022 1046)" fill="none"/>
<path id="路径_7315" data-name="路径 7315" d="M219.89,205.6l-6.574,6.574-6.574-6.574a.856.856,0,0,0-.587-.235.848.848,0,0,0-.822.822.859.859,0,0,0,.235.587l6.574,6.574-6.574,6.574a.8.8,0,0,0-.222.809.749.749,0,0,0,.574.587.837.837,0,0,0,.821-.222l6.574-6.574,6.574,6.574a.856.856,0,0,0,.587.235.848.848,0,0,0,.822-.822.859.859,0,0,0-.235-.587l-6.574-6.574,6.574-6.574a.8.8,0,0,0,.222-.809.752.752,0,0,0-.587-.587A.8.8,0,0,0,219.89,205.6Z" transform="translate(820.685 844.653)" fill="#fa5151"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="正确绿" transform="translate(-1022 -1046)">
<rect id="矩形_3230" data-name="矩形 3230" width="24" height="24" transform="translate(1022 1046)" fill="none"/>
<path id="路径_7316" data-name="路径 7316" d="M148.105,243.086l-5.368-5.368a.819.819,0,0,0-1.361.369.817.817,0,0,0,.217.8l6.512,6.512,13.025-13.025a.8.8,0,0,0,.217-.585.827.827,0,0,0-.255-.572.77.77,0,0,0-.56-.242.835.835,0,0,0-.572.229Z" transform="translate(882.652 820.024)" fill="#02c160"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="半对黄" transform="translate(-1022 -1046)">
<rect id="矩形_3230" data-name="矩形 3230" width="24" height="24" transform="translate(1022 1046)" fill="none"/>
<path id="联合_20" data-name="联合 20" d="M-1743.755-2354.089a.817.817,0,0,1-.216-.8.758.758,0,0,1,.572-.573.758.758,0,0,1,.788.2l5.368,5.368,6.462-6.476-2.225-2.225a.75.75,0,0,1,0-1.06.749.749,0,0,1,1.061,0l2.223,2.223,4.333-4.343a.83.83,0,0,1,.572-.229.771.771,0,0,1,.561.241.825.825,0,0,1,.255.573.8.8,0,0,1-.217.586l-4.338,4.337,1.914,1.914a.75.75,0,0,1,0,1.061.75.75,0,0,1-1.06,0l-1.914-1.915-7.626,7.626Z" transform="translate(2768 3413)" fill="#ffc300"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="疑问红" transform="translate(0)">
<rect id="矩形_3230" data-name="矩形 3230" width="24" height="24" transform="translate(0)" fill="none"/>
<path id="联合_19" data-name="联合 19" d="M-8377.047-1684.787a.986.986,0,0,1,.986-.987.986.986,0,0,1,.986.987.986.986,0,0,1-.986.987A.986.986,0,0,1-8377.047-1684.787Zm.953-2a.965.965,0,0,1-.965-.965v-.735a3.991,3.991,0,0,1,.27-1.735,3.082,3.082,0,0,1,1.246-1.362h-.024q.813-.629,1.372-1.118a5.551,5.551,0,0,0,.814-.839,2.781,2.781,0,0,0,.514-1.606,2.3,2.3,0,0,0-.2-1.061,3.763,3.763,0,0,0-.616-.915l-.049-.052a3.006,3.006,0,0,0-2.187-.836,2.564,2.564,0,0,0-2.094,1.014,4.577,4.577,0,0,0-.842,2.231.961.961,0,0,1-1.059.814.96.96,0,0,1-.848-1.072,6.771,6.771,0,0,1,.339-1.474,5.41,5.41,0,0,1,1.036-1.8,4.408,4.408,0,0,1,1.537-1.118,4.817,4.817,0,0,1,1.932-.384,4.993,4.993,0,0,1,3.585,1.3,4.437,4.437,0,0,1,1.42,3.352,4.69,4.69,0,0,1-.2,1.384,4.82,4.82,0,0,1-.523,1.151,6.676,6.676,0,0,1-1.025,1.165,15.557,15.557,0,0,1-1.675,1.327,1.686,1.686,0,0,0-.605.641,2.5,2.5,0,0,0-.14.967v.759a.965.965,0,0,1-.965.965Z" transform="translate(8387.768 1703.801)" fill="#fa5151"/>
</g>
</svg>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论