canvas库:frabic.js

203 阅读6分钟

一、 安装

 npm install fabric(或yarn add fabric)

二、 使用

在项目中导入:
import { fabric } from 'fabric' 


创建frabicManager对象管理:
// css:
    .container{
        display: flex;
        width: 100%;
        height: 50%;
        .top{
            width: 50%;
            height: 100%;
            background-color: rgb(248, 249, 254);
            display:flex;
            align-items: center;
            justify-content: center;

        }
    }
// html:
    <div class="top" ref="top">
      <canvas id="frabic" width="768" height="477"></canvas>
    </div>
// js:
    var frabicManager = {
        w: 768,
        h: 477,
        scale: 1,
        itemsArr: [],
        init() {
          //注意:创建不可交互的画布,其实只需把 `new fabric.Canvas` 改成 `new fabric.StaticCanvas` 即可。不可交互的画布添加鼠标事件不生效!!!
            this.canvas = new fabric.StaticCanvas("canvas_l");
            this.createline(400, "#000", 1, "E1= -13.6eV");
            this.createStatic();
            this.containerSize();
            this.createSin(300, 300, "#FF8C00", 150);
        },
        resize() {
            var container = document.querySelector(".top");
            var width = container.clientWidth;
            var height = container.clientHeight;
            //////////////////////方式一//////////////////////////////////////
            const canvas = document.querySelector("#frabic");
            if (frabicManager.w / frabicManager.h < width / height) {
                width = height/leftManager.h*leftManager.w
            } else {
                height = width/leftManager.w*leftManager.h
            }
            canvas.style.width = `${width}px`;
            canvas.style.height = `${height}px`;

            ///////////////////////方式二////////////////////////////////
            if (frabicManager.w / frabicManager.h < width / height) {
                // h的减小更多的情况
                frabicManager.scale = height / frabicManager.h;
            } else {
                frabicManager.scale = width / frabicManager.w;
            }
            let zoomPoint = new fabric.Point(width / 2 - 50, height / 2); // 中心点
            this.canvas.zoomToPoint(zoomPoint, leftManager.scale);
        },
        createStatic() {
            let text = new fabric.Text("文字内容", {
                left: 300,
                top: 5,
                fontFamily: "Comic Sans", //字体
                fontSize: 26, //字号
                textAlign: "center", //文本对齐方式
                lineHeight: 1.5, //行高
            });

            const line1 = new fabric.Line(
                [
                    100,
                    403, // 起始点坐标
                    100,
                    50, // 结束点坐标
                ],
                {
                    stroke: "#000",
                    strokeWidth: 3,
                }
            );
            const triangle = new fabric.Triangle({
                top: 30,
                left: 91,
                width: 20, // 底边长度
                height: 20, // 底边到对角的距离
                fill: "#000",
            });
            this.itemsArr.push(text, line1, triangle);
            // 建组
            this.group = new fabric.Group(this.itemsArr, {});
            this.canvas.add(this.group);
        }, 
        //鼠标事件(必须设置可交互的画布:new fabric.Canvas("canvas_r");否则不生效)
        event(){
            // 创建一个矩形对象
            const rect = new fabric.Rect({
                left: 100,
                top: 100,
                fill: 'red',
                width: 200,
                height: 200
            });

            // 将矩形添加到画布上
            this.canvas.add(rect);

            // 为矩形添加鼠标悬浮事件
            rect.on('mousedown', function() {
                console.log('Mouse is over the rectangle');
                // 你可以在这里改变对象的属性,比如颜色
                this.set({ fill: 'blue' });
                rightManager.canvas.renderAll();
            });

            // 你也可以添加鼠标移出事件来恢复原始状态
            rect.on('mouseout', function() {
                console.log('Mouse is out of the rectangle');
                this.set({ fill: 'red' });
                rightManager.canvas.renderAll();
            });
               rect.selectable = true//允许鼠标操作
        rect.perPixelTargetFind = true
         rect.lockMovementX = true// 不允许水平移动
         rect.lockMovementY = true// 不允许垂直移动
         rect.lockRotation  = true// 不允许旋转
         rect.lockScalingX   = true// 不允许水平缩放
         rect.lockScalingY   = true// 不允许垂直缩放
        },
        createline(y, color, number, text) {//创建线段
            const line = new fabric.Line(
                [
                    105,
                    y, // 起始点坐标
                    550,
                    y, // 结束点坐标
                ],
                {
                    stroke: `${color}`, // 笔触颜色
                    strokeWidth: 2,
                }
            );
            const circle = new fabric.Circle({
                top: 100, 
                left: 100, 
                radius: 50, // 半径:50px 
                backgroundColor: 'green', // 背景色:绿色 
                fill: 'orange', // 填充色:橙色 
                stroke: '#f6416c', // 边框颜色:粉色 
                strokeWidth: 5, // 边框粗细:5px 
                strokeDashArray: [20, 5, 14], // 边框虚线规则:填充20px 空5px 填充14px 空20px 填充5px …… 
                shadow: '10px 20px 6px rgba(10, 20, 30, 0.4)', // 投影:向右偏移10px,向下偏移20px,羽化6px,投影颜色及透明度 
                transparentCorners: false, // 选中时,角是被填充了。true 空心;false 实心 
                borderColor: '#16f1fc', // 选中时,边框颜色:天蓝 
                borderScaleFactor: 5, // 选中时,边的粗细:5px 
                borderDashArray: [20, 5, 10, 7], // 选中时,虚线边的规则 
                cornerColor: "#a1de93", // 选中时,角的颜色是 青色 
                cornerStrokeColor: 'pink', // 选中时,角的边框的颜色是 粉色 
                cornerStyle: 'circle', // 选中时,叫的属性。默认rect 矩形;circle 圆形 
                cornerSize: 20, // 选中时,角的大小为20 
                cornerDashArray: [10, 2, 6], // 选中时,虚线角的规则 
                selectionBackgroundColor: '#7f1300', // 选中时,选框的背景色:朱红 
                padding: 40, // 选中时,选择框离元素的内边距:40px 
                borderOpacityWhenMoving: 0.6, // 当对象活动和移动时,对象控制边界的不透明度
            });
            const text1 = new fabric.Text(`${number}`, {
                top: 40, 
                left: 40, 
                fontSize: 120, 
                backgroundColor: 'green', // 背景色:绿色 
                fill: 'orange', // 填充色:橙色 
                stroke: '#f6416c', // 边框颜色:粉色 
                strokeWidth: 3, // 边框粗细:3px 
                strokeDashArray: [20, 5, 14], // 边框虚线规则:填充20px 空5px 填充14px 空20px 填充5px …… 
                shadow: '10px 20px 6px rgba(10, 20, 30, 0.4)', // 投影:向右偏移10px,向下偏移20px,羽化6px,投影颜色及透明度 
                transparentCorners: false, // 选中时,角是被填充了。true 空心;false 实心 
                borderColor: '#16f1fc', // 选中时,边框颜色:天蓝 
                borderScaleFactor: 5, // 选中时,边的粗细:5px 
                borderDashArray: [20, 5, 10, 7], // 选中时,虚线边的规则 
                cornerColor: "#a1de93", // 选中时,角的颜色是 青色 
                cornerStrokeColor: 'pink', // 选中时,角的边框的颜色是 粉色 
                cornerStyle: 'circle', // 选中时,叫的属性。默认rect 矩形;circle 圆形 
                cornerSize: 20, // 选中时,角的大小为20 
                cornerDashArray: [10, 2, 6], // 选中时,虚线角的规则 
                selectionBackgroundColor: '#7f1300', // 选中时,选框的背景色:朱红 
                padding: 40, // 选中时,选择框离元素的内边距:40px 
                borderOpacityWhenMoving: 0.6, // 当对象活动和移动时,对象控制边界的不透明度
                overline: true, // 上划线
                underline: true, // 下划线
                linethrough: true, // 删除线
                textAlign: 'left', // 左对齐
                textAlign: 'center',// 居中对齐
                textAlign: 'right', // 右对齐
                lineHeight: 1, // 行高
            });
            //使用 `new fabric.IText` 可以创建**可编辑文本**,用法和 `new fabric.Text` 一样。
           
            this.itemsArr.push(line, circle, text1);
        },
        createSin(left, top, color, length) {//创建螺旋形的线
            var x = 1;
            var y = 20;
            let path = `M ${x} ${y}`;
            for (let i = 1; i < length; i += 0.1) {
                x = i * 2;
                y = Math.sin(i) * 10 + 20;
                path += `L ${x} ${y}`;
            }
            let customPath = new fabric.Path(path);
            customPath.set({
                left: left,
                top: top,
                stroke: `${color}`,
                fill: "rgba(0,0,0,0)",
                angle: 90,
            });
            this.itemsArr.push(customPath);
        },
        createGroup(){// 建组一定要最后建!!!等所有元素都建好了再建组push进去
            this.group = new fabric.Group(this.groups, {
                top: 10, // 整组距离顶部
                left: 10, // 整组距离左侧
                fill: '#DFECF7',
                // angle: -10, // 整组旋转-10deg
            })
            this.canvas.add(this.group);
        },
    };
       onMounted(()=>{
         frabicManager.init()
       })
      window.addEventListener('resize',()=>{
         frabicManager.resize()
      })
  

