前端canvas项目实战——简历制作网站(二)——右侧属性栏(颜色)

目录

  • 前言
  • 一、效果展示
  • 二、实现步骤
    • 1. 实现一个自定义的选色板
    • 2. 创建属性工厂,为每个对象定制属性
    • 3. 为canvas对象注册监听器,点击不同对象时更新属性列表
  • 三、Show u the code
  • 后记

前言

上一篇博文中,我们实现了左侧工具栏,通过点击工具栏,我们可以自由得在画布中添加想要的对象。

这篇博文是《前端canvas项目实战——简历制作网站》付费专栏系列博文的第二篇——右侧属性栏(颜色),主要的内容有:

  1. 初步实现右侧属性栏,使用户可以修改画布中选中的对象的边框填充颜色。

一、效果展示

  • 动手体验
    CodeSandbox会自动对代码的进行编译,并提供地址以供体验代码效果
    由于CSDN的链接跳转有问题,会导致页面无法工作,请复制以下链接在浏览器打开:
    https://srgi02.csb.app/

  • 动态效果演示

  • 本节之后,我们的简历能做成什么样子
    我们可以修改画布背景色、图形、线条和文字的颜色了。

二、实现步骤

知道了这节我们要实现的功能,接下来就开始实现。为了便于理解,我将代码拆分为4个部分进行讲解。

1. 实现一个自定义的选色板

从上述的动态图中可以看到,我们通过一个选色板来选择为画布中的对象索要设置的颜色。这里我们讲相关的代码写到一个palette.js文件中。

import paletteIcon from "../images/palette.svg";
import "./index.css";
import { ChromePicker } from "react-color";
import React, { useState } from "react";
import { Dropdown, Space } from "antd";
import transparentIcon from "../images/transparent.svg";const _parseHex2Rgb = (hex) => {return {r: parseInt(hex.substring(1, 3), 16),g: parseInt(hex.substring(3, 5), 16),b: parseInt(hex.substring(5, 7), 16),a: 1,};
};let ColorPicker = (props) => {let { handleChange, initColor } = props;let [color, setColor] = useState({rgb: { ...initColor.rgb, a: 1 },hex: initColor.hex,});function _handleChange(color, isCommonColor) {if (color.hex === "") {color.hex = "#FFFFFF";color.rgb = { r: 255, g: 255, b: 255, a: 0 };}if (!color.hasOwnProperty("rgb") && color.hex) {color.rgb = _parseHex2Rgb(color.hex);}setColor(color);handleChange && handleChange(color.hex);}return (<ChromePicker width="100%" color={color.hex} onChange={(color) => _handleChange(color)}/>);
};const CustomePalette = (props) => {let { title, color, handleChange } = props;if ("" === color || "transparent" === color) {color = "#FFFFFF";}const overlay = (<ColorPicker initColor={{ hex: color, rgb: _parseHex2Rgb(color) }}handleChange={(value) => handleChange(value)} />);const overlayShadow = "0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%), 0 9px 28px 8px rgb(0 0 0 / 5%)";return (<div className="palette"><span className="property-title">{title}</span><Dropdown dropdownRender={() => overlay} overlayClassName="overlay"overlayStyle={{ boxShadow: overlayShadow }} trigger="click" placement="bottom"><div className="property-container"><div className="property-color-bar" style={{ backgroundColor: color }} /><img alt="选色盘" src={paletteIcon} className="palette-icon" /></div></Dropdown></div>);
};export { Palette };

代码很清晰,分为3个部分:

  • 定义一个16进制色彩值到rgb色彩值的转换方法
  • 引入react-color库中的ChromePicker选色盘进行自定义封装。安装依赖需要在命令行执行npm install react-color
    • 设定了宽度width
    • 设置了一个ReactHook(useState),监听选色盘上当前选中的颜色值变化
    • 监听了onChange事件,当用户改变了选中的颜色值,执行传入的handleChange方法
  • 使用上述自定义封装的选色盘CustomePickerantd库的DropDown下拉菜单组件封装一个选色模块。即初始时显示下图中的颜色条和选色盘icon,点击后出现下拉菜单,其中显示选色盘。

2. 创建属性工厂,为每个对象定制属性

显而易见,画布中不同的对象有不同的属性。如矩形和圆有描边填充两种颜色属性,而线条和文字只有填充这一种。

