前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)

news2025/1/18 9:46:16

目录

  • 前言
  • 一、效果展示
  • 二、实现步骤
    • 1. 实现线条宽度(strokeWidth)的属性模块
    • 2. 实线线条样式(strokeDashArray)的属性模块
    • 3. 意料之外的“联动”
  • 三、Show u the code
  • 后记

前言

上一篇博文中,我们初步实现了右侧属性栏,通过属性栏,我们可以便捷得修改画布中对象的颜色相关属性。

这篇博文是《前端canvas项目实战——简历制作网站》付费专栏系列博文的第三篇——右侧属性栏(线条宽度&样式),主要的内容有:

  1. 针对线条对象: 扩充属性列表,使用户可以修改画布中选中的线条的宽度和样式(实线、虚线、点线等)。

一、效果展示

  • 动手体验
    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
  • 组装模块

注意:

  1. 构造下拉菜单选项的代码中有一行<div className="property-stroke-width-line" style={{ height:${option}px}} />,这里的作用是将下拉菜单的每个选项绘制成一条宽度对应的线条,如下图所示:
2. 实现一个新模块后,要记得添加到属性列表中:
	const propertyWrapperMap = {
		...
		line: ["StrokeWrapper", "StrokeWidthWrapper"],
		...
	};

2. 实线线条样式(strokeDashArray)的属性模块

strokeDashArraystrokeWidth类似,但实现更复杂一些

  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,且只接受stringnumber类型。
    • fabric.Line.strokeDashArray的默认值是 null,同时接受数组(例如[2, 2])作为参数。
  • strokeWidth类似,这个模块的下拉菜单选项也由<div>标签来绘制。
    • 我们使用的是它的border-top-style来表示线段样式,但其接受的值为string,比如实线为solid,虚线为dashed
    • 所以这个模块的 value 拆分为fabricValuecssValue两个。

strokeDashArray实现的效果如下:


3. 意料之外的“联动”

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

--->

但按照常理,虚线加粗之后应该仍是虚线! 说明我们的实现还存在问题,对于上述strokeWidthstrokeDashArray两部分代码,我们作出以下调整:

  • 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实现了修改宽度和样式的属性模块。

在下一节中,我们会为线条两端加上端点,如箭头、圆点、菱形等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

理顺 QR 分解算法

咱们网站的这个公式编辑器&#xff0c;估计是后台生成图片后贴回来的&#xff0c;固定分辨率而且分辨率不高。 还不如先离线 latex 生成 pdf 后再截图上来 1. Why QR When A and b are known, to solver the minimization of , where . The reduction of A to various canoni…

【计算机网络】概述|分层体系结构|OSI参考模型|TCP/IP参考模型|网络协议、层次、接口

目录 一、思维导图 二、计算机网络概述 1.计算机网络定义、组成、功能 2.计算机网络分类 3.计算机网络发展历史 &#xff08;1&#xff09;计算机网络发展历史1&#xff1a;ARPANET->互联网 &#xff08;2&#xff09;计算机网络发展历史2&#xff1a;三级结构因特网 …

时序预测 | MATLAB实现ICEEMDAN-SSA-GRU、ICEEMDAN-GRU、SSA-GRU、GRU时间序列预测对比

时序预测 | MATLAB实现ICEEMDAN-SSA-GRU、ICEEMDAN-GRU、SSA-GRU、GRU时间序列预测对比 目录 时序预测 | MATLAB实现ICEEMDAN-SSA-GRU、ICEEMDAN-GRU、SSA-GRU、GRU时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现ICEEMDAN…

详解SpringCloud微服务技术栈:ElasticSearch实践2——RestClient查询并处理文档

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;详解SpringCloud微服务技术栈&#xff1a;ElasticSearch搜索结果处理&#xff08;排序、分页、高亮&#xff09; &#x1f4da;订…

kali系统入侵电脑windows(win11系统)渗透测试,骇入电脑教学

本次渗透测试将使用kali虚拟机&#xff08;攻击机&#xff09;对本机&#xff08;靶机&#xff09;进行入侵并监控屏幕 声明&#xff1a;本篇仅仅是将本机作为靶机的一次简易渗透测试&#xff0c;实际情况中基本不可能出现如此简单的木马骇入&#xff08;往往在上传木马时就被防…

Unity中URP下逐顶点光照

文章目录 前言一、之前额外灯逐像素光照的数据准备好后&#xff0c;还有最后的处理二、额外灯的逐顶点光照1、逐顶点额外灯的光照颜色2、inputData.vertexLighting3、surfaceData.albedo 前言 在上篇文章中&#xff0c;我们分析了Unity中URP下额外灯&#xff0c;逐像素光照中聚…

