因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器
自我介绍
本猫生活在东北的一个四线小城市,目前在一家小单位任职前端工程师的职位。早八晚五,生活充实,好不快活!
噩耗
Ctrl+c
,Ctrl+v
。Ctrl+c
,Ctrl+v
。新的一天开始了,本猫正在努力的工作着。看着旁边的美工小妹妹,我的口水止不住的往下流,别误会,是因为公司没有几个人,所以我们每天中午都在一起吃饭,而且我本来身为一个吃货,想到午饭就会流口水,很合理吧。
正当我沉迷在幻想之际,手机的一声震动把我拽回到现实。
“来我办公室一趟!”
竟然是老板给我发的消息!!!
难不成是我每天辛苦的工作被他发现了?要给我涨工资?
我一溜烟的从工位冲了出去,直奔老板的办公室。
这一路上我想了很多:想我这么多年的辛劳付出终于达到了回报、想我迎娶白富美的现场何其壮观、想我出任ceo
之后回村又是多么的风光......
终于在三秒之后,我来到了老板的办公室,见到了我最敬爱的老板。
“猫啊,听说你最近表现不错”
还没等我说话,老板又接着说到:
“咱们公司最近新接了一个项目要交给你完成,你有没有信心啊?”
我拍了拍胸脯:
“必须的!老板您说让我做什么我就做什么”
然后老板对我展开了需求攻势:
“巴拉巴拉,如此如此,这般这般,巴巴拉拉加班拉拉巴巴”
“什么?加班!”
其实老板说了那么多我是左耳听,右耳冒,但是加班这两个重重的砸在了我心上。我突然感觉一股热流冲到了头顶,双腿也止不住的颤抖,随即我双手用力的支撑在了老板的办公桌上,才勉强地站稳脚跟。
老板似乎也看出了我的不适,继续说道:
“小猫啊!你年龄这么小,正是应该努力奋斗的时候,我像你这么大的时候每天只睡十分钟,才有了今天的成就。巴拉巴拉。。。。”
听着老板的经历,我不由得留下了感动的泪水。原来老板是如此的器重我,耐心的劝导我只为了让我成长,想到我刚才还想向老板提涨工资的事,我的脸唰的一下就红了。我赶紧向老板鞠了一躬,猫着腰往办公室外面跑。
“谢谢老板关心,我一定完美完成任务!”
“公司就你一个前端,一定得好好做啊!”
随着老板的声音越来越小,我知道我已经离开了老板的办公室,我挺起胸膛,这一刻我仿佛重生了一般,浑身充满了干劲。迈着自信的步伐,我回到了我的工位。
打开电脑,老板已经把项目需求文档发给了我,打开1个G的doc
文件,首页赫然印着几个大字:项目工期一个月
我眼前一黑,晕了过去
曙光
“醒醒!醒醒!你怎么睡着了呢?”
我闻到一股淡淡的清香味,原来是我旁边的美工小妹妹在叫我。
“老板发你的新需求的项目文档你看了吧?老板让我们一起做这个项目”
“看到了看到了”
我惊喜着大叫一声,丝毫不顾忌周围同事的目光。我把头发往后捋了捋,望向我旁边的美工小妹妹:
“放心吧,包在我身上!”
“好的吧,那我先回去了,需要我做什么跟我说吖!”
我比了一个ok
的手势,目送美工小妹妹转身回到了她的工位上。
需求分析
于是乎,我赶紧打开了文档,细心的分析了这个项目的需求。
原来这个项目是希望完成一个web端的拓扑图,要求使用svg
技术实现,布局大概是长这样:
功能呢,也不复杂,可以从左侧的节点区把节点拖到画布,在画布上选中绘制的节点可以缩放旋转,在右侧属性区可以快捷的更改节点的一些属性。
美工小妹妹就负责配合我去设计svg
的图形
我冷笑一声,这还不简单?真是小看了我这个代码吸血鬼。我打开搜索引擎,用出了我的绝招
“无敌暴龙cv大法”
不出半天,上面的布局就被我给做好了。
根据项目需求还需要去实现拖动的功能,凭借我多年的工作经验,我很快便找到了如下可以进行参考的文章:
详细的拖拽需求以及缩放旋转的操作这篇文章里都有讲,我这里就不重复赘述了,经过了几天没日没夜的开发,主要说下我遇到的问题吧!
上面文章包含的项目实际上是采用定位来实现的,本身也是支持集成svg
文件的,我们先看一下svg
文件如何集成:
svg节点定义:
<template>
<div class="svg-star-container">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" :fill="fill" />
</svg>
</div>
</template>
<script>
export default {
props: {
fill: {
type: String,
require: true,
default: '#ff0000',
},
},
}
</script>
右侧属性面板定义:
<template>
<div>
<el-form>
<el-form-item label="填充色">
<el-color-picker v-model="curComponent.fill" />
</el-form-item>
</el-form>
</div>
</template>
上面这是我新集成的一个svg
图形,里面只有一个圆形,我这里希望可以在右侧改变圆形的填充(fill
)颜色,集成之后的效果就是这样的:
其实本质上是可以满足我们的需求的,因为我们也就是想改改svg
的fill
或者是stroke
这些基本属性的,但是我们的项目大概有300多个组件,这样一来我需要写600多个vue
文件。上面的示例我只是演示了如何更改svg
的fill
属性,没做缩放适配效果是这样的:
所以我还需要手动调整每个文件去适配缩放,这个工作量堪比吨级,我的脑中顿时思绪万千:
想起来这几日美工小妹妹准时下班向我发我来的甜蜜问候
想起来昨天向公司申请换键盘的尴尬经历
望着手机屏幕反射出连续高强度加班憔悴的我,看着我新换回来CV按键清晰可见的键盘,看着美工小妹妹键盘上那纤细的手指,我不由得感叹道:这么好看的手,不多做几个图可惜了。于是乎我的脑海里萌生了一个大胆的想法:
我要写个逻辑自动把
svg
文件转成组件,每个svg
文件写个配置文件就能在右侧属性区动态的设置svg
的fill
,stroke
等属性!!!
理想很丰满,现实很骨感
开始我是打算用vite
的raw以字符串的方式加载svg
文件,再用v-html
指令将字符串渲染成html
。
<script setup lang="ts">
import testSvgString from '../assets/vue.svg?raw'
</script>
<template>
<div>
<div v-html="testSvgString"></div>
<div v-html="testSvgString"></div>
</div>
</template>
效果是这样的:
这个方案确实行得通,不过如果真正绘制图像的话,会导致dom
节点变的很多很多。
而且现在还没有考虑怎么适应svg
节点的实际大小,怎么动态的改变节点的fill
等基本属性。。。
越想头越大,迷迷糊糊中我仿佛身处在一片森林中,映入我眼帘的是一个正在从我面前河里飘出来的白发老人。
“少年哟,你掉的是这个<symbol>
标签呢?还是这个<use>
标签呢?”
我猛然惊醒
皇天不负有心人
对啊,之前我们用过的一个项目里面的icon
图标就是一个个文件,当时是用的这个插件vite-plugin-svg-icons
它可以把svg
文件加载成symbol
标签,然后在需要的地方用use
标签引用就可以了
说干就干,于是我赶紧熟练的打开了搜索引擎,开始了我的求知之路,
终于
这个基于 vue3.2
+ts
实现的 svg
可视化 web
组态编辑器项目诞生了!
项目介绍
svg
文件即组件,引入并编写好配置文件后之后无需进行额外配置,编辑器会自适应解析加载组件。
同时支持自定义svg
组件和传统的vue
组件
开源地址
绘画
选中左侧的组件库,按住鼠标左键即可把组件拖动到画布中
操作
选中绘制好的节点后会出现锚点,可以直接进行移动、缩放、旋转等功能,右侧属性面板可以设置配置好的节点的属性,鼠标右键可以进行一些快捷操作
连线
鼠标移动到组件上时会出现连线锚点,左键点击锚点创建线段,继续左键点击画布会连续创建线段,右键停止创建线段,鼠标放在线段上会出现线段端点提示,拖动即可重新设置连线,选中线段后还可以在右侧的动画面板设置线段的动画效果
支持集成到已有项目
脚手架项目
# 创建项目(已有项目跳过此步骤)
npm init vite@latest
# 进入项目目录
cd projectname
# 安装插件
pnpm i webtopo-svg-edit
# 安装pinia
pnpm i pinia
# 修改main.ts 注册pinia
import { createPinia } from 'pinia';
const app = createApp(App);
app.use(createPinia());
app.mount('#app')
#在需要的页面引入插件
import { WebtopoSvgEdit,WebtopoSvgPreview } from 'webtopo-svg-edit';
import 'webtopo-svg-edit/dist/style.css'
umd方式集成
<!DOCTYPE html>
<html>
<head>
<title>webtopo-svg-edit Example</title>
<link href="https://unpkg.com/webtopo-svg-edit@0.0.8/dist/style.css" rel="stylesheet" />
<script src="https://unpkg.com/vue@3.2.6/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script>
<script src="https://unpkg.com/pinia@2.0.33/dist/pinia.iife.prod.js"></script>
<script src="https://unpkg.com/webtopo-svg-edit@0.0.8/dist/webtopo-svg-edit.umd.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const pinia = Pinia.createPinia()
const app = Vue.createApp(WebtopoYLM.WebtopoSvgEdit)
app.use(pinia)
app.mount('#app')
</script>
</body>
</html>
es module方式集成
<!DOCTYPE html>
<html>
<head>
<title>webtopo-svg-edit Example</title>
<link href="https://unpkg.com/webtopo-svg-edit@0.0.8/dist/style.css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
</body>
</html>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3.2.47/dist/vue.esm-browser.prod.js",
"@vue/devtools-api": "https://cdn.jsdelivr.net/npm/@vue/devtools-api/lib/esm/index.min.js",
"vue-demi": "https://unpkg.com/vue-demi@0.13.11/lib/index.mjs",
"pinia": "https://unpkg.com/pinia@2.0.29/dist/pinia.esm-browser.js",
"WebtopoYLM": "https://unpkg.com/webtopo-svg-edit@0.0.8/dist/webtopo-svg-edit.es.js"
}
}
</script>
<script type="module">
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { WebtopoSvgEdit } from 'WebtopoYLM'
const app = createApp(WebtopoSvgEdit)
app.use(createPinia())
app.mount('#app')
</script>
后记
“报告老板,以前一个月的工作,现在7天就能做完!”
“小伙子你很有前途,等公司赚钱了一定不会忘了你的!”
“老板这是哪里话,牛马的命也是命,当牛做马是我的荣幸!”
“行了,没什么事就去忙吧,7天之后等你们的好消息!”
凌晨三点,我看着美工小妹妹忙碌的身影,不由得嘴角上扬
嘿嘿!天
来源:juejin.cn/post/7260126013111812153