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

目录

  • 前言
  • 一、效果展示
  • 二、实现步骤
    • 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实现了修改宽度和样式的属性模块。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA 创建maven项目没有src

环境&#xff1a; IntelliJ IDEA 2022.3.3 (Ultimate Edition) JDK 17 Windows 11 10.0 Maven 3.9.5 创建maven项目的时候没有src目录 试过网上说的重新配置maven库&#xff0c;增加vm-options&#xff0c;并没有什么用。直到我看见了 正常创建就好了。

QoS服务质量

内存QoS——服务质量&#xff08;Quality of Service&#xff09; 作用&#xff1a;如果不开启QoS&#xff0c;会通过内存复用技术&#xff0c;动态调整虚拟机的资源&#xff0c;如果说有一台跑核心业务&#xff0c;然后通过QoS技术&#xff0c;通过限额&#xff0c;预留&…

思考,是世界上最有趣的事

经常有读者问我&#xff1a; 你总说我们要多思考&#xff0c;可是每天的生活就那样&#xff0c;究竟要怎么思考&#xff0c;思考什么呢&#xff1f; 跟大家分享我上周日的一天&#xff1a; 读完一篇推理小说&#xff0c;写了一篇书评发给作者&#xff0c;并跟作者聊了聊写作的…

vivado 配置I/O端口

配置I/O端口 AMD设备支持可配置的SelectIO™ 接口驱动程序和接收器&#xff0c;支持各种标准接口。这些标准接口包括输出的可编程控制强度和转换速率&#xff0c;使用DCI的片上终端&#xff0c;以及内部VREF的生成。你可以配置一个或多个I/O端口以定义I/O标准、驱动器强度、转…

LaTeX基础使用【系列四】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;LaTeX基础使用 &#x1f984;1 LaTeX的多行数学公式&#x1f420;1.1 导入包&#x1f420;1.2 gather环境&#xff1a;多行公式&#x1f420;1.3 gather\* &#xff1a;无编号公式&#x1…

【Javaweb程序】【C00156】基于SSM餐饮管理系统(论文+PPT)

基于SSM餐饮管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的餐饮管理系统 本系统分为前台用户模块和后台管理员模块 其中前台用户模块的权限&#xff1a;当游客打开系统的网址后&#xff0c;首先看到的就是首页…

Day01_Java概述(JDK的下载安装,初学者常见错误)

文章目录 JavaSE_Day01 Java概述学习目标1.1 JavaSE课程体系介绍1.2 计算机语言概述1、计算机语言是什么2、计算机语言发展3、计算机语言分类4、计算机语言排行榜 1.3 Java语言概述1、Java语言发展历史2、Java是最好的语言吗&#xff1f;3、Java语言的特点4、Java生态圈5、Java…

【MySQL】学习如何通过DML更新数据库的数据

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-QIqURn9fNFMjLD9l {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【贪吃蛇:C语言实现】

文章目录 前言1.了解Win32API相关知识1.1什么是Win32API1.2设置控制台的大小、名称1.3控制台上的光标1.4 GetStdHandle&#xff08;获得控制台信息&#xff09;1.5 SetConsoleCursorPosition&#xff08;设置光标位置&#xff09;1.6 GetConsoleCursorInfo&#xff08;获得光标…

mysql 存储过程学习

存储过程介绍 1.1 SQL指令执行过程 从SQL执行的流程中我们分析存在的问题: 1.如果我们需要重复多次执行相同的SQL&#xff0c;SQL执行都需要通过连接传递到MySQL&#xff0c;并且需要经过编译和执行的步骤; 2.如果我们需要执行多个SQL指令&#xff0c;并且第二个SQL指令需要…

Linux文本三剑客---awk

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

AlexNet,ZFNet详解

1 AlexNet 网络结构 对于AlexNet网络来说&#xff0c;因为当时资源环境受限&#xff0c;他从第一步卷积开始就把一个图像分到两个GPU上训练&#xff0c;然后中间进行组合最后进行融合成全连接成1000个置信度 1 得到一张3x224x224的图像&#xff0c;然后进行11x11的卷积&…

1|Java代码是怎么跑起来的?

相信每个Java程序员都想过一个问题&#xff1a; “我写的Java代码时怎样在机器上跑起来的&#xff1f;“&#x1f914; 这篇文章就尝试把这个问题说一下✍ Java代码执行流程 二话不说先把图丢出来&#xff1a; 大概经历了这么几个步骤&#xff1a; 一位高级程序猿&#xff0…

竞赛练一练 第31期:GESP和电子学会相关题目练习

Day20&#xff1a;CIE一级2020.09_小鸡与鸭妈拥抱 1. 准备工作 &#xff08;1&#xff09;背景&#xff1a;Farm; &#xff08;2&#xff09;角色&#xff1a;Chick、Duck。 2. 功能实现 &#xff08;1&#xff09;角色的初始位置、方向和造型如图所示。 &#xff08;2&am…

DualSPHysics v5.0源码编译教程,新手入门

目录 一、前期准备1. 安装C编译器2. 安装CUDA 二、下载源码三、编译四、报错解决五、验证 一、前期准备 DualSPHysics是可以编译运行在CPU和GPU上的&#xff0c;所以需要安装C编译器&#xff1a;例如gcc&#xff0c;和CUDA编译器&#xff1a;nvcc。 如果电脑上不支持CUDA&…

【笔试常见编程题01】删除公共字符串、组队竞赛、倒置字符串、排序子序列

1. 删除公共字符串 输入两个字符串&#xff0c;从第一字符串中删除第二个字符串中所有的字符。 例如&#xff0c;输入”They are students.”和”aeiou”&#xff0c;则删除之后的第一个字符串变成”Thy r stdnts.” 输入描述 每个测试输入包含2个字符串 输出描述 输出删除后的…

翻译: GPT-4 Vision静态图表转换为动态数据可视化 升级Streamlit 三

GPT-4 Vision 系列: 翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式一翻译: GPT-4 with Vision 升级 Streamlit 应用程序的 7 种方式二 1. 将任何静态图表转换为动态数据可视化 ChatGPT Vision 不仅可以将涂鸦变成功能齐全的 Streamlit 应用程序&#xff0c;还…

Python算法题集_无重复字符的最长子串

本文为Python算法题集之一的代码示例 题目3&#xff1a;无重复字符的最长子串 说明&#xff1a;给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "a…

LeNet跟LeNet5详解

1 LeNet结构 主要是为了手写数字识别 具体结构讲解&#xff1a;从图中例子可得 1 先传入一个灰度图像尺寸为1x28x28&#xff0c;通道数为1&#xff0c;尺寸为28x28的灰度图像 2 第一层5x5卷积&#xff0c;经过公式 输入图像尺寸-卷积核尺寸2padding/步长1&#xff0c;&#…

打造专业级ChatGPT风格聊天界面:SpringBoot与Vue实现动态打字机效果,附完整前后端源码

大家好&#xff0c;今天用SpringBoot、vue写了一个仿ChatGPT官网聊天的打字机效果。 所有代码地址:gitee代码地址 &#xff0c;包含前端和后端&#xff0c;可以直接运行 使用本技术实现的项目&#xff1a;aicnn.cn&#xff0c;欢迎大家体验 如果文章知识点有错误的地方&#xf…