montage.js 是一个基于 canvas 的绘图库,并且内置了一些鼠标交互功能,在一些需要用到 canvas 的场景下可使用此库来更简单的完成开发,比如拼接图片、简易绘图功能等等
也可以基于此库来开发一些自定义组件,几个常用场景的使用可见 demo 👇
可处理一些简单的拖拽需求,复杂交互不建议使用。前端在更多场景下可用于图片的拼接、整合、标记操作
简单的动画示例
以base64格式输出截图
大致性能可见下表( Mac Pro, M1, 2020 )
说明:
- 图案个数指画布中实际存在的图案/连线数量;
- 响应时长为鼠标 "按下" 至 "抬起" 过程中所花费的响应时间总和;
- 加载图案上限约为 1.34w 个;
- 本次测试不包含图片,图片加载/响应时长受图片大小/格式影响,具体性能以实际使用情况为准;
- 本次测试在设备通电情况下进行,实际使用过程中建议将图案个数控制在6000以内,否则会对性能产生较为明显的影响;
图案个数 | 加载时长 ms | 响应时长 ms | 测试次数 |
---|---|---|---|
60 | 2 | 12 ~ 33 | 6 |
600 | 23 | 72 ~ 103 | 6 |
6000 | 650 ~ 662 | 545 ~ 603 | 6 |
12000 | 2248 ~ 2306 | 1000 ~ 1200 | 6 |
开发示例,仅供参考
cd example
npm i
npm run serve
npm install montage.js
<canvas id="board"></canvas>
import Montage from "montage.js";
// 初始化
this.draw = new Montage({
drag: true, // 注意:如果要当成画布使用(允许缩放/拖拽),则需要开启 drag ,若只需要生成静态图案,则无需开启此选项
width: 300,
height: 300,
}, document.getElementById('board'));
// 添加两个节点
this.draw.addNode({
type: "rect",
x: 20,
y: 50,
width: 80,
height: 40,
zoom: true, // 开启缩放
connect: true, // 开启连线功能
textInfo: {
text: "hello world",
},
});
this.draw.addNode({
type: "circular",
x: 200,
y: 70,
radiusX: 50,
radiusY: 30,
zoom: true,
connect: true,
textInfo: {
text: "hello world",
},
});
创建节点后会返回被创建的节点信息
注意:只有在调用 addNode 方法时会返回
// 获取创建的节点信息
this.draw.addNode({
type: "rect",
x: 100,
y: 100,
width: 50,
height: 50
}).then((node) => {
console.log('node: ', node)
})
当要将画布中的元素保存下来时,可调用 getNodes 方法,该方法会返回画布中的节点信息和连接线信息,导入时需要将这两组数据分别导入
同理,如果需要将两个图形连接起来,也可以定义一组 connects 进行导入(可参考 demo 中的示例)
// 获取节点信息
let {nodes, connects} = this.draw.getNodes();
// 导入
for(let i of nodes){
this.draw.addNode(i)
}
for(let i of connects){
this.draw.addConnect(i)
}
当需要使用 addEventListener 监听某些事件时,请不要直接监听 canvas 元素,推荐监听父级元素,示例如下:
需注意:在鼠标按下并选中了某一个元素后,为了防止不必要的重绘,会渲染一层蒙版,所以鼠标抬起时将无法监听 up / move ... 等事件
<div id = 'canvasEvent'>
<canvas id = 'canvas'></canvas>
</div>
document.getElementById('canvasEvent').addEventListener('mousemove', (event) => {
console.log('move', event)
})
创建画布时,传入第三个参数作为点击画布的回调,当选中图案时,会将选中的图案作为参数传入
import montage from "montage.js";
function checked(node) => {
console.log('checked node', node)
}
new Montage({
drag: true,
width: 300,
height: 300,
}, document.getElementById('board'), checked);
画布默认为静态画布,只用于展示添加的图案,同时内置了图案的拖拽方法,若需要对画布进行操作,需要将 drag 属性设置为 true
注意:此插件不提供画布整体拖拽 / 缩放功能,整体缩放 / 拖拽的实现可运行 example 后查看示例
属性 | 说明 | 可选值 | 默认值 | 类型 |
---|---|---|---|---|
width | 画布宽度 | - | - | number |
height | 画布高度 | - | - | number |
drag | 是否开启拖拽操作,如果关闭,则无法更新画布内的图案信息 | true/false | false | boolean |
highlight | 鼠标选中高亮设置 (高亮效果取决于节点的 fillType 属性) |
fillColor:高亮颜色; | { fillColor: 'rgb(0,217,255)', } |
object |
defaultStyle | 默认的元素样式 (可配置默认颜色/默认线宽,当使用自带的绘制方法去绘制图形时会非常有用) |
fillColor:默认颜色; lineWidth:默认宽度(图案fillType='stroke'时生效); zoomColor: 缩放框颜色; zoomWidth: 缩放框线宽; rotateColor: 旋转框颜色; rotateWidth: 旋转框宽度; connectColor: 连接点颜色 |
{ fillColor: 'rgba(0, 0, 0, 1)', lineWidth: 1, zoomColor: 'rgb(30, 0, 255)', zoomWidth: 1, rotateColor: 'rgb(30, 0, 255)', rotateWidth: 1, connectColor: 'rgb(19, 154, 251)' } |
object |
// 初始化
import Montage from "montage.js";
this.ctx = new Montage({
drag: true,
width: 300,
height: 300,
}, document.getElementById('board'));
用于往画布中添加一个新的节点,可选值见节点配置项 type 属性
addNode(prop: object) // 传入要创建的节点属性
注意:这个操作是异步的,返回创建的节点信息
// prop 见节点配置项
// * 如果指定了节点id,那么在下一次加入相同id节点的时候,将覆盖之前创建的节点
this.ctx.addNode(prop).then((node) => {
console.log('new node', node)
})
获取当前选中的节点信息,或指定id的节点信息
注意:这将返回一个响应式对象,修改其属性时会自动修改画布内此节点的属性
// 传入节点 id,返回这个节点的实例
let node = this.ctx.getNode(id: string | null);
获取画布当前状态下的所有图案
let {
nodes, // 当前画布中的所有节点
connects // 当前画布中所有的连接线的信息集合
} = this.ctx.getNodes();
用于删除某一当前选中的节点,或是根据id删除节点
deleteNode(id: string | null) // 传入节点id
let nodeId = 'id';
this.ctx.deleteNode(nodeId)
清空整个画布
this.ctx.clearable();
用于重绘当前画布上的所有节点(刷新)
this.ctx.reload();
根据图案路径去绘制自定义图案,区别于 addNode 方法,这个方法用于创建一个纯静态展示的复杂图案
注意:纯静态图案,仅用于展示,更新时需要使用reload方法更新画布
// 传入要绘制的图案路径信息,详见 自定义图案配置项
this.ctx.customDrawing(node: object)
// 这是一个绘制星星的示例
let custom = {
start: {
x: 200,
y: 200,
},
lineWay: [[230, 100], [260, 200], [360, 230], [260, 260], [230, 360], [200, 260], [100, 230], [200, 200]],
fillType: "stroke",
fillColor: "rgba(200,200,100,0.8)",
}
this.ctx.customDrawing(custom)
将两个图案使用连线进行连接,目前只支持曲线和箭头曲线两种连线
addConnect(connect: object) // 传入节点的连线信息
let connect = {} // 详见连接线配置项
this.ctx.addConnect(connect)
// 传入图案类型, 自定义图案属性,及辅助属性, 无返回值
setNodeType(type: string, customProp: object | null, auxProps: object | null)
注意:只有在手动绘制图案时有效
用于设置即将在画布中绘制的图案类型
// type可选值为 rect: 矩形 / line: 线 / circular: 圆形
let type = 'rect';
// 自定义的节点属性,这些属性将被原封不动的保存在节点中
let customProp = {
prop1: 'xx',
prop2: 'xx',
...
};
// CanvasRenderingContext2D 的一些属性,实际使用频率较低,逐步开放中
// 目前仅支持 globalCompositeOperation
let auxProps = {
globalCompositeOperation: '', // 设置合成的操作类型,详见 https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
}
this.ctx.setNodeType(type, customProp, auxProps)
对于使用 getNode 方法获取的节点对象,插件内部使用 Proxy 来响应外界对节点的操作,为了防止频繁更改节点属性带来不必要的刷新,在节点更改完成后需要调用 reload 方法更新画布的展示效果
关于层级的说明:
- 图层按照层级从小到大排序,当点击位置包含多个图案,则会优先选中层级较大的图案
- 由于图片是异步加载,为了防止遮挡其他图案,加载时会置底,但是选取时仍会受到层级影响
- 当前选中的图案会默认置顶,取消选中后恢复原层级
属性 | 说明 | 可选值 | 默认值 | 类型 |
---|---|---|---|---|
id | 节点id,每次添加节点时会自动验证是否重复 当未填写id时,会自动填充,如果需要固定id,请指定 |
- | - | - |
type | 节点类型 | rect: 矩形 circular: 圆形 line: 线 image: 图片 |
- | string |
x, y | 起点x坐标, 起点y坐标 | - | - | number |
width, height | 图案宽高 | - | - | number |
src | 自定义图片路径(type='image'时生效) | - | - | string |
radiusX, radiusY | 自定义圆的半径(type='circular'时生效) | - | - | number |
endX, endY | 终点坐标(type='line'时生效) | - | - | number |
rotate | 旋转弧度,n*Math.PI | - | 0 | number |
level | 层级 | - | 1 | number |
zoom | 允许缩放/旋转(画布允许拖拽时生效) | true/false | false | boolean |
connect | 允许连线(画布允许拖拽时生效) | true/false | false | boolean |
drag | 允许拖拽(画布允许拖拽时生效) | true/false | true | boolean |
unClick | 禁止选中 (当无法被选中时,将无法响应式的更新该图案配置,修改配置后需要先调用 deleteNode 方法删除,再调用 addNode 方法重新加载) |
true/false | false | boolean |
unLight | 选中后禁止高亮 | true/false | false | boolean |
fillColor | 填充颜色 | color/rgb()/rgba() | rgb(0,0,0) | string |
fillType | 类别 | fill/stroke | stroke | string |
lineWidth | 宽度(fillType = 'stroke'时生效) | - | 1 | number |
textInfo | 文字信息 * 注意:文字换行可使用 /n 来处理,文字缩进可直接使用空格填充 |
text: string, font: string(与css font属性用法相同), fillType: 'fill/stroke', fillColor: 'color/rgb()/rgba()' |
- | object |
连线用于配置不同图案之间的连接关系,目前仅支持曲线、剪头曲线;
需要注意:
- 在实际连线过程中,将每一个图形分成了上右下左四个方位,分别对应1、2、3、4号位置,节点中的 pos 属性为此位置的序号
- 需要确保开始节点和目标节点的已经存在并且 id 完全一致,否则会失效
属性 | 说明 | 可选值 |
---|---|---|
id | 连接线id | ----- |
startInfo | 开始节点的信息 | { id: 开始节点的id pos: 开始的位置 } |
targetInfo | 目标节点的信息 | { id: 目标节点的id pos: 结束的位置 } |
用于创建一个纯静态的自定义图案,由于是根据路径绘制的,所以这个图案可以是一个复杂图形
属性 | 说明 | 可选值 |
---|---|---|
start | 开始位置 | { x, y } |
lineWay | 绘制的路径,将按照路径顺序进行绘制 | [[x, y], [x1, y1], ...] |
fillType | 图案类型 | fill: 实心 / stroke: 空心 |
fillColor | 图案颜色 | rgba() |
lineWidth | 线宽,在filleType = 'stroke'时生效 | number |
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。