这里,我们创建一个object-props.js

import { Palette } from "../../components/palette";
import { Actions as actions } from "../../modules/actions";
import { connect } from "react-redux";
import ObjectAPI from "../../apis/objectAPI";const ObjectProps = (props) => {let { canvas, activeObject, activeObjectProperties } = props;let { stroke, fill } = activeObjectProperties;function handleChange(key, newValue) {ObjectAPI.updateProperty(activeObject, key, newValue);}// 1. 封装自定义的选色盘,实现描边和填充两种选色器const StrokeWrapper = (props) => {return (<div className="property-row" key={props.key}><Palette title="描边" color={stroke} handleChange={(value) => handleChange("stroke", value)} /></div>);};const FillWrapper = (props) => {return (<div className="property-row" key={props.key}><Palette title="填充" color={fill} handleChange={(value) => handleChange("fill", value)} /></div>);};const wrapperNameEntityMap = {StrokeWrapper: StrokeWrapper,FillWrapper: FillWrapper};// 2. 分别为不同的对象类型定制属性组const propertyWrapperMap = {rect: ["StrokeWrapper", "FillWrapper"],circle: ["StrokeWrapper", "FillWrapper"],textbox: ["FillWrapper"],line: ["StrokeWrapper"]};function handleClick() {canvas.discardActiveObject();canvas.renderAll();handleClearActiveObject();}// 3. 绘制对象的属性组return (<div className="property-list"><div className="property-list-header"><div className="property-list-header-tab" active="true" style={{ paddingLeft: "1.5rem" }}><span>对象属性</span></div><div className="property-list-header-tab" onClick={handleClick}><span>画布</span></div></div>{propertyWrapperMap[type].map((item, index) => {let wrapperEntity = wrapperNameEntityMap[item];return wrapperEntity({ key: type + "-" + index });})}</div>);
};
const mapStateToProps = (state) => {return {canvas: state.canvas,activeObject: state.activeObject,activeObjectProperties: state.activeObjectProperties};
};export default connect(mapStateToProps, null)(ObjectProps);

由上述代码可见,属性工厂分为3个部分:

  • 使用上文中实现的自定义选色器实现描边填充两种属性的操作模块
  • 分别为不同的对象类型定制属性列表
  • 将属性列表依次绘制出来

如下图,选中矩形对象,它的颜色属性有两个;选中文字对象它的颜色属性就只有一个

选中矩形
选中文字

注意: 其中使用了react-redux作为中央数据仓库,篇幅所限,不对其做深入的讲解,你可以自行搜索,也可以点击文章末尾CodeSandbox链接,直接看代码学习。如确实需要讲解,请在评论中留言,需要的人数较多的话,我会在react基础博文中新增一篇来介绍。

3. 为canvas对象注册监听器,点击不同对象时更新属性列表

