前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)
目录
- 前言
- 一、效果展示
- 二、实现步骤
- 1. 实现线条宽度(strokeWidth)的属性模块
- 2. 实线线条样式(strokeDashArray)的属性模块
- 3. 意料之外的“联动”
- 三、Show u the code
- 后记
前言
上一篇博文中,我们初步实现了右侧属性栏,通过属性栏,我们可以便捷得修改画布中对象的颜色相关属性。
这篇博文是《前端canvas项目实战——简历制作网站》付费专栏系列博文的第三篇——右侧属性栏(线条宽度&样式),主要的内容有:
- 针对线条对象: 扩充属性列表,使用户可以修改画布中选中的线条的宽度和样式(实线、虚线、点线等)。
一、效果展示
-
动手体验
CodeSandbox会自动对代码进行编译,并提供地址以供体验代码效果
由于CSDN的链接跳转有问题,会导致页面无法工作,请复制以下链接在浏览器打开:
https://4z795q.csb.app/ -
动态效果演示

- 本节之后,我们的简历能做成什么样子
我们可以修改线条的宽度和样式了。

二、实现步骤
本节的实现的功能在我们的简历模板上没有太多的改变(只改变了蓝色分隔线的宽度,1 --> 2),但作为一个通用的编辑器,我们实现的功能还是很有价值的。下面开始实现:
1. 实现线条宽度(strokeWidth)的属性模块
这里我们要继续修改上一篇博文中的属性工厂——object-props.js
,向其中添加一个控件StrokeWidthWrapper
const StrokeWidthWrapper = (props) => {const strokeWidthOptions = [1, 2, 3, 4, 5];// 下拉菜单选项列表const optionViews = strokeWidthOptions.map((option, index) => {return (<Option className="property-stroke-width"key={`stroke-width-${option}`} value={option} title={option}><div className="property-stroke-width-line" style={{ height: `${option}px` }} /></Option>);});return (<div className="property-row" key={props.key}><span className="property-title">宽度</span><div className="property-container"><Select value={strokeWidth} bordered={false} style={{ width: "100%" }}onChange={(value) => { handleChange("strokeWidth", value) }>{optionViews}</Select></div></div>);};
代码很简洁,分为 3 个部分:
- 定义可选的线条宽度列表
strokeWidthOptions
,这里我设置了最小为1
,最大为5
,可以根据自己的需要做出调整。 - 通过
strokeWidthOptions
构造出下拉菜单的选项列表optionViews
- 组装模块
注意:
- 构造下拉菜单选项的代码中有一行
<div className="property-stroke-width-line" style={{ height:
${option}px}} />
,这里的作用是将下拉菜单的每个选项绘制成一条宽度对应的线条,如下图所示:2. 实现一个新模块后,要记得添加到属性列表中: ![]()
const propertyWrapperMap = {...line: ["StrokeWrapper", "StrokeWidthWrapper"],...};
2. 实线线条样式(strokeDashArray)的属性模块
strokeDashArray
和strokeWidth
类似,但实现更复杂一些
const strokeDashArrayWrapper = (props) => {const strokeDashArrayOptions = [{ key: "实线", fabricValue: null, cssValue: "solid" },{ key: "虚线", fabricValue: [5, 5], cssValue: "dashed" },{ key: "点线", fabricValue: [1, 1], cssValue: "dotted" },];/*** 根据传入的value,返回对应的index*/const mapValueToIndex = (value) => {if (null !== value && Array.isArray(value)) {for (let i = 1; i < strokeDashArrayOptions.length; i++) {if (strokeDashArrayOptions[i].fabricValue[0] === value[0]) {return i;}}}return 0;};const optionViews = strokeDashArrayOptions.map((option, index) => {return (<Option className="property-stroke-width" key={`stroke-dasharray-${index}`}value={index} title={option.key}><div className="property-stroke-dasharray-line"style={{ borderTopStyle: option.cssValue }} /></Option>);});return (<div className="property-row" key={props.key}><span className="property-title">线条</span><div className="property-container"><Select value={mapValueToIndex(_recoverValue(strokeDashArray, strokeWidth))}bordered={false} style={{ width: "100%" }}onChange={(value) =>let adjustedValue = _adjustValue(strokeDashArrayOptions[value].fabricValue, strokeWidth);handleChange("strokeDashArray", adjustedValue);}>{optionViews}</Select></div></div>);};
可以看到,strokeDashArray
的实现复杂很多,这里分别讲解:
- 方法
_adjustValue
和_recoverValue
: 这两个方法在这里没有给出代码,在下一小节会讲到。 - 这个模块的 value 不直接设置,设置的是选项列表中的索引
index
(0, 1, 2, …),原因:antd
的<Select.Option>
不允许设置value=null
,且只接受string
和number
类型。fabric.Line.strokeDashArray
的默认值是null
,同时接受数组(例如[2, 2]
)作为参数。
- 和
strokeWidth
类似,这个模块的下拉菜单选项也由<div>
标签来绘制。- 我们使用的是它的
border-top-style
来表示线段样式,但其接受的值为string
,比如实线为solid
,虚线为dashed
。 - 所以这个模块的
value
拆分为fabricValue
和cssValue
两个。
- 我们使用的是它的
strokeDashArray实现的效果如下:

3. 意料之外的“联动”
本以为实现可以到此为止了,但是在测试中发现了一个问题。当我设置线条的样式为虚线(strokeDashArray=[5, 5]
) 时,如果将线条宽度strokeWidth
从1
逐渐增大到5
,一条细的虚线会变成粗的点线,如下图所示:


但按照常理,虚线加粗之后应该仍是虚线! 说明我们的实现还存在问题,对于上述strokeWidth
和strokeDashArray
两部分代码,我们作出以下调整:
- 将
strokeWidth
作为strokeDashArray
的系数 “联动” 起来,例如strokeWidth=1
时虚线的strokeDashArray=[5, 5]
,strokeWidth=2
时,strokeDashArray
就变为[5 * 2, 5 * 2] = [10, 10]
。 - 则有了以下代码,分别用来根据当前的线条宽度缩放
strokeDashArray
数组中的每一位:
const _adjustValue = (value, factor) => {if (null === value) {return null;}return value.map((item) => item * factor);};const _recoverValue = (value, factor) => {if (null === value) {return null;}return value.map((item) => Math.round(item / factor));};
- 用户修改了线条宽度,应该同时通过
_adjustValue
和_recoverValue
更新strokeDashArray
。修改strokeWidthWrapper
中<Select>
标签的onChange
方法为:
onChange={(value) => {let adjustedValue = _adjustValue(_recoverValue(strokeDashArray, strokeWidth), value);handleChange("strokeDashArray", adjustedValue);handleChange("strokeWidth", value);}}
经过上述的调整,一条虚线的宽度由1
放大到5
时,仍是虚线。


三、Show u the code
按照惯例,本节的完整代码我也托管在了CodeSandbox中,点击前往,查看完整代码
后记
本节中,我们为线条对象Line
实现了修改宽度和样式的属性模块。
在下一节中,我们会为线条两端加上端点,如箭头、圆点、菱形等。
相关文章:

前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)
目录 前言一、效果展示二、实现步骤1. 实现线条宽度(strokeWidth)的属性模块2. 实线线条样式(strokeDashArray)的属性模块3. 意料之外的“联动” 三、Show u the code后记 前言 上一篇博文中,我们初步实现了右侧属性栏…...

