五一小卷一个svg编辑器

·  阅读 578
五一小卷一个svg编辑器

一、前言

五一来了,好家伙直接放5天假,今年立志要也稍微小卷一下,必须把这5天时间好好利用一下。本来打算上上课啥的,不过和我的好朋友宇深商量了一下,不如一起做个小个人项目,实践一把它不香么?

那到底做啥呢!

u=1119628129,726021668&fm=253&fmt=auto&app=138&f=JPEG.webp

思前想后,我们决定做一个简单的svg编辑器,废话不多说,先看一下效果

  1. 可滑动的工具栏 step1.gif

  2. 拖拽想要的图形 step2.gif

  3. 自定义svg属性 step3.gif

  4. 代码生成 step4.gif

体验地址:wildvillage.github.io/SVG-Editor/
源码地址:github.com/wildvillage…

二、项目报告

  1. 项目背景
    这个项目是源于我们都有一个想法,就是平常的工作中比较少接触到svg或者canvas的相关应用场景,但是我们都对svg和canvas还是很感兴趣的,因此希望做这方面的一个练手和尝试;于是经过了一个电话的讨论,确定了这样的一个方向;

  2. 选择原因
    主要有以下两个原因:

    • 项目不会涉及到前后段数据交互,这样在有限的时间内,我们可以把精力放在前端
    • 编辑器交互逻辑还是有一定的挑战的,有一定的尝试价值
  3. 投入产出
    项目总共代码工时应该是有30个小时左右,人均15个小时。因为我们每天花在这个上面的时间大约都是3个小时左右的时间;一起讨论出想法之后,就开始写会儿代码!然后咖啡店要关门了就回家!整个过程不算高效,但尽力了。

    所谓产出就是这样的一个半成品,但是我不会就这样就算了,今后依然会不断完善,把当时的想法都实现掉;但这篇博客可以先写,毕竟博客也属于当时的一个计划嘛!

三、技术细节

  1. 技术栈:react18 + vite + antd + ts

    考虑到这样的项目本质上其实是一个只有一个路由的单页面,因此就不需要用类似umi这样的框架了,我们直接用react自带的脚手架,另外时间紧迫,不自己造UI轮子了,antd直接拿来用,ts是必须用的,这个没得说;

  2. 基于svg

    我们最初的设想的做一个可以让用户随便画东西,然后能够生成代码的工具,我们设想过用canvas但是我们想到canvas画出来的图形不会体现在DOM上,因为DOM上就只有一个元素<canvas></canvas>,而画出来的图形代码都在js当中。当时没想到用canvas怎么实现,但svg的元素直接能够体现在DOM上,获取代码直接获取DOM就可以,因此选择基于svg进行实现;这样会方便一些。

  3. 数据流

截屏2022-05-05 下午10.31.35.png

画了一张简单的类型信息,左侧的菜单和可移动的tool工具包同时给画布传递信息,这个信息是如下这样的数据结构:

const render = [
  {
    id:string,
    type:"line" | "rect",
    attrs:{
      ...props
    }
  },
  ...
]

复制代码