由上述动图可见,我们点击画布中不同的对象时,右侧的属性栏会立即更新为当前选中对象的属性。要实现这里我们需要给画布对象canvas注册一个监听器。

  /*** 为画布添加监听器* @param canvas 画布*/static addListeners(canvas) {// 初次选中对象时的监听器canvas.on("selection:created", () =>// 向中央数据仓库更新画布中选中的对象store.dispatch(actions.updateActiveObject(canvas.getActiveObject())););// 更新选中对象时的监听器canvas.on("selection:updated", () =>// 向中央数据仓库更新画布中选中的对象store.dispatch(actions.updateActiveObject(canvas.getActiveObject())););// 取消选中对象之前的监听器canvas.on("before:selection:cleared", (e) => {// 从中央数据仓库中清除画布中选中的对象store.dispatch(actions.clearActiveObject);});}

核心的代码很简洁,这里我们为canvas添加了3个监听器,下面分别介绍:

  • selection:created:选中被创建时,这里我们向中央数据仓库更新画布中选中的对象
  • selection:updated:选中更新时,这里的操作同上
  • before:selection:cleared:选中被清除之前,这里我们从中央数据仓库中清除画布中选中的对象。

注意: 这个方法可以写在任何地方,在创建canvas之后调用addListener(canvas)即可。这里我们对中央数据仓库中activeObject的任何更新,都会立即被属性工厂中监听到,同时立即渲染当前所需的属性列表。


三、Show u the code

按照惯例,本节的完整代码我也托管在了CodeSandbox中,点击前往,查看完整代码


后记

本文中,我们注册了canvas的3种监听事件。除此之外,它还有很多监听事件,比如:

  • after:render:画布重绘后
  • object:moving:对象移动时
  • object:rotating:对象被旋转时
  • object:added:对象被添加到画布中后
  • object:removed:对象被从画布中移除后

更多的监听事件,我们在后续博文中如有用到,还会详细讲解。

本节中,我们让用户可以在页面中随意修改各种对象的颜色。下一节中,我们将会对线条Line的样式编辑能力做更多的扩展。

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

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

相关文章

kubernetes实战教程:kubernetes简介

kubernetes实战教程:kubernetes简介 简介 官网:https://kubernetes.io/zh-cn/ 一款生产级别的容器编排系统,也成为k8s,用于自动部署,扩展和管理容器化应用的开源系统.Google在2014年开源了kubernetes(后续就用k8s来代替了)这个项目.k8s建立在Google大规模运行生产工作负载十几…

解决vue 2.6通过花生壳ddsn(frp内网穿透)实时开发报错Invalid Host header和websocket

请先核对自己的vue版本&#xff0c;我的是2.6.14&#xff0c;其他版本未测试 起因 这两天在维护一个基于高德显示多个目标&#xff08;门店&#xff09;位置的项目&#xff0c;由于高德要求定位必须使用https服务&#xff0c;遂在本地无法获取到定位坐标信息&#xff0c;于是…

OpenCV笔记之图像处理中遮罩和掩模的关系

OpenCV笔记之图像处理中遮罩和掩模的关系 code review 文章目录 OpenCV笔记之图像处理中遮罩和掩模的关系1.遮罩详解遮罩的创建遮罩的应用遮罩的主要应用遮罩的类型如何创建遮罩遮罩在图像处理中的应用方式 2.遮罩和掩模的关系 1.遮罩详解 在图像处理中&#xff0c;遮罩&#…

字符串和格式化输入/输出

本文参考C Primer Plus进行C语言学习 文章目录 strlen()函数sizeof使用数据类型 1.strlen()函数 之前提到的sizeof运算符它以字节为单位给出对象的大小。strlen()函数给出字符串中的字符长度。 #include<stdio.h> #include<string.h> #define PRAISE "You ar…

IS-IS:05 ISIS开销值和协议优先级

IS-IS 协议为路由器的每个 IS-IS 接口定义并维护了一个 level-1 开销值和一个 level-2开销值。开销值可以在接口上或者全局上手动配置&#xff0c;也可以使用 auto-cost自动计算确定。 修改接口cost&#xff1a; int g0/0/0 isis cost 50修改全局cost&#xff1a; isis cir…

Github 无法正常访问?一招解决

查询IP网址: https://ip.chinaz.com/ 主页如下&#xff1a; 分别查询以下三个网址的IP&#xff1a; github.com github.global.ssl.fastly.net assets-cdn.github.com 修改 hosts 文件&#xff1a; 将 /etc/hosts 复制到 home 下 sudo cp /etc/hosts ./ gedit hosts 在底下…

【C语言】(3)字符

字符串 1. 字符串简介 在C语言中&#xff0c;字符串是由字符数组构成的序列&#xff0c;以空字符&#xff08;\0&#xff09;结尾。这个空字符不可见&#xff0c;用于标记字符串的结束。C语言中没有专门的字符串类型&#xff0c;通常使用字符数组表示字符串。 2. 声明和初始…

Facebook 广告帐户:多账号运营如何防止封号?

Facebook目前是全球最受欢迎的社交媒体平台之一&#xff0c;拥有超过27亿活跃用户。因此&#xff0c;它已成为个人和企业向全球受众宣传其产品和服务的重要平台。 然而&#xff0c;Facebook 制定了广告商必须遵守的严格政策和准则&#xff0c;以确保其广告的质量和相关性&…

一文搞懂Jenkins持续集成解决的是什么问题

1、持续集成的定义 大师 Martin Fowler 是这样定义持续集成的: 持续集成是一种软件开发实战, 即团队开发成员经常集成他们的工作. 通常, 每个成员每天至少集成一次, 也就意味着每天可能发生多次集成. 持续集成并不能消除Bug, 而是让它们非常容易发现和改正. 根据对项目实战的…

【C++11并发】mutex 笔记

简介 在多线程中往往需要访问临界资源&#xff0c;C11为我们提供了mutex等相关类来保护临界资源&#xff0c;保证某一时刻只有一个线程可以访问临界资源。主要包括各种mutex&#xff0c;他们的命名大都是xx_mutex。以及RAII风格的wrapper类&#xff0c;RAII就是一般在构造的时…

docker 修改默认存储位置

✨✨✨✨✨✨✨ &#x1f380;前言&#x1f381;查看前面docker储存位置&#x1f381;移动文件位置&#x1f381;修改配置文件docker.service&#x1f381;修改daemon.json&#x1f381;加载配置并重启 &#x1f380;前言 最近服务出现系统盘满了,发现其中docker存储占用很大一…

Keycloak - docker 运行 前端集成

Keycloak - docker 运行 & 前端集成 这里的记录主要是跟我们的项目相关的一些本地运行/测试&#xff0c;云端用的 keycloak 版本不一样&#xff0c;不过本地我能找到的最简单的配置是这样的 docker 配置 & 运行 keycloak keycloak 有官方(Red Hat Inc.)的镜像&#…

基于固件库的RT-THREAD移植

为什么要使用操作系统 当我们进入嵌入式这个领域的时候&#xff0c; 往往首先接触的都是单片机编程&#xff0c; 单片机编程又首选 51 单片机来入门。 这里面说的单片机编程通常都是指裸机编程&#xff0c;即不加入任何 RTOS&#xff08;Real Time Operation System 实时操作系…

药物使用不当可能会导致耳聋,尤其是这6类,需警惕

耳聋的原因有很多&#xff0c;其中之一就是药物使用不当。有些药物具有耳毒性&#xff0c;也就是说&#xff0c;它们会损害内耳的结构和功能&#xff0c;导致听力下降或丧失。这种药物性耳聋有时是可逆的&#xff0c;有时则是永久的。那么&#xff0c;到底哪些药物会导致耳聋和…

ctf-idea调试jar包

0.拿到jar包并解压 进入解压出来的目录,然后以该目录打开项目 1.设置maven 设不设置都行 2.添加依赖 添加两个依赖, boot-inf下的 classes和lib 3.配置调试器 添加 remote jvm debug 1.根据jdk版本选择调试参数 2.选择module classpath为解压后的文件夹名 如图,运行jar包的…

CDR绘图软件|安装教程来了(小白福利:有红包封面领取哦!)

前言 今天给小伙伴们讲讲&#xff1a;如何安装CDR软件。 如果未来的你想从事平面设计/广告行业&#xff0c;那应该就会接触到CDR这款软件。 CorelDRAW Graphics Suite是加拿大Corel公司的平面设计软件&#xff1b;该软件是Corel公司出品的矢量图形制作工具软件&#xff0c;这…

Confluence 的文章导入到 YouTrack KB 中

YouTrack 是有一个 KB 的&#xff0c;我们可以吧 Confluence 的文章全部导入到 YouTrack 的 KB 中。 首先&#xff0c;你需要具有管理员权限&#xff0c;然后选择导入。 然后可以在打开的界面中新增一个导入。 在新增导入中输入 Confluence 在随后的界面中输入你 Confluence …

【Hexo博客|Fluid主题】实现链接卡片效果

文章目录 前言一、CardLink库二、配置步骤1. 添加静态js文件2. 使库文件生效3. 编写启用CardLink4. 查看效果效果与前面一致。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/06e0630f994d4d67a90e18e291c3fdc5.png#pic_center) 总结 前言 今天在阅读Github…

格子表单GRID-FORM | 嵌套子表单与自定义脚本交互

格子表单/GRID-FORM已在Github 开源&#xff0c;如能帮到您麻烦给个星&#x1f91d; GRID-FORM 系列文章 基于 VUE3 可视化低代码表单设计器嵌套表单与自定义脚本交互 新版本功能 &#x1f389; 不觉间&#xff0c;GRID-FORM 已经开源一年&#xff08;2023年1月29日首次提交…

通过FileZilla配置FTP

FileZilla服务端的安装 在虚拟机里安装FileZilla服务器 FileZilla的官网 下载一个客户端和一个服务端的FileZilla 如果已经有了一个客户端&#xff0c;可以不下用载。 FileZilla的配置 说明一下&#xff1a;通过FileZilla配置FTP有两种模式&#xff0c;我们先用被动模式 下载…