字节跳动二面经典题目
前言 语论即为「语兴式论语」,以语录体及对话的形式,沉淀球友实际工作学习中存在的疑难杂症解答,希望能够更好的帮助到球友和粉丝。欢迎关注公众号:语数 本期投稿 本期语数精选来源于球友应对字节跳动二面时候的场景问题 数仓工程…...

微搭低代码从入门到精通01应用介绍
目录 1 学习路线图2 应用介绍3 编辑器介绍总结 低代码的概念于2014年由 Forrester 首次正式提出。其将低代码定义为:能够以“最少的手写代码”和设置快速开发应用、配置和部署业务应用程序。 不同应用厂商的解法不一样,Gartner评估了400多款低代码/无代码…...

论文阅读《thanking frequency fordeepfake detection》
项目链接:https://github.com/yyk-wew/F3Net 这篇论文从频域的角度出发,提出了频域感知模型用于deepfake检测的模型 整体架构图: 1.FAD: 频域感知分解,其实就是利用DCT变换,将空间域转换为频域ÿ…...

ArcgisForJs快速入门
文章目录 0.引言1.前端代码编辑工具2.使用ArcgisForJs创建一个简单应用3.切片地图服务图层4.动态地图服务图层5.地图事件 0.引言 ArcGIS API for JavaScript是一款由Esri公司开发的用于创建WebGIS应用的JavaScript库。它允许开发者通过调用ArcGIS Server的REST API,…...