画布就做一件事情那就是拿到最新的render进行渲染;render的信息保存在全局的状态管理器中

  1. 关于拖拽

    拖拽主要是用了ahooks中的两个hook,分别是useDrag 和 useDrop,然后拿到画布所放的位置信息,在render中push一条信息即可;

    详情可看ahooks官网文档示例

  2. 关于网格和刻度

    网格是使用svg画出来的,其实本质上就是横向和竖向的等差数列line.

     generateSplitLine = (
       split: number,
       step: number,
       type: 'vertical' | 'horizontal'
     ) => {
       const STROKE = '#ccc5';
       if (type === 'vertical') {
         return new Array(split).fill(null).map((item, idx) => {
           return {
             x1: idx * step,
             y1: 0,
             x2: idx * step,
             y2: '100%',
             stroke: STROKE,
             strokeWidth: idx % 5 ? 1 : 1.5,
           };
         });
       } else {
         return new Array(split).fill(null).map((item, idx) => {
           return {
             x1: 0,
             y1: idx * step,
             x2: '100%',
             y2: idx * step,
             stroke: STROKE,
             strokeWidth: idx % 5 ? 1 : 1.5,
           };
         });
       }
     };
    
     function SplitLine({ width, height }: { width: number; height: number }) {
       const splitLine = useMemo(() => {
         if (height && width) {
           const vertical = Math.ceil(width / 100);
           const verticalLine = generateSplitLine(
             vertical * 5,
             SCALE_STEP,
             'vertical'
           );
    
           const horizontal = Math.ceil(height / 100);
           const horizontalLine = generateSplitLine(
             horizontal * 5,
             SCALE_STEP,
             'horizontal'
           );
           return [...verticalLine, ...horizontalLine];
         }
       }, [height, width]);
    
       return (
         <svg xmlns={SVG_XMLNS} className={styles.splitLine}>
           {splitLine?.map((line) => (
             <line key={nanoid()} {...line} />
           ))}
         </svg>
       );
     }
    复制代码
  3. 代码展示

    可以看到,代码的展示属于一个beautiful版的代码,但是实际上他们就是代码字符串而已,怎么使其美化呢?用到了一个叫做Prism的库,专门用来美化字符串代码的一个轻量的库;

    import Prism from 'prismjs';
    import 'prismjs/themes/prism-okaidia.css';
    
    const 美化后的code = Prism.highlight(原字符串, Prism.languages.svg, 'Markup');
    复制代码

    截屏2022-05-05 下午10.52.55.png

    简单研究了一下,它的原理其实就是遍历每一个字符串,然后拦截诸如<>、svg、line这些敏感字符串,然后将他们用<span>包装一下,加上类名使用css美化就好了;

三、项目心得

  1. 高效才是硬道理

    无论做任何事情,其实效率高是非常重要的,做这个项目,效率还算可以,但是有的时候还是浪费了不少时间。另外节奏非常重要,应该在前两天把核心技术讨论一下攻克掉,否则后面没时间了,就水过去了。

  2. 让假期更有意义

    通过这次的小项目,我发现,其实假期也可以和自己感兴趣的事情结合在一起去过,也是一种很不错的体验,很喜欢那种一起讨论,一起头脑风暴的感觉,瞬间动力满满,因为这样的东西,不是为老板而坐,更不是为了别人想要的效果而做,而是朝着自己希望的方向去做;所以无论多么花费时间也觉得值得;

  3. 1 + 1 > 2

    可能如果是自己一个人弄的话,假期就玩过去了,但是有一到两个小伙伴一起弄的话,会相互监督,相互提意见,把这件事情尽可能做的好一点,我觉得这个是展现出了1 + 1 > 2的感觉,因为它会倒逼我们进步;同时一起合作的时候,也会学到对方身上优秀的点,不知道的东西又少了一些;很nice;

四、关于未来

  1. 维护

    这个项目会一直维护下去,因为这个项目,目前还是一个半成品,我还是比较希望能够做成当时设想的那个样子,目前是还有图形操作上的内容没有完成,数据流部分还不是很完善,接下来会逐渐改善这个部分;

  2. 拓展

    接下来,我能想到的是拓展这样的一个功能,可实现图形的拖拽移动、旋转、放大、缩小。目前支持直线和矩形,接下来会支持圆形、箭头、椭圆、多边形等,UI相关的样式也会重新进行一个设计。尤其是图标部分,需要统一和美观。

五、结语

感谢各位的阅读,我的base在杭州,如果有希望一起进步的同学欢迎一起学习前端知识,偶尔一起做个前端项目也挺棒的哦!😁

自荐其他文章阅读:

《typescript内置类型》
《typescript自测清单》
《时间切片了解一下》
《commonjs和es6的区别》
《设计一个Scrollbar的终极解决方案》

分类:
前端
收藏成功!
已添加到「」, 点击更改