内容简介:DOM 结构如下:div#workarea顾名思义,该层为编辑器的可视范围。当 svgRoot 的高或宽大于该层的宽高时,会显示滚动条。
DOM 结构如下:
svg 编辑器 ├── workarea (视口层) └── svgcanvas (挂载层) └── svgRoot (最上层的svg) ├── canvasBg (svg背景层) ├── svgcontent (绘制层) | ├── layout1 (图层一) | ├── layout2 (图层二) | └── ... ├── guideLine (辅助线层) 复制代码
层
视口层
div#workarea
顾名思义,该层为编辑器的可视范围。当 svgRoot 的高或宽大于该层的宽高时,会显示滚动条。
挂载层
div#svgcanvas
挂载层负责 svg 的挂载。它会保持宽高和 svgRoot 相同。你可能会奇怪这层到底有什么用,直接挂载到适口层不也行吗?没错,直接挂载在视口层也是可行的,但软件设计需要考虑到一些可能会发生的情况。这里我们加上了这层,是考虑到后期我们可能会需要在 svgRoot 的同一层上添加一些 div 元素(毕竟svg中是无法添加 div 元素的),比如说添加一些备忘录。
svgRoot
svg#svgRoot
该元素为 根部svg 元素,它并不是真正绘制 svg 的载体,真正绘制 svg 图形的地方是它的内嵌 svg 元素,即绘制层。我们追加这层根部 svg 的目的,是为了使超出内嵌 svg 范围外的矢量图形,仍然能显示出来(svgRoot 比)。如图所示:
这里给个图片
svg背景层
svg#canvasBg
它负责显示出画布的位置,一般设置为白色。
绘制层
svg#svgcontent
矢量图形真正绘制的地方。导出的 svg 文件内容即是这个元素下的所有内容。注意要设置 overflow="visible"
绘制层的图层
g#layout
类似 PhotoShop,我们引入了“图层”的概念。图层就像叠好的一张张半透明(软件中其实是全透明)的白纸,你可以选择任意一张进行绘画。另外上层的纸的不透明的部分,会挡住它的下层的相同区域的显示。
辅助线层
作为一款编辑器,我们需要一些辅助线,提供一些选中效果以及一些交互。比如点击一个图形,就显示一个包围着它的矩形,我称之为“选中框”,此外这个矩形上有一些控制点,对它们进行拖拽等操作,可以对当前这个矩形进行缩放或者旋转。为了实现这些功能,辅助线是 svg 编辑器十分重要的部分。
但是为什么我们把辅助线层放到 根部svg 下,而不是直接放到绘制层呢?原因是在实现画布“缩放”功能的时候,画布的缩放其实是通过设置 svg#svgcontent 的 viewBox 属性来实现的(后面的svg编辑器系列会详细讲解),这种缩放会导致元素的 stroke-width(线宽)也会跟着变大变小。这样的话,用户体验就很不好了。
放大还好,选中框的线条虽然很大,但被选中的那个元素也好大。当如果是缩小的话,并缩小到很小的时候,就会有一个问题,那就是选中框也变细变小了,这样选中框的一些变形控制点也不好点中了。
辅助线层下的元素一般来说,在编辑器初始化的时候就应该进行创建,并将其设置 style="display: none;"
。比如说选中框,选中一个元素时,辅助线层下相关的元素一些属性会被修改(如元素的位置),然后显示出来;取消选中时,则将相关元素全部设置为不可见。我不建议直接删除或添加这些元素,因为这会有性能损失。
初始化
const svgRoot = SVG('svgcanvas').id('svgroot'); // svg root const canvasBg = svgRoot.nested().id('canvasBg'); // svg 内容的底色,宽高需和 svg content 同步 const svgContent = svgRoot.nested().id('svgcontent'); // svg 的真正内容位置。 const draw = svgContent.group(); // svgContent 下创建一个 group,作为第一个“图层”(类似ps的图层概念) const guideLine = svgRoot.group().id('guideLine'); // 放置辅助线的父容器 const selectedBox = guideLine.group().id('selectedBox'); // 选中框相关辅助线 const selectedBoxOutline = selectedBox.polygon() // 选中框-矩形轮廓 .fill('none') .stroke({width: 1, color: '#4d84ff'}) .hide(); // 选中框的 6个 缩放控制点 const scaleGrips = (() => { ... }) 复制代码
SVG('svgcanvas')
的意思是在 id 为 svgcanvas 的元素下创建一个根部 svg。
// 参数配置 const config = { bgcolor: '#fff', contentW: 517, contentH: 384, } // 初始化 svgContent.size(config.contentW, config.contentH).move(config.contentW, config.contentH); // 设置宽高和左上角坐标 canvasBg.size(config.contentW, config.contentH).move(config.contentW, config.contentH); svgRoot.size(config.contentW * 3, config.contentH * 3); workarea.scroll( (svgRoot.width() - workarea.w())/2, (svgRoot.height() - workarea.h())/2 ); // 滚动条拖到中间 canvasBg.rect('100%', '100%').fill(config.bgcolor); // canvasBg 添加 白色 rect,实现达到填充背景色效果 复制代码
svgcontent(绘制层)的宽为 w,高为 h。则有:
- svgroot 的宽为 w * 3, 高为 h * 3;
- canvasbg 的宽为 w,高为 h;
- workarea 的 scrollLeft 为 (w * 3 - workarea.width) / 2,(w * 3 - workarea.height) / 2。(使画布位于视口层的正中心)
最后我们用代码绘制一个 path,并调用写好的 showSelectedBox() 方法,显示它的选中框。
结尾
这篇文章主要讲述了 svg 编辑器的层次结构(DOM结构)设计和这样设计的原因,并简单讲述了 svg 编辑器初始化时需要做的事情。
下一篇系列文章的内容应该是讲解如何进行工具(如选择 工具 切换为钢笔工具)的激活和切换,以及如何配合事件响应函数实现其中一个简单的工具功能。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 对Android和iOS项目中的模块结构和类结构设计的探讨
- Go项目结构设计过程点滴记录
- 用户画像—数据指标与表结构设计
- 设计模式 结构型模式
- 如何设计redux state结构
- Fuchsia 操作系统的四层结构设计
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。