【解决方法】git pull报错ssh: connect to host github.com port 22: Connection timed out
问题 git pull ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository.解决方法 在C:\Users\username.ssh文件夹下新建config文件,填入以下文本(如有则直接在文件最后一行新增)&am…...

30天精通Nodejs--第三十天:项目实战-物联网应用
目录 引言架构设计编码创建项目数据服务模拟设备消息接收并保存设备数据后端接口项目启动及接口测试项目启动测试源码地址结语引言 在之前的一系列文章中,我们已系统性地探讨了诸多Node.js相关的技术要点与理论背景。随着知识体系的铺垫到位,我们现在步入了实战环节。接下来…...

java 社区资源管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 java Web社区资源管系统是一套完善的java web信息管理系统 ,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.…...

网络编程套接字(Socket)
为什么需要网络编程??? -丰富的网络资源 每天你在b站上刷着喜欢的up主的视频,实质是通过网络,获取到网络上的一个视频资源 与本地打开文件类似,只是视频文件这个资源来源是网络 所谓的网络编程,其实就是从网络上获取各种数据资源 什么是网络编程?? 网络编程,指的是网络…...

C语言第十一弹---函数(下)
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 函数 1、嵌套调用和链式访问 1.1、嵌套调用 1.2、链式访问 2、函数的声明和定义 2.1、单个文件 2.2、多个文件 2.3、static 和 extern 2.3.1、static…...

Unity读书系列《Unity3D游戏开发》——拓展编辑器(一)
文章目录 前言一、扩展Project视图1、右键扩展菜单(Asset)2、监听事件3、拓展布局 二、扩展Hierarchy视图1、拓展菜单(GameObject)2、拓展布局3、重写菜单 三、扩展Inspector视图1、扩展原生组件2、扩展继承组件 四、扩展Scene视图…...

【Git】项目管理笔记
文章目录 本地电脑初始化docker报错.gitignoregit loggit resetgit statusgit ls-filesgit rm -r -f --cached拉取仓库文件更新本地的项目报错处理! [rejected] master -> master (fetch first)gitgitee.com: Permission denied (publickey).error: remote origin already e…...

中文词性标注工具pkuseg例子(运行结果,不太好)
pkuseg_demo.md pkuseg 预训练模型 预训练模型science 安装 pip3 install pkuseg cd /rot/pkuseg_home/model/wget https://github.com/lancopku/pkuseg-python/releases/download/v0.0.25/science.zip uzip science.zip -d ./science/ ls /rot/pkuseg_home/model/science/…...

获取URL参数:split方法、URLSearchParams方法示例
在JavaScript中,可以使用多种方法来获取URL参数,其中常用的方法有split()和URLSearchParams()。 使用split()方法获取URL参数: split()方法将字符串分割成数组。可以使用split()方法将URL分割成协议、主机、路径和查询字符串等部分。然后可…...

SparkSql---用户自定义函数UDFUDAF
文章目录 1.UDF2.UDAF2.1 UDF函数实现原理2.2需求:计算用户平均年龄2.2.1 使用RDD实现2.2.2 使用UDAF弱类型实现2.2.3 使用UDAF强类型实现 1.UDF 用户可以通过 spark.udf 功能添加自定义函数,实现自定义功能。 如:实现需求在用户name前加上"Name:…...

