web技术分享| web的白板工具栏封装
最近做白板项目,最重要的工具栏模块在网上搜了搜都没找到想要的,狠下心自己原生封装一个。
最终效果展示:
使用白板 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" 文字
- type: 类型
具体相关配置展示如下:
// 白板颜色设置
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 = "";
}
}