2.1 绘制一个简单的图形

Fabric 提供了 7 种基础形状:

  • fabric.Circle (圆)
  • fabric.Ellipse (椭圆)
  • fabric.Line (线)
  • fabric.Polyline (多条线绘制成图形)
  • fabric.triangle (三角形)
  • fabric.Rect (矩形)
  • fabric.Polygon (多边形)

我们可以通过设置以下属性,决定是否可以对相关元素进行交互

canvas.selection = false; // 禁止所有选中
rect.set("selectable", false); // 只是禁止这个矩形选中

2.2 绘制图片

有通过 url 和 img 标签绘制两种方式

//通过url绘制图片
import img from '@/assets/img.png' // 引入图片
fabric.Image.fromURL(img, oImg => {
    oImg.scale(0.5) // 缩放 
    canvas.add(oImg) // 将图片加入到画布 
    }) 
}

//也可以通过标签绘制
<img src="@/assets/logo.png" id="img">
let img = document.getElementById("img");
imgElement.onload = function() {
    let imgInstance = new fabric.Image(imgElement, { 
        left: 100, 
        top: 100, 
        width: 200, 
        height: 200, 
        angle: 50, // 旋转
    }) 
    canvas.add(imgInstance) 
 }

2.21组中常用的方法:

  • getObjects() 返回一组中所有对象的数组
  • size() 所有对象的数量
  • contains() 检查特定对象是否在 group
  • item() 组中元素
  • forEachObject() 遍历组中对象
  • add() 添加元素对象
  • remove() 删除元素对象
  • fabric.util.object.clone() 克隆

