写点什么

web 技术分享| web 的白板工具栏封装

作者:anyRTC开发者
  • 2022 年 1 月 06 日
  • 本文字数:12806 字

    阅读完需:约 42 分钟

最近做白板项目,最重要的工具栏模块在网上搜了搜都没找到想要的,狠下心自己原生封装一个。

最终效果展示:

使用白板 SDK

使用 anyRTC 的白板 SDK 项目地址:https://demos.anyrtc.io/whiteboard-next-demo/如有需要,可前往 anyRTC 官网咨询客服下载源码

原理

封装一个白板工具栏,通过传入容器id工具相关配置白板实例,自动生成对应的左侧白板工具栏

容器创建

<div id="ToolBarWhiteBoard"></div>
复制代码

工具相关配置

  • 侧边栏配置

  • icon: 工具栏图标

  • brushtooltype: 白板对应的工具类型

  • brushFn: 白板设置工具类型的方法

  • 侧边栏提示配置

  • tip: 提示

  • 侧边栏内容配置

  • type: 类型

  • “progress” 进度条

  • "color" 颜色

  • “form” 形状

  • “text" 文字


具体相关配置展示如下:


// 白板颜色设置var brushColor = [  "#1A1A1E",  "#0089FF",  "#00E3FF",  "#31FF88",  "#FFEA00",  "#FF6800",  "#FF001C",  "#ffffff",];
/** * 白板工具栏设置 * icon: 工具栏图标 * tip: 提示 * brushtooltype: 白板对应的工具类型 * brushFn: 白板设置工具类型的方法 * defaultcolor: 默认颜色 * detail: 内容模块分类 * * type: toolbar封装组件内部所用类型 * contenttext: 内容模块名称 * * *** progress 类型(进度条) * * min: 最小值 * * max: 最大值 * * defaultsize: 默认大小 * * *** color 类型(颜色) * * detailcolor: 颜色数组 * * defaultcolor: 默认颜色 * * *** text 类型(文字) * * brushtooltype: 白板类型,内部仅封装“清除涂鸦/白板” * * *** form 类型(形状列表) * * detail: 形状列表 * * */var config_toolbar = [ { icon: "icon-default", tip: "鼠标", brushtooltype: 0, // 画笔工具类型 NONE brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-select", tip: "图选", brushtooltype: 1, // 画笔工具类型 SELECT brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-pen", tip: "涂鸦", brushtooltype: 2, // 画笔工具类型 FREE_DRAW brushFn: "setBrushType", // 白板对应方法 detail: [ { type: "progress", // 进度条 contenttext: "线宽", brushFn: "setBrushThin", // 白板对应方法 defaultsize: 3, min: 1, max: 10, }, { type: "color", // 颜色 contenttext: "颜色", detailcolor: brushColor, defaultcolor: brushColor[0], // 画笔默认颜色 brushFn: "setBrushColor", // 白板对应方法 }, ], }, { icon: "icon-laser", tip: "激光笔", brushtooltype: 4, // 画笔工具类型 LASER_POINTER brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-eraser", tip: "橡皮擦", brushtooltype: 3, // 画笔工具类型 ERASER brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-text", tip: "文本", brushtooltype: 9, // 画笔工具类型 TEXT brushFn: "setBrushType", // 白板对应方法 detail: [ { type: "progress", // 进度条 contenttext: "字号", brushFn: "setTextSize", defaultsize: 14, min: 10, max: 50, }, { type: "color", // 颜色 contenttext: "颜色", detailcolor: brushColor, defaultcolor: brushColor[0], // 文本默认颜色 brushFn: "setTextColor", // 白板对应方法 }, ], }, { icon: "icon-setting", tip: "形状", brushtooltype: 7, // 画笔工具类型 RECT brushFn: "setBrushType", // 白板对应方法 detail: [ { type: "form", // 形状 detail: [ { icon: "icon-rect", tip: "矩形", brushtooltype: 7, // 画笔工具类型 RECT brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-elipse", tip: "椭圆", brushtooltype: 8, // 画笔工具类型 ELLIPSE brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-arrow", tip: "箭头", brushtooltype: 6, // 画笔工具类型 ARROW brushFn: "setBrushType", // 白板对应方法 }, { icon: "icon-line", tip: "直线", brushtooltype: 5, // 画笔工具类型 LINE brushFn: "setBrushType", // 白板对应方法 }, ], }, { type: "progress", // 进度条 contenttext: "线宽", brushFn: "setBrushThin", // 白板对应方法 defaultsize: 3, min: 1, max: 10, }, { type: "color", // 颜色 contenttext: "颜色", detailcolor: brushColor, defaultcolor: brushColor[0], // 画笔颜色 brushFn: "setBrushColor", // 白板对应方法 }, ], }, { icon: "icon-clear", tip: "清除", detail: [ { contenttext: "清空涂鸦", type: "text", brushtooltype: "涂鸦", // brushFn: "clear", // 白板对应方法 }, { contenttext: "清空白板", type: "text", brushtooltype: "白板", // brushFn: "clear", // 白板对应方法 }, ], }, { icon: "icon-copy", tip: "背景", detail: [ { type: "color", // 背景颜色 contenttext: "颜色", detailcolor: brushColor, // defaultcolor: brushColor[0], // 背景默认颜色 brushFn: "setBackgroundColor", // 白板对应方法 }, ], },];
复制代码

工具栏样式

如需更改,请自行修改


.tip {  opacity: 0;  visibility: hidden;  transition: opacity 1s;  position: absolute;  padding: 6px 12px;  background-color: #5a5a66;  color: #fff;  display: flex;  justify-content: center;  align-items: center;  border-radius: 4px;  font-size: 12px;  user-select: none;  z-index: 20;}.tip::before {  content: "";  position: absolute;  width: 12px;  height: 12px;  border-radius: 2px;  background: #5a5a66;  transform: rotate(45deg);  z-index: 10;}
.tip_left { left: 60px; width: 100%;}.tip_left::before { left: -4px;}
.tip_top { top: -36px;}.tip_top::before { bottom: -4px;}
.tip_bottom { bottom: -36px; width: 100%;}.tip_bottom::before { top: -4px;}
.toolbar { background: #ffffff; border-radius: 4px; box-shadow: 0px 2px 20px 0px rgba(192, 192, 205, 0.2); padding: 8px 2px;}.toolbar .toolbar_tool { position: relative; padding: 2px 6px;}.toolbar .toolbar_tool .toolbar_tool_buton { z-index: 40; border-radius: 4px; padding: 4px; display: flex; justify-content: center; align-items: center;}.toolbar .toolbar_tool .toolbar_tool_buton .toolbar_tool_icon { font-size: 20px; opacity: 1; color: #5a5a67;}.toolbar .toolbar_tool .toolbar_tool_buton .toolbar_tool_icon_activate { color: #294bff;}.toolbar .toolbar_tool .toolbar_tool_buton:hover { z-index: 40; cursor: pointer; background: #f5f6fa;}.toolbar .toolbar_tool .toolbar_tool_buton:hover .tip { z-index: 40; transition: opacity 1s; opacity: 1; visibility: visible;}.toolbar .toolbar_tool .toolbar_tool_detail { z-index: 50; transition: opacity 1s; opacity: 0; visibility: hidden; position: absolute; top: 0px; left: 60px; background: #fff; box-shadow: 0px 2px 20px 0px rgba(192, 192, 205, 0.2); display: flex; flex-direction: column; border-radius: 4px; padding: 20px; font-size: 12px; color: #5a5a67; user-select: none;}.toolbar .toolbar_tool .toolbar_tool_detail_visibility { transition: opacity 1s; opacity: 1; visibility: visible;}.toolbar .toolbar_tool .toolbar_tool_color { width: 100%; height: 40px;}
/* color */.colorinfo { display: flex; margin: 10px 0 0; white-space: nowrap;}.colorinfo .colorlist { display: grid; grid-template-columns: repeat(4, 25%); align-items: center;}.colorinfo .colorlist .color { margin: 12px; width: 20px; height: 20px; border-radius: 100%; border: 1px solid #efefef;}.colorinfo .colorlist .color_active { margin: 10px; border: 2px solid #fff; box-shadow: 0px 0px 2px 1px #294bff;}
/* text */.detail_text { cursor: pointer; white-space: nowrap; width: 100%; padding: 6px 4px; text-align: center;}.detail_text:hover { background: #f5f6fa;}
/* from */.form { display: flex;}.form .form_button { z-index: 50; position: relative; display: flex; align-items: center; justify-content: center; margin-right: 8px; padding: 4px;}.form .form_button:hover { cursor: pointer; background: #f5f6fa; border-radius: 4px;}.form .form_button:hover .tip { transition: opacity 1s; opacity: 1; visibility: visible;}.form .form_button:hover .tip_top { top: -40px; width: 100%;}.form .form_button .form_button_icon { font-size: 20px;}.form .form_button .form_button_icon_active { color: #294bff;}
/* progress */.progressinfo { display: flex; align-items: center; white-space: nowrap;}.progressinfo .progressinfo_text { margin-right: 12px;}
复制代码

原生封装-工具类

进度条封装

/** * 进度条 */class progress {  constructor(options, callback) {    if (options) {      this.initprogress(options, callback);    }  }  //  initprogress(options, callback) {    options.max = Number(options.max);    options.min = Number(options.min);    // 创建最外围    const oProgress = document.createElement("div");    oProgress.className = "progress";    const oProgressWidth = oProgress.offsetWidth;    // 创建进度条拖拽点    const oProgressDot = document.createElement("div");    oProgressDot.className = "progress_dot";    oProgressDot.style.marginLeft =      (options.defaultwidth / (options.max - options.min)) * oProgressWidth +      "px";
// 创建提示 const oCreateToolDetailTip = document.createElement("div"); oCreateToolDetailTip.className = "tip tip_top"; oCreateToolDetailTip.textContent = options.defaultwidth; oProgressDot.appendChild(oCreateToolDetailTip);
// 创建进度条bg const oProgressBg = document.createElement("div"); oProgressBg.className = "progress_bg"; oProgressBg.style.width = (options.defaultwidth / (options.max - options.min)) * oProgressWidth + "px";
// const oProgressBgPro = document.createElement("div"); oProgressBgPro.className = "progress_bgpro";
oProgress.appendChild(oProgressBgPro); oProgress.appendChild(oProgressDot); oProgress.appendChild(oProgressBg);
options.document.appendChild(oProgress);
var isfalse = false, m = Math, b = document.body, value = 0, ratio = options.max - options.min;
oProgressDot.onmousedown = function (e) { // 停止冒泡行为 stopBubble(e); isfalse = true; var X = e.clientX; var offleft = this.offsetLeft; var max = oProgress.offsetWidth - this.offsetWidth; oProgress.onmousemove = function (e) { if (isfalse == false) { return; } var changeX = e.clientX;
var moveX = m.min(max, m.max(-2, offleft + (changeX - X)));
value = m.round(m.max(0, moveX / max) * ratio) + options.min; oCreateToolDetailTip.textContent = value; oProgressDot.style.marginLeft = m.max(0, moveX) + "px"; oProgressBg.style.width = moveX + 6 + "px"; }; }; oProgress.onmouseup = function () { if (isfalse) { callback(Number(value)); } isfalse = false; }; oProgress.onmouseleave = function () { if (isfalse) { callback(Number(value)); } isfalse = false; }; }}
复制代码

进度条样式

.progress {  width: 100%;  height: 4px;  padding: 20px 0;  background: #fff;  border-radius: 3px;  position: relative;}.progress .progress_dot {  width: 12px;  height: 12px;  border-radius: 50%;  background: #294bff;  position: absolute;  margin-top: -4px;  cursor: pointer;  border: 1px solid #fff;  box-shadow: 0px 0px 3px #294bff;  display: flex;  justify-content: center;}.progress .progress_dot:hover .tip {  transition: opacity 1s;  opacity: 1;  visibility: visible;}.progress .progress_dot:hover .tip_top {  top: -44px;}.progress .progress_bg {  width: 0px;  height: 4px;  background-color: #294bff;  border-radius: 3px;  position: absolute;}.progress .progress_bgpro {  width: 100%;  height: 4px;  background-color: #f0f0fc;  border-radius: 3px;  position: absolute;}
复制代码


具体封装代码如下:


// 侧边工具栏class ToolBar {  constructor(options) {    if (options) {      // 获取容器      const oToolBar = document.getElementById(options.el);      oToolBar.className = "toolbar";      // oToolBar.style.height = options.infolists.length * 40 + "px";      this.board = options.board;      this.toolbaar = oToolBar;      // 创建容器侧边栏      this.createSideBar(oToolBar, options.infolists);    }    // 清除容器内容显示    const oBody = document.getElementsByTagName("body")[0];    oBody.addEventListener("click", this.clearShow);  }  // 创建侧边栏  createSideBar(toolbarDom, infolists) {    infolists.map((info, index) => {      // 创建工具      const oCreateTool = document.createElement("div");      oCreateTool.className = "toolbar_tool";      // 工具按钮      const oCreateToolButton = document.createElement("div");      oCreateToolButton.className = "toolbar_tool_buton";      // 工具按钮icon (默认选中第一个 )      const oCreateToolButtonIcon = document.createElement("i");      if (index == 0) {        oCreateToolButtonIcon.className =          "toolbar_tool_icon toolbar_tool_icon_activate iconfont " + info.icon;      } else {        oCreateToolButtonIcon.className =          "toolbar_tool_icon iconfont " + info.icon;      }      // 工具经过提示tip      const oCreateToolTip = document.createElement("div");      oCreateToolTip.className = "tip tip_left";      oCreateToolTip.textContent = info.tip;
// 添加 oCreateToolButton.appendChild(oCreateToolButtonIcon); oCreateToolButton.appendChild(oCreateToolTip); oCreateTool.appendChild(oCreateToolButton); toolbarDom.appendChild(oCreateTool); // 创建侧边栏内容 if (info.detail && info.detail.length > 0) { this.createSideBarDetail(oCreateTool, info.detail); } // 侧边栏点击 this.showSideBarDetail(oCreateTool, info); }); } // 创建侧边栏内容 createSideBarDetail(toolDom, detailedinfo) { // 创建详细分类 const oCreateToolDetail = document.createElement("div"); oCreateToolDetail.className = "toolbar_tool_detail"; const _this = this; detailedinfo.map((detail) => { switch (detail.type) { case "progress": // 设置默认大小 _this.board[detail.brushFn](detail.defaultsize);
const oProgress = document.createElement("div"); oProgress.className = detail.brushFn == "setBrushThin" ? "progressinfo thin_progress " : "progressinfo size_progress";
if (detail.contenttext) { const oProgressText = document.createElement("div"); oProgressText.className = "progressinfo_text"; oProgressText.textContent = detail.contenttext; oProgress.appendChild(oProgressText); }
// 进度条 new progress( { document: oProgress, defaultwidth: detail.brushFn == "setBrushThin" ? _this.board.getBrushThin() : _this.board.getTextSize(), min: detail.min, max: detail.max, }, function (num) { _this.board[detail.brushFn](num); } );
oCreateToolDetail.appendChild(oProgress); break; case "color": const oColorInfoList = document.createElement("div"); oColorInfoList.className = "colorinfo"; oColorInfoList.onclick = function (e) { // 停止冒泡行为 stopBubble(e); }; if (detail.contenttext) { const oCreateToolDetailColorText = document.createElement("div"); oCreateToolDetailColorText.textContent = detail.contenttext; oColorInfoList.appendChild(oCreateToolDetailColorText); } const oCreateToolDetailColorList = document.createElement("div"); oCreateToolDetailColorList.className = "colorlist";
if (detail.brushFn == "setBrushColor") { // 画笔默认颜色 _this.board[detail.brushFn](detail.defaultcolor); } else if ( detail.brushFn == "setBackgroundColor" && detail.defaultcolor ) { // 背景默认颜色(需要白板创建后才可以设置) let oTimer = setInterval(function () { if (_this.board.getCurrentBoardId()) { clearInterval(oTimer); _this.board[detail.brushFn](detail.defaultcolor); } }); } else if (detail.brushFn == "setTextColor" && detail.defaultcolor) { // 文字默认颜色 _this.board[detail.brushFn](detail.defaultcolor); }
detail.detailcolor.map((color) => { const oCreateToolDetailColor = document.createElement("div");
oCreateToolDetailColor.setAttribute("data-color", color); if (detail.brushFn == "setBrushColor") { // 画笔相关颜色 oCreateToolDetailColor.className = detail.defaultcolor == color ? "color color_active bu_color" : "color bu_color"; } else if (detail.brushFn == "setBackgroundColor") { // 白板背景颜色 oCreateToolDetailColor.className = "color bg_color"; } else if (detail.brushFn == "setTextColor") { // 白板文本默认颜色 oCreateToolDetailColor.className = detail.defaultcolor == color ? "color color_active text_color" : "color text_color"; }
oCreateToolDetailColor.style.backgroundColor = color; oCreateToolDetailColor.onclick = function (e) { // 停止冒泡行为 stopBubble(e); _this.board[detail.brushFn](color); _this.clearColor(_this.board, detail); _this.clearShow(); }; oCreateToolDetailColorList.appendChild(oCreateToolDetailColor); });
oColorInfoList.appendChild(oCreateToolDetailColorList); oCreateToolDetail.appendChild(oColorInfoList); break; case "form": const oCreateToolDetailFrom = document.createElement("div"); oCreateToolDetailFrom.className = "form"; detail.detail.map((form) => { const oCreateToolDetailButton = document.createElement("div"); oCreateToolDetailButton.className = "form_button";
oCreateToolDetailButton.setAttribute( "data-form", form.brushtooltype );
// 分类工具按钮提示tip const oCreateToolDetailTip = document.createElement("div"); oCreateToolDetailTip.className = "tip tip_top"; oCreateToolDetailTip.textContent = form.tip;
// 分类工具按钮icon const oCreateToolDetailButtonIcon = document.createElement("i"); oCreateToolDetailButtonIcon.className = "form_button_icon iconfont " + form.icon;
oCreateToolDetailButton.appendChild(oCreateToolDetailTip); oCreateToolDetailButton.appendChild(oCreateToolDetailButtonIcon); oCreateToolDetailButton.onclick = function (e) { // 停止冒泡行为 stopBubble(e); _this.board[form.brushFn](form.brushtooltype); _this.formBrush(_this.board); _this.clearShow(); }; oCreateToolDetailFrom.appendChild(oCreateToolDetailButton); oCreateToolDetail.appendChild(oCreateToolDetailFrom); }); break; case "text": const oText = document.createElement("div"); if (detail.contenttext) { oText.textContent = detail.contenttext; } oText.className = "detail_text"; oText.onclick = function (e) { // 停止冒泡行为 stopBubble(e); if (detail.brushtooltype == "涂鸦") { _this.board[detail.brushFn](); } else if (detail.brushtooltype == "白板") { _this.board[detail.brushFn](true); } // 清楚后变鼠标 _this.board.setBrushType(0); _this.clearShow(); }; oCreateToolDetail.style.alignItems = "center"; oCreateToolDetail.appendChild(oText); break; default: break; } }); toolDom.appendChild(oCreateToolDetail); } // 侧边栏内容显示/隐藏 showSideBarDetail(toolDom, detailedinfo) { const _this = this; toolDom.onclick = function (e) { // 停止冒泡行为 stopBubble(e); if (detailedinfo.brushFn) { _this.board[detailedinfo.brushFn](detailedinfo.brushtooltype); } if (detailedinfo.detail) { detailedinfo.detail.map((item) => { switch (item.type) { case "progress": // 进度条默认显示 _this.progressDefault(_this.board, item); break; case "color": // 当前背景颜色 _this.clearColor(_this.board, item); break; case "form": // 形状(当前画笔形状) _this.formBrush(_this.board); break; default: break; } }); }
const oCreateToolDetail = toolDom.getElementsByClassName( "toolbar_tool_detail" )[0]; if (oCreateToolDetail) { if ( oCreateToolDetail.classList.contains("toolbar_tool_detail_visibility") ) { oCreateToolDetail.classList.remove("toolbar_tool_detail_visibility"); } else { _this.clearShow(); oCreateToolDetail.classList.add("toolbar_tool_detail_visibility"); } } else { _this.clearShow(); }
// 点击效果 const oSelectIcon = toolDom.getElementsByClassName("toolbar_tool_icon")[0]; const oAllButton = document.getElementsByClassName("toolbar_tool_icon"); for (let detail = 0; detail < oAllButton.length; detail++) { oAllButton[detail].classList.remove("toolbar_tool_icon_activate"); } oSelectIcon.classList.add("toolbar_tool_icon_activate"); }; } // 颜色清空 clearColor(board, info) { let oBoardColor = null; let oColorList = null; if (info.brushFn == "setBrushColor") { // 画笔颜色 oBoardColor = board.getBrushColor(); oColorList = document.getElementsByClassName("bu_color"); } else if (info.brushFn == "setBackgroundColor") { // 背景颜色 oBoardColor = board.getBackgroundColor(); oColorList = document.getElementsByClassName("bg_color"); } else if (info.brushFn == "setTextColor") { // 文本颜色 oBoardColor = board.getTextColor(); oColorList = document.getElementsByClassName("text_color"); }
for (let index = 0; index < oColorList.length; index++) { if (oBoardColor == oColorList[index].getAttribute("data-color")) { oColorList[index].classList.add("color_active"); } else { oColorList[index].classList.remove("color_active"); } } } // 进度条默认显示 progressDefault(board, info) { let boardwidth = null; let oBrushAllProgress = null; if (info.brushFn == "setBrushThin") { boardwidth = board.getBrushThin(); oBrushAllProgress = document.getElementsByClassName("thin_progress"); } else if (info.brushFn == "setTextSize") { boardwidth = board.getTextSize(); oBrushAllProgress = document.getElementsByClassName("size_progress"); } if (oBrushAllProgress) { for (let x = 0; x < oBrushAllProgress.length; x++) { const oAllProgress = oBrushAllProgress[x].getElementsByClassName("progress"); for (let index = 0; index < oAllProgress.length; index++) { const oProgressWidth = oAllProgress[index].offsetWidth; const oDot = oAllProgress[index].getElementsByClassName("progress_dot")[0]; const oBg = oAllProgress[index].getElementsByClassName("progress_bg")[0]; const oTip = oAllProgress[index].getElementsByClassName("tip")[0]; oDot.style.marginLeft = ((boardwidth - info.min) / (info.max - info.min)) * (oProgressWidth - oDot.offsetWidth) + "px"; oBg.style.width = ((boardwidth - info.min) / (info.max - info.min)) * (oProgressWidth - oDot.offsetWidth) + "px"; oTip.textContent = boardwidth; } } } }
// 形状(当前画笔形状) formBrush(board) { // 当前画笔形状 const oBrush = board.getBrushType();
const oBrushLists = document.getElementsByClassName("form_button"); for (let index = 0; index < oBrushLists.length; index++) { const oIcon = oBrushLists[index].getElementsByClassName("form_button_icon")[0]; if (oBrushLists[index].getAttribute("data-form") == oBrush) { oIcon.classList.add("form_button_icon_active"); } else { oIcon.classList.remove("form_button_icon_active"); } } } // 所有显示效果清除 clearShow() { const oAllDetail = document.getElementsByClassName("toolbar_tool_detail"); if (oAllDetail && oAllDetail.length > 0) { for (let detail = 0; detail < oAllDetail.length; detail++) { oAllDetail[detail].classList.remove("toolbar_tool_detail_visibility"); } } } // 销毁 destroy() { this.toolbaar.innerHTML = ""; }}
复制代码



发布于: 刚刚
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
web技术分享| web的白板工具栏封装