系统架构15 - 软件工程(3)
软件过程模型 瀑布模型特点缺点 原型化模型特点两个阶段不同类型注意 螺旋模型V 模型特点 增量模型特点 喷泉模型基于构件的开发模型(CBSD)形式化方法模型敏捷模型特点“适应性” (adaptive) 而非“预设性” (predictive)“面向人的” (People-oriented) 而非“面向过程的” (P…...

两个近期的计算机领域国际学术会议(软件工程、计算机安全):欢迎投稿
近期,受邀担任两个国际学术会议的Special session共同主席及程序委员会成员(TPC member),欢迎广大学界同行踊跃投稿,分享最新研究成果。期待这个夏天能够在夏威夷檀香山或者加利福尼亚圣荷西与各位学者深入交流。 SERA…...

(二十一)Flask之上下文管理第二篇(细细扣一遍源码)
每篇前言: 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者 🔥🔥本文已收录于Flask框架从入门到实战专栏:《Flask框架从入…...

Java项目:基于SSM框架实现的企业员工岗前培训管理系统(ssm+B/S架构+源码+数据库+毕业论文)
一、项目简介 本项目是一套ssm821基于ssm框架实现的企业员工岗前培训管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格…...

深入了解Redis:选择适用于你的场景的持久化方案
自然语言处理的发展 文章目录 自然语言处理的发展强烈推荐前言:Redis提供了几种主要的持久化方案:RDB快照持久化:工作原理: AOF日志文件持久化:混合持久化: 总结强烈推荐专栏集锦写在最后 强烈推荐 前些天…...

【Git配置代理】Failed to connect to github.com port 443 问题解决方法
前言: 在学习代码审计时,有时会需要使用git去拉取代码,然后就出现了如下错误 看过网上很多解决方法,觉得问题的关键还是因为命令行在拉取/推送代码时并没有使用VPN进行代理。 解决办法 : 配置http代理:…...

python提取word文档内容的示例
一、微软Word历史、背景: Word 的特异功能就是把那些应该写成简单的 TXT 或 PDF 格式的文件,变成了既大又慢且难以打开的怪兽,它们经常在系统切换和版本切换中出现格式不兼容,而且因为某些原因在文件内容已经定稿后仍处于可编辑的…...

MarkDown快速入门-以Obsidian编辑器为例
直接上图,左右对应。 首先是基础语法。 # 标题,几个就代表几级标题;* 单个是序号,两个在一起就是斜体;- [ ] 代表任务,注意其中的空格; 然后是表格按钮代码 | 使用中竖线代表表格,…...

【计算机网络】协议,电路交换,分组交换
定义了在两个或多个通信实体之间交换的报文格式和次序,以及报文发送和/或接收一个报文或其他事件所采取的动作.网络边缘: 端系统 (因为处在因特网的边缘) 主机 端系统 客户 client服务器 server今天大部分服务器都属于大型数据中心(data center)接入网(access network) 指将端…...

加速应用开发:低代码云SaaS和源码交付模式如何选
随着数字化转型的加速,企业对于快速开发和交付高质量应用的需求也越来越迫切。为了满足这一需求,开发者们开始探索采用低代码平台进行软件开发工作,以加速应用开发过程。 目前,市场上的低代码产品众多,但基本可分为简单…...

ATT汇编
指令后缀 AT&T格式的汇编指令有不同的后缀 其中 b表示byte,字节 w表示word,字/两字节 l表示long,32位系统下的long是4字节 q表示quad,意味四重,表示4个字/8字节 寄存器用途 参见 AT&T的汇编世界 - Gemfield…...

java split 拆分字符串
今天突然把java里split 跟,kotlin中的split 弄混了 kotlin中split 的用法跟python 中的split 用法是一样的,java中由于返回值是String[] 的数组,所以 在使用的时候需要注意下返回值如果要获取里面的内容,还是需要遍历下里面的内…...

【InternLM 大模型实战】作业与笔记汇总
笔记1:https://blog.csdn.net/weixin_42567071/article/details/135375937 笔记2:https://blog.csdn.net/weixin_42567071/article/details/135423120 作业2:https://github.com/xiaomile/InternLM-homework/tree/main/%E4%BD%9C%E4%B8%9A1 笔…...

解析PreMaint在石油化工设备预测性维护领域的卓越表现
石油化工行业一直在寻找能够确保设备高效运行的先进维护解决方案。在这个领域,PreMaint以其卓越的性能和创新的技术引起了广泛关注。 一、为何选择预测性维护? 传统的维护方法,基于固定的时间表,无法灵活应对设备的真实运行状况。…...

C++面试宝典第25题:阶乘末尾零的个数
题目 给定一个整数n,返回n!(n的阶乘)结果尾数中零的个数。 示例 1: 输入:3 输出:0 解释:3! = 6,尾数中没有零。 示例 2: 输入:5 输出:1 解释:5! = 120,尾数中有1个零。 解析 这道题主要考察应聘者对于数学问题的分析和理解能力,以及在多个解决方案中,寻求最优…...