vue3之echarts3D环柱图

vue3之echarts3D环柱图 效果&#xff1a; 核心代码&#xff1a; <template><div class"container"><div ref"chartRef" class"charts"></div></div> </template><script lang"ts" setup&g…

通讯录小项目(上)

Start And Stick 通讯录的实现有很多种方式&#xff0c;今天我们将用结构体实现简单的通讯录项目功能。包括通讯录的增、删、查、改等功能。 思路&#xff1a; 此次代码文件分别为&#xff1a; 文件名用途sqlist.h用于函数和结构体的声明sqlist.c用于函数的实现test.c用于通讯…

【数据结构四】栈与Stack详解

目录 栈与Stack 1.实现一个自己的栈 2.Stack的基本使用 3.栈的一些oj题训练 4.栈&#xff0c;虚拟机栈&#xff0c;栈帧的区别 栈与Stack 栈 &#xff1a;一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶…

Java集合总览

1.总览 Java中的集合分List、Set、Queue、Map 4种类型。 List&#xff1a;大多数实现元素可以为null&#xff0c;可重复&#xff0c;底层是数组或链表的结构&#xff0c;支持动态扩容 Set&#xff1a;大多数实现元素可以为null但只能是1个&#xff0c;不能重复&#xff0c; …

LeetCode(1)

目录 时间复杂度分析&#xff1a; 递归 题1&#xff1a;爬楼梯 解法1&#xff1a;递归 解法2&#xff1a;循环 题2&#xff1a;两数之和 解法1&#xff1a;暴力枚举 解法2&#xff1a; 哈希表 题3&#xff1a;合并两个有序数组 解法1&#xff1a;直接合并后排序 解法2&…

华为机考入门python3--(0)模拟题3-计算字符串重新排列数

分类&#xff1a;排列组合 知识点&#xff1a; 计算字符串中每个字符出现的次数 Counter(string) 计算列表中每个元素出现的次数 Counter(list) 阶乘 math.factorial(num) 排列去重 题目来自【华为招聘模拟考试】 先把每个字符当成唯一出现过一次&#xff0c;计算所有排列…

Linux文本三剑客---awk经典案例

awk&#xff08;是一种处理文本文件的应用程序&#xff0c;它依次处理文件的每一行&#xff0c;并读取里面的每一个字段。&#xff09; awk 包含几个特殊的内建变量&#xff08;可直接用&#xff09;如下所示&#xff1a; 1、获取根分区剩余大小 #可以使用df -h命令来查看所有…

详解顺序结构双指针处理算法

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

如何在Ubuntu安装配置SVN服务端并实现无公网ip访问内网资料库

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改au…

swift - reduce简介

reduce 减少&#xff0c;降低&#xff1b;&#xff08;烹调中&#xff09;使变浓稠&#xff0c;收汁&#xff1b;<美>节食减肥&#xff1b;使沦为&#xff0c;使陷入&#xff08;不好的境地&#xff09;&#xff1b;迫使&#xff0c;使不得不&#xff08;做&#xff09;&…

【C++】输入输出、缺省参数、函数重载

目录 C的输入和输出 缺省参数 概念 缺省参数的分类 全缺省参数 半缺省参数 函数重载 概念 C支持函数重载的原理--名字修饰 C的输入和输出 #include<iostream> // std是C标准库的命名空间名&#xff0c;C将标准库的定义实现都放到这个命名空间中 using namespace …

BKP备份寄存器、RTC实时时钟

目录 1. BKP (Backup Registers)备份寄存器 2. RTC (Real Time Clock)实时时钟 1. BKP (Backup Registers)备份寄存器 BKP可用于存储用户应用程序数据。当VDD (2.0-3.6V)电源被切断,他们仍然由VBAT (1.8-3.6V)维持供电。当系统在待机模式下被唤醒&#xff0c;或系统复位或…

【大数据】Flink 架构(一):系统架构

Flink 架构&#xff08;一&#xff09;&#xff1a;系统架构 1.Flink 组件1.1 JobManager1.2 ResourceManager1.3 TaskManager1.4 Dispatcher 2.应用部署2.1 框架模式2.2 库模式 3.任务执行4.高可用设置4.1 TaskManager 故障4.2 JobManager 故障 Flink 是一个用于状态化并行流处…

BeanUtils和BeanCopier性能复制Bean工具比较

文章目录 一、前言二、实验三、原理1、BeanUtils2、BeanCopier 四、总结 一、前言 我们本篇比较的是复制Bean对象的工具&#xff0c;分别是org.springframework.beans.BeanUtils和 net.sf.cglib.beans.BeanCopier 二、实验 import net.sf.cglib.beans.BeanCopier; import org…