2.3 通过自定义的路径绘制

let customPath = new fabric.Path("M 0 0 L 300 100 L 170 100 L 70 300 L 20 200 C136.19,2.98,128.98,0,121.32,0 z");
customPath.set({
    left: 100,
    top: 100,
    fill: "green",
});
canvas.add(customPath);

2.4 颜色

2.41 定义颜色

new fabric.Color("#f55");
new fabric.Color("#aa3123");
new fabric.Color("356333");
new fabric.Color("rgb(100,50,100)");
new fabric.Color("rgba(100, 200, 30, 0.5)");

2.42 颜色转换

new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
new fabric.Color('fff').toHex(); // "FFFFFF"

我们还可以用另一种颜色叠加,或将其转换为灰度版本。

let redish = new fabric.Color("#f55");
let greenish = new fabric.Color("#5f5");
redish.overlayWith(greenish).toHex(); // "AAAA55"
redish.toGrayscale().toHex(); // "A1A1A1"

2.5 渐变

Fabric 通过 setGradient 方法支持渐变,在所有对象上定义。调用 setGradient('fill', { ... })就像设置一个对象的“fill”值一样。

let circle = new fabric.Circle({
  left: 100,
  top: 100,
  radius: 50
});

// 线性渐变 
let gradient = new fabric.Gradient({ 
type: 'linear', // linear or radial 
gradientUnits: 'pixels', // pixels or pencentage 像素 或者 百分比 
coords: { x1: 0, y1: 0, x2: circle.width, y2: 0 }, // 至少2个坐标对(x1,y1和x2,y2)将定义渐变在对象上的扩展方式 
colorStops:[ // 定义渐变颜色的数组 
    { offset: 0, color: 'red' }, 
    { offset: 0.2, color: 'orange' }, 
    { offset: 0.4, color: 'yellow' }, 
    { offset: 0.6, color: 'green' }, 
    { offset: 0.8, color: 'blue' }, 
    { offset: 1, color: 'purple' },
    ] 
}) 
circle.set('fill', gradient);
//径向渐变
let gradient = new fabric.Gradient({ 
    type: 'radial', 
    coords: { 
        r1: 50, // 该属性仅径向渐变可用,外圆半径 
        r2: 0, // 该属性仅径向渐变可用,外圆半径
        x1: 50, // 焦点的x坐标 
        y1: 50, // 焦点的y坐标 
        x2: 50, // 中心点的x坐标 
        y2: 50, // 中心点的y坐标 
    }, 
    colorStops: [ 
        { offset: 0, color: '#fee140' },
        { offset: 1, color: '#fa709a' } 
        ] 
})

2.6 事件

fabric 中通过 on 方法来初始化事件,off 方法用来删除事件。

常用的事件有以下

  • “mouse:down” 鼠标被按下
  • “object:add” 对象被添加
  • “after:render” 渲染完成
canvas.on("mouse:down", function(options) {
    canvas.clear();
    let text = new fabric.Text("点击触发", {
        left: 200,
        top: 200,
    });
    canvas.add(text);
    console.log(options.e.clientX, options.e.clientY);
});
canvas.on("mouse:up", function(options) {
    this.text = "没有发现点击";
    canvas.clear();
    let text = new fabric.Text("没有发现点击", {
        left: 200,
        top: 200,
    });
    canvas.add(text);
    console.log(options.e.clientX, options.e.clientY);
});

Fabric 允许将侦听器直接附加到 canvas 画布中的对象上。

let rect = new fabric.Rect({ width: 100, height: 50, fill: "green" });
rect.on("selected", function() {
    console.log("选择了目标");
});

let circle = new fabric.Circle({ radius: 75, fill: "blue" });
circle.on("selected", function() {
    console.log("选择了目标");
});

2.7 自由绘画

Fabric canvas 的 isDrawingMode 属性设置为 true 即可实现自由绘制模式.
这样画布上的点击和移动就会被立刻解释为铅笔或刷子。

let canvas = new fabric.Canvas("canvas");
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "blue";
canvas.freeDrawingBrush.width = 5;

官网:fabricjs.com/