likes
comments
collection
share

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

作者站长头像
站长
· 阅读数 10

自我介绍

本猫生活在东北的一个四线小城市,目前在一家小单位任职前端工程师的职位。早八晚五,生活充实,好不快活!

噩耗

Ctrl+c,Ctrl+vCtrl+c,Ctrl+v。新的一天开始了,本猫正在努力的工作着。看着旁边的美工小妹妹,我的口水止不住的往下流,别误会,是因为公司没有几个人,所以我们每天中午都在一起吃饭,而且我本来身为一个吃货,想到午饭就会流口水,很合理吧。

正当我沉迷在幻想之际,手机的一声震动把我拽回到现实。

“来我办公室一趟!” 竟然是老板给我发的消息!!! 难不成是我每天辛苦的工作被他发现了?要给我涨工资? 我一溜烟的从工位冲了出去,直奔老板的办公室。 这一路上我想了很多:想我这么多年的辛劳付出终于达到了回报、想我迎娶白富美的现场何其壮观、想我出任ceo之后回村又是多么的风光...... 终于在三秒之后,我来到了老板的办公室,见到了我最敬爱的老板。

“猫啊,听说你最近表现不错” 还没等我说话,老板又接着说到: “咱们公司最近新接了一个项目要交给你完成,你有没有信心啊?” 我拍了拍胸脯: “必须的!老板您说让我做什么我就做什么” 然后老板对我展开了需求攻势: “巴拉巴拉,如此如此,这般这般,巴巴拉拉加班拉拉巴巴” “什么?加班!” 其实老板说了那么多我是左耳听,右耳冒,但是加班这两个重重的砸在了我心上。我突然感觉一股热流冲到了头顶,双腿也止不住的颤抖,随即我双手用力的支撑在了老板的办公桌上,才勉强地站稳脚跟。 老板似乎也看出了我的不适,继续说道: “小猫啊!你年龄这么小,正是应该努力奋斗的时候,我像你这么大的时候每天只睡十分钟,才有了今天的成就。巴拉巴拉。。。。” 听着老板的经历,我不由得留下了感动的泪水。原来老板是如此的器重我,耐心的劝导我只为了让我成长,想到我刚才还想向老板提涨工资的事,我的脸唰的一下就红了。我赶紧向老板鞠了一躬,猫着腰往办公室外面跑。 “谢谢老板关心,我一定完美完成任务!” “公司就你一个前端,一定得好好做啊!” 随着老板的声音越来越小,我知道我已经离开了老板的办公室,我挺起胸膛,这一刻我仿佛重生了一般,浑身充满了干劲。迈着自信的步伐,我回到了我的工位。

打开电脑,老板已经把项目需求文档发给了我,打开1个Gdoc文件,首页赫然印着几个大字:项目工期一个月

我眼前一黑,晕了过去

曙光

“醒醒!醒醒!你怎么睡着了呢?” 我闻到一股淡淡的清香味,原来是我旁边的美工小妹妹在叫我。 “老板发你的新需求的项目文档你看了吧?老板让我们一起做这个项目” “看到了看到了” 我惊喜着大叫一声,丝毫不顾忌周围同事的目光。我把头发往后捋了捋,望向我旁边的美工小妹妹: “放心吧,包在我身上!” “好的吧,那我先回去了,需要我做什么跟我说吖!” 我比了一个ok的手势,目送美工小妹妹转身回到了她的工位上。

需求分析

于是乎,我赶紧打开了文档,细心的分析了这个项目的需求。 原来这个项目是希望完成一个web端的拓扑图,要求使用svg技术实现,布局大概是长这样:

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成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文件转成web组态组件的svg编辑器

其实本质上是可以满足我们的需求的,因为我们也就是想改改svgfill或者是stroke这些基本属性的,但是我们的项目大概有300多个组件,这样一来我需要写600多vue文件。上面的示例我只是演示了如何更改svgfill属性,没做缩放适配效果是这样的:

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

所以我还需要手动调整每个文件去适配缩放,这个工作量堪比吨级,我的脑中顿时思绪万千:

想起来这几日美工小妹妹准时下班向我发我来的甜蜜问候

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

想起来昨天向公司申请换键盘的尴尬经历

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

望着手机屏幕反射出连续高强度加班憔悴的我,看着我新换回来CV按键清晰可见的键盘,看着美工小妹妹键盘上那纤细的手指,我不由得感叹道:这么好看的手,不多做几个图可惜了。于是乎我的脑海里萌生了一个大胆的想法:

我要写个逻辑自动把svg文件转成组件,每个svg文件写个配置文件就能在右侧属性区动态的设置svgfillstroke等属性!!!

理想很丰满,现实很骨感

开始我是打算用viteraw以字符串的方式加载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>


效果是这样的:

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

这个方案确实行得通,不过如果真正绘制图像的话,会导致dom节点变的很多很多。

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

而且现在还没有考虑怎么适应svg节点的实际大小,怎么动态的改变节点fill等基本属性。。。

越想头越大,迷迷糊糊中我仿佛身处在一片森林中,映入我眼帘的是一个正在从我面前河里飘出来的白发老人

“少年哟,你掉的是这个<symbol>标签呢?还是这个<use>标签呢?”

我猛然惊醒

皇天不负有心人

对啊,之前我们用过的一个项目里面的icon图标就是一个个文件,当时是用的这个插件vite-plugin-svg-icons

它可以把svg文件加载成symbol标签,然后在需要的地方用use标签引用就可以了

说干就干,于是我赶紧熟练的打开了搜索引擎,开始了我的求知之路

终于

这个基于 vue3.2+ts 实现的 svg 可视化 web 组态编辑器项目诞生了!

项目介绍

svg文件即组件,引入并编写好配置文件后之后无需进行额外配置,编辑器会自适应解析加载组件。 同时支持自定义svg组件和传统的vue组件

开源地址

github

gitee

在线预览

绘画

选中左侧的组件库,按住鼠标左键即可把组件拖动到画布中

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

操作

选中绘制好的节点后会出现锚点,可以直接进行移动、缩放、旋转等功能,右侧属性面板可以设置配置好的节点的属性,鼠标右键可以进行一些快捷操作

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

连线

鼠标移动到组件上时会出现连线锚点,左键点击锚点创建线段,继续左键点击画布会连续创建线段,右键停止创建线段,鼠标放在线段上会出现线段端点提示,拖动即可重新设置连线,选中线段后还可以在右侧的动画面板设置线段的动画效果

因为美工小妹妹天还没亮就下班,我做了一版可以把svg文件转成web组态组件的svg编辑器

支持集成到已有项目

脚手架项目

# 创建项目(已有项目跳过此步骤)
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天之后等你们的好消息!”

凌晨三点,我看着美工小妹妹忙碌的身影,不由得嘴角上扬

嘿嘿!天还没亮,谁也别想走!