canvas插件 fabric.js 使用

2023-05-16

fabric.js使用

  • fabric.js 是 常用的 canvas 插件
    • 1, 在项目中使用
    • 2, 特殊用法
      • ①, 基本设置
      • ②, 画板数据的导入导出
      • ③, 遮罩 Pattern ( 引用官网案例 )
      • ④, 多个对象合并, 并设置为 fabric 背景 ( 适用于变色和更多场景 )
      • ⑤, 把 canvas对象 或者 fabric对象 导出为图片
      • ⑥, 位置的获取
        • 思路一: (计算法, 没算出来)
        • 思路二 (记录位置) 补充: 鼠标位移留痕不规则线条在如下代码中
    • 注意事项

fabric.js 是 常用的 canvas 插件

官方地址:  http://fabricjs.com/
小编用的版本为 4.5.1

1, 在项目中使用

		#myCanvas{
          width:10000px;
          height:10000px;
        }
<canvas id="myCanvas" width="10000" height="10000"></canvas>
<!-- 此处引用jquery ,也可以不引用 -->
<script src="./jquery-2.0.0.min.js"></script>
<script src="./fabric.5.1.0.min.js"></script>
		// 初始化 canvas 为 fabric 对象
        var canvas = this.__canvas = new fabric.Canvas('myCanvas');

		// 画一个矩形
        var rect = new fabric.Rect({
            width: 1000,
            height: 1000,
            left: 0,
            top: 0,
            fill: 'rgba(255, 0, 0, 0.4)',
        });
		// canvas 添加矩形并渲染
        canvas.add( rect );
        canvas.renderAll();

2, 特殊用法

    下面是在使用时用到和遇到的场景

①, 基本设置

		//画板元素不能被选中
        canvas.skipTargetFind = false;
        //画板不显示选中
        canvas.selection = false;
        canvas.freeDrawingBrush.color = "red";
        canvas.freeDrawingBrush.width = 1;
        //画板不限制调整时的宽高比
        // mycanvas.uniScaleTransform = true;
        // //绑定画板事件
        canvas.on({
            // 'mouse:dblclick': this.dblShowRectFrom,//双击区域弹出
            'mouse:down': this.mouseDownDrawRect, //按下,
            'mouse:move': this.mouseMoving, //移动中,
            'mouse:up': this.mouseUpDrawRect, //抬起,
            'mouse:wheel': this.zoomsHandle, //缩放
            // 'object:moved': this.objectMoved, //移动完成
            // // 'object:moving': objectMov,//移动中
            // 'object:scaled': this.mouseScaleDrawRect,//缩放完成
            // 'object:scaling': this.mouseScalingDrawRect,//缩放中
        });

②, 画板数据的导入导出

	// 1, 导出  检测 画板上所有对象 并保存为 字符串
	 let inkTrace = [];
	 canvas.getObjects().forEach((v,i) => {
            let klass = v.toJSON();
            if(klass.type == 'image'){
            	// 对其中一些特殊对象进行处理
            }
            inkTrace.push(klass)
      })
      // 对数据最后加工
      if(inkTrace.length==0){inkTrace=""}else{inkTrace = JSON.stringify(inkTrace)}
	// 2, 导入 根据字符串处理为 fabric 可识别的对象
			JSON.parse(inkTrace).forEach((v,i) => {
				// 不同类型的数据要分别处理 数据中的 type 属性
                if(v.type=="image"){
                    new fabric.Image.fromObject(v, (e) => {
                        mycanvas.add(e)
                    })
                }
                if(v.type=="path"){
                    new fabric.Path.fromObject(v, (e) => {
                        canvas.add(e)
                    })
                }
            })
            canvas.renderAll();

③, 遮罩 Pattern ( 引用官网案例 )

		var text = new fabric.Text('Honey,\nI\'m subtle', {
            fontSize: 250,
            left: 0,
            top: 0,
            lineHeight: 1,
            originX: 'left',
            fontFamily: 'Helvetica',
            fontWeight: 'bold',
            statefullCache: true,
            scaleX: 0.4,
            scaleY: 0.4
        });
        var shape = new fabric.Rect({
            width: 200,
            height: 100,
            left: 10,
            top: 300,
        });
        canvas.add(text, shape);
        loadPattern('./xxx.png');
        function loadPattern(url) {
            fabric.util.loadImage(url, function(img) {
            console.log(img)
            text.set('fill', new fabric.Pattern({
                source: img,
                repeat: "no-repeat"
            }));
            rect.set('fill', new fabric.Pattern({
                source: img,
                repeat: "no-repeat"
            }));
            canvas.renderAll();
            });
        }

④, 多个对象合并, 并设置为 fabric 背景 ( 适用于变色和更多场景 )

			// 创建对象
			let image = new fabric.Image(image, {
                left: 10,
                top: 10,
                scaleX: 1,
                scaleY: 1,
                crossOrigin: 'anonymous',// 跨域
            })
            let shape = new fabric.Rect({
                width: image.width,
                height: image.height,
                opacity:0.4,
                fill: "#FF0000",
                left: 10,
                top: 10,
                scaleX: 1,
                scaleY: 1,
            });
            // 合并
            let group = new fabric.Group([image, shape], {})
            // 设置为背景
            canvas.setBackgroundImage(group, canvas.renderAll.bind(canvas), {});

⑤, 把 canvas对象 或者 fabric对象 导出为图片

		let image = new Image();
		// 先引入一张图片作为底图, 不引入也没关系
        image.src = './xxx.png';
        image.setAttribute('crossOrigin', 'anonymous');
        image.onload = () => {
            let fabricImage = new fabric.Image(image, {
                left: 0,
                top: 0,
                width: image.width,
                height: image.height
            })
            let shapeLine = new fabric.Rect({
                width: 1700,
                height: 800,
                fill: "#333",
                left: 0,
                top: 0,
            });
            let shapeVert = new fabric.Rect({
                width: 235,
                height: image.height,
                fill: "#333",
                left: 0,
                top: 0,
            });
            // 把这几个对象合并一下
            let group = new fabric.Group([fabricImage, shapeLine, shapeVert], {})
            let imgs = group.toDataURL({
                format: 'png', // jpeg或png
                left: 0,
                top: 0,
                width: image.width,
                height: image.height
            });
            // imgs 就是导出后的图片, 放在 img 的src中即可使用
        }

⑥, 位置的获取

应用场景: 要求背景为一块矩形, 所有的遮罩, 痕迹, 只准出现在背景矩形上, 不准超出

思路一: (计算法, 没算出来)

在有旋转角度的情况下,
     位移: 算出位移之后出现在矩形上的位置(如,右侧超出出现在右侧)
     缩放: 在有旋转角度的情况下, 拉伸已旋转的矩形, 如果超出背景矩形, 则缩放至最大高度(没算出来)
     旋转: 旋转矩形如果超出背景矩形, 计算矩形能在背景矩形旋转的最大角度(没算出来)

mycanvas.on({
            //'mouse:down': this.mouseDownDrawRect, //按下,
            //'mouse:move': this.mouseMoving, //移动中,
            //'mouse:up': this.mouseUpDrawRect, //抬起,
            //'mouse:wheel': this.zoomsHandle, //缩放
            'object:moved': this.objectMov, //移动完成
            //'object:moving': this.objectMov,//移动中
            'object:scaled': this.mouseScaleDrawRect,//缩放完成
            //'object:scaling': this.mouseScalingDrawRect,//缩放中
            'object:rotated': this.objectRotated,// 旋转完成
            //'object:rotating': this.objectRotated,// 旋转中
        });
        // 移动完成计算
        objectMov = (t) => {
        const { mainCanvas } = this.state;
        let mycanvas = mainCanvas,oImgList = mycanvas.getObjects(),oImg = t?oImgList[oImgList.length-1]:mycanvas.getActiveObject();
        if(!oImg) { return false;}
        let ep = oImg.aCoords,// 目标对象的四个坐标点
            angle= Math.floor(( oImg.angle ) / 90),// 目标对象的旋转角度
            ptl = mycanvas.backgroundImage.aCoords.tl,
            pbr = mycanvas.backgroundImage.aCoords.br,et = 0,el = 0,eb = 0,er = 0,w = 0,h = 0;
        switch (angle) {
            case 0:
                et = ep.tl.y;el = ep.bl.x;eb = ep.br.y;er = ep.tr.x;
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.bl.x }); // 左侧超出
                if(er > pbr.x) { // 右侧超出
                    if((ep.tr.x - ep.bl.x) <= (pbr.x - ptl.x)) { oImg.set({ left:pbr.x - (ep.tr.x - ep.tl.x) })}
                    if((ep.tr.x - ep.bl.x) > (pbr.x - ptl.x)) { oImg.set({ left:ptl.x }) }
                }
                et < ptl.y && oImg.set({ top:ptl.y })// 上侧超出
                if(eb > pbr.y) { // 下侧超出
                    if((ep.br.y - ep.tl.y) <= (pbr.y - ptl.y)) { oImg.set({ top:pbr.y - (ep.br.y - ep.tl.y) })}
                    if((ep.br.y - ep.tl.y) > (pbr.y - ptl.y)) { oImg.set({ top:ptl.y }) }
                }
                break;
            case 1:
                et = ep.bl.y;el = ep.br.x;eb = ep.tr.y;er = ep.tl.x;
                er > pbr.x && oImg.set({ left:pbr.x  })// 右侧超出
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.br.x });// 左侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.bl.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y - (ep.tr.y - ep.tl.y) })// 下侧超出
                break;
            case 2:
                et = ep.br.y;el = ep.tr.x;eb = ep.tl.y;er = ep.bl.x;
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.tr.x });// 左侧超出
                er > pbr.x && oImg.set({ left:pbr.x - (ep.bl.x - ep.tl.x)})// 右侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.br.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y  })// 下侧超出
                break;
            case 3:
                et = ep.tr.y;el = ep.tl.x;eb = ep.bl.y;er = ep.br.x;
                el < ptl.x && oImg.set({ left:ptl.x }); // 左侧超出
                er > pbr.x && oImg.set({ left:pbr.x - (ep.br.x - ep.tl.x)})// 右侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.tr.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y - (ep.bl.y - ep.tl.y) })// 下侧超出
        }
        mycanvas.renderAll()
    }
获取所有的对象: mycanvas.getObjects()
获取最后一个对象: var objList = mycanvas.getObjects(),obj = objList[objList.length-1]
获取被选中的对象: mycanvas.getActiveObject()

缩放和旋转没算出来, 代码删了留着日后解决,

思路二 (记录位置) 补充: 鼠标位移留痕不规则线条在如下代码中

方法非常简单, mousedown记录选中矩形状态信息, mouseup检测是否超出, 是则回退至原来的位置

// objectMov 位移
mycanvas.on({
            'mouse:down': this.mouseDownDrawRect, //按下,
            'mouse:move': this.mouseMoving, //移动中,
            'mouse:up': this.mouseUpDrawRect, //抬起,
            //'mouse:wheel': this.zoomsHandle, //缩放
            //'object:moved': this.objectMov, //移动完成
            //'object:moving': this.objectMov,//移动中
            //'object:scaled': this.mouseScaleDrawRect,//缩放完成
            //'object:scaling': this.mouseScalingDrawRect,//缩放中
            //'object:rotated': this.objectRotated,// 旋转完成
            //'object:rotating': this.objectRotated,// 旋转中
        });
        mouseDownDrawRect = () => {
            _this_obj : JSON.parse(JSON.stringify(mycanvas.getActiveObject()))
    	};
    	mouseMoving = (options) => {
    	// canvasPointSave 在 mouseUpDrawRect 中定义
        // 判断是否可以留痕
        if( chousedType == 0 && mycanvas.backgroundImage && canvasPointSave.tl){
            let ptl = canvasPointSave.tl,
            pbr = canvasPointSave.br,
            eposition = options.pointer;
            if ( eposition.x < ptl.x || eposition.x > pbr.x || eposition.y < ptl.y || eposition.y > pbr.y) {
                mycanvas.isDrawingMode = false;
            }else{
                mycanvas.isDrawingMode = true;
            }
        }
    };
    	mouseUpDrawRect = (options) => {
    	// 如果是鼠标画不规则线条, 则重新判断位置
    	mycanvas.isDrawingMode = false;
        let canvasObjArr = mycanvas.getObjects();
        if( chousedType == 0 && canvasObjArr.length > 0){
            this.referDrawRect();
        }
        // 如果是位移,缩放,旋转则计算位置
        if( options.transform ){
            if( options.transform.action== "drag"){
                this.objectMov();
            }
            if( options.transform.action== "scaleX" ||  options.transform.action== "scaleY" ||  options.transform.action== "scale"){
                this.mouseScalingDrawRect();this.objectMov();
            }
            if( options.transform.action== "rotate"){
                this.objectRotated();this.objectMov();
            }
        }else if(options.target){
            this.objectMov();
        }
        // 记录位置
        if(mycanvas.backgroundImage) { canvasPointSave = mycanvas.backgroundImage.lineCoords }
    };
    objectMov = (t) => {
        const { mainCanvas } = this.state;
        let mycanvas = mainCanvas,oImgList = mycanvas.getObjects(),oImg = t?oImgList[oImgList.length-1]:mycanvas.getActiveObject();
        if(!oImg) { return false;}
        let ep = oImg.aCoords,// 目标对象的四个坐标点
            angle= Math.floor(( oImg.angle ) / 90),// 目标对象的旋转角度
            ptl = mycanvas.backgroundImage.aCoords.tl,
            pbr = mycanvas.backgroundImage.aCoords.br,et = 0,el = 0,eb = 0,er = 0,w = 0,h = 0;
        switch (angle) {
            case 0:
                et = ep.tl.y;el = ep.bl.x;eb = ep.br.y;er = ep.tr.x;
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.bl.x }); // 左侧超出
                if(er > pbr.x) { // 右侧超出
                    if((ep.tr.x - ep.bl.x) <= (pbr.x - ptl.x)) { oImg.set({ left:pbr.x - (ep.tr.x - ep.tl.x) })}
                    if((ep.tr.x - ep.bl.x) > (pbr.x - ptl.x)) { oImg.set({ left:ptl.x }) }
                }
                et < ptl.y && oImg.set({ top:ptl.y })// 上侧超出
                if(eb > pbr.y) { // 下侧超出
                    if((ep.br.y - ep.tl.y) <= (pbr.y - ptl.y)) { oImg.set({ top:pbr.y - (ep.br.y - ep.tl.y) })}
                    if((ep.br.y - ep.tl.y) > (pbr.y - ptl.y)) { oImg.set({ top:ptl.y }) }
                }
                break;
            case 1:
                et = ep.bl.y;el = ep.br.x;eb = ep.tr.y;er = ep.tl.x;
                er > pbr.x && oImg.set({ left:pbr.x  })// 右侧超出
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.br.x });// 左侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.bl.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y - (ep.tr.y - ep.tl.y) })// 下侧超出
                break;
            case 2:
                et = ep.br.y;el = ep.tr.x;eb = ep.tl.y;er = ep.bl.x;
                el < ptl.x && oImg.set({ left:ptl.x + ep.tl.x - ep.tr.x });// 左侧超出
                er > pbr.x && oImg.set({ left:pbr.x - (ep.bl.x - ep.tl.x)})// 右侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.br.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y  })// 下侧超出
                break;
            case 3:
                et = ep.tr.y;el = ep.tl.x;eb = ep.bl.y;er = ep.br.x;
                el < ptl.x && oImg.set({ left:ptl.x }); // 左侧超出
                er > pbr.x && oImg.set({ left:pbr.x - (ep.br.x - ep.tl.x)})// 右侧超出
                et < ptl.y && oImg.set({ top:ptl.y + (ep.tl.y - ep.tr.y) })// 上侧超出
                eb > pbr.y && oImg.set({ top:pbr.y - (ep.bl.y - ep.tl.y) })// 下侧超出
        }
        mycanvas.renderAll()
    }
    mouseScalingDrawRect = () => {
        const { mainCanvas,_this_obj } = this.state;
        let mycanvas = mainCanvas,obj = mycanvas.getActiveObject();
        if(!obj) { return false;}
        let ep = obj.aCoords,// 目标对象的四个坐标点
            angle= Math.floor(( obj.angle ) / 90),et = 0,el = 0,eb = 0,er = 0,w = 0,h = 0;// 目标对象的旋转角度
        switch (angle) {
            case 0:
                et = ep.tl.y;el = ep.bl.x;eb = ep.br.y;er = ep.tr.x;
                w = ep.tr.x - ep.bl.x ;h = ep.br.y - ep.tl.y ;
                break;
            case 1:
                et = ep.bl.y;el = ep.br.x;eb = ep.tr.y;er = ep.tl.x;
                w = ep.tl.x - ep.br.x ;h = ep.tr.y - ep.bl.y ;
                break;
            case 2:
                et = ep.br.y;el = ep.tr.x;eb = ep.tl.y;er = ep.bl.x;
                w = ep.bl.x - ep.tr.x ;h = ep.tl.y - ep.br.y ;
                break;
            case 3:
                et = ep.tr.y;el = ep.tl.x;eb = ep.bl.y;er = ep.br.x;
                w = ep.br.x - ep.tl.x ;h = ep.bl.y - ep.tr.y ;
        }
        if(w > mycanvas.backgroundImage.width || h > mycanvas.backgroundImage.height){
            obj.set({ 
                scaleY: _this_obj.scaleY,
                scaleX: _this_obj.scaleX,
                left: _this_obj.left,
                top: _this_obj.top,
            }) 
        }
        mycanvas.renderAll()
    }
    referDrawRect = () => {
        const { mainCanvas } = this.state;
        let mycanvas = mainCanvas,objList = mycanvas.getObjects(),obj = objList[objList.length-1];
        if(!obj) { return false;}
        let scx = mycanvas.backgroundImage.width / obj.width;// -0.05
        let scy = mycanvas.backgroundImage.height / obj.height;// -0.05
        if (obj.scaleX > scx) {
            obj.set({scaleX:scx})
        };
        if (obj.scaleY > scy) {
            obj.set({scaleY:scy})
        };
        mycanvas.renderAll()
        this.objectMov(true)
    }
    objectRotated = () => {
        const { mainCanvas, _this_obj } = this.state;
        let mycanvas = mainCanvas,oImg = mycanvas.getActiveObject();// 目标对象
        if(!oImg) { return false;}
        let ep = oImg.aCoords,// 目标对象的四个坐标点
            angle= Math.floor(( oImg.angle ) / 90),// 目标对象的旋转角度
            ptl = mycanvas.backgroundImage.aCoords.tl,
            pbr = mycanvas.backgroundImage.aCoords.br,et = 0,el = 0,eb = 0,er = 0,w = 0,h = 0,lock = false;
        switch (angle) {
            case 0:
                et = ep.tl.y;el = ep.bl.x;eb = ep.br.y;er = ep.tr.x;
                w = ep.tr.x - ep.bl.x ;h = ep.br.y - ep.tl.y ;
                break;
            case 1:
                et = ep.bl.y;el = ep.br.x;eb = ep.tr.y;er = ep.tl.x;
                w = ep.tl.x - ep.br.x ;h = ep.tr.y - ep.bl.y ;
                break;
            case 2:
                et = ep.br.y;el = ep.tr.x;eb = ep.tl.y;er = ep.bl.x;
                w = ep.bl.x - ep.tr.x ;h = ep.tl.y - ep.br.y ;
                break;
            case 3:
                et = ep.tr.y;el = ep.tl.x;eb = ep.bl.y;er = ep.br.x;
                w = ep.br.x - ep.tl.x ;h = ep.bl.y - ep.tr.y ;
        }
        if(w > mycanvas.backgroundImage.width || h > mycanvas.backgroundImage.height ) {
            oImg.set({ 
                angle: _this_obj.angle,
                left: _this_obj.left,
                top: _this_obj.top,
            }) 
        }
        mycanvas.renderAll()
    }

注意事项

1, canvas 使用和 img 相关操作时 如果 跨域 需要加上 crossOrigin: 'anonymous' 属性;
2, fabric.js 是根据 html 中 canvas标签的id 来初始化的, 如需 初始化多个fabric , 则需 注意 canvas 标签的 id, 以及 window.全局配置的参数(使用vue和react时)
3, fabric 初始化过后的画布, 如果发生 位移缩放 , 再进行放置对象是要 进行计算


计算规则如下
// 发生位移计算
			// 右上角
            let tr = canvas.backgroundImage.lineCoords.tr;
            // 右下角
            let br = canvas.backgroundImage.lineCoords.br;
            // 左上角
            let tl = canvas.backgroundImage.lineCoords.tl;
            // 左下角
            let bl = canvas.backgroundImage.lineCoords.bl;
            //判断试卷最右侧 是否离开了可视区域
            if (tr.x <= 50) {
                var delta = new fabric.Point(50, 0);
                relativeMouseX += 50;
                canvas.relativePan(delta);
                return;
            }
            //判断试卷最上侧 是否离开了可视区域
            if (tr.y > screenHeight - 50) {
                var delta = new fabric.Point(0, -50);
                relativeMouseY -= 50;
                canvas.relativePan(delta);
                return;
            }
            //判断试卷最下侧 是否离开了可视区域
            if (br.y <= 50) {
                var delta = new fabric.Point(0, 50);
                relativeMouseY += 50;
                canvas.relativePan(delta);
                return;
            }
            //判断试卷最左侧 是否离开了可视区域
            if (tl.x > screenWidth - 50) {
                var delta = new fabric.Point(-50, 0);
                relativeMouseX -= 50;
                canvas.relativePan(delta);
                return;
            }

            var delta = new fabric.Point(options.e.movementX, options.e.movementY);
            canvas.relativePan(delta);
            relativeMouseX += options.e.movementX; //累计每一次移动时候的偏差
            relativeMouseY += options.e.movementY;





// 发生缩放计算
	//  缩放代码
		let wheelPost = e?e.e.deltaY:wheel,
            pointerX = e.pointer.x,
            pointerY = e.pointer.y,
            zoomSpeed = 0.03,
            zoom, zoomPoint, lastzoom, lastzoomPoint={x:0,y:0}, lastmousePoint={x:0,y:0}, relativeMouseX, relativeMouseY;// 通过zoomSpeed 控制缩放速度
        zoom = (wheelPost > 0 ? -zoomSpeed : zoomSpeed) + canvas.getZoom();
        zoom = Math.max(0.1, zoom); //最小为原来的1/10
        zoom = Math.min(3, zoom); //最大是原来的3倍
        zoomPoint = new fabric.Point(pointerX, pointerY);
        canvas.zoomToPoint(zoomPoint, zoom);

        lastzoomPoint.x =
            lastzoomPoint.x + (zoomPoint.x - lastmousePoint.x - relativeMouseX) / lastzoom;
        lastzoomPoint.y =
            lastzoomPoint.y + (zoomPoint.y - lastmousePoint.y - relativeMouseY) / lastzoom;

        lastmousePoint.x = zoomPoint.x;
        lastmousePoint.y = zoomPoint.y;
        lastzoom = zoom;

        relativeMouseX = 0;
        relativeMouseY = 0;

// 需要获取值时
	transformMouse = (mouseX, mouseY) => {
        let { lastzoomPoint,zoomPoint,relativeMouseX,relativeMouseY } = this.state;
        let {
            mainCanvas
        } = this.state;

        let mycanvas = mainCanvas;

        let x = lastzoomPoint.x + (mouseX - zoomPoint.x - relativeMouseX) / mycanvas.getZoom();
        let y = lastzoomPoint.y + (mouseY - zoomPoint.y - relativeMouseY) / mycanvas.getZoom();
        return { x, y };
    };
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

canvas插件 fabric.js 使用 的相关文章

  • Android中webview的截图方法

    我在 webview 中的 html5 canvas 上画了一些线 并尝试使用下面的代码截取 webview 的屏幕截图 WebView webView WebView findViewById R id webview webView s
  • 将剪贴板图像粘贴到画布

    我有一个画布 我需要用户能够将图像粘贴到上面 我希望这是跨浏览器的 我只想使用 html javascript 我也愿意使用 Flash 对象 这在 Chrome 中工作得很好 尽管到目前为止我还没有弄清楚如何让它在 Firefox 中工作
  • 即使光标位于画布之外也会调用 MouseMove 事件

    我不知道我的代码或 WPF 是否有问题 但问题是 我想创建一个小程序 您可以在其中用光标在画布上绘图 我有一个简单的 WPF 窗口
  • 如何清除WebGL中的矩形区域?

    WebGL 有一个clear清除整个表面的方法 清除表面的特定矩形的最佳方法是什么 例如 我想将一个从 50 50 开始的 100x100 像素框设置为全零 ARGB 0 0 0 0 我现在能想到的就是用一个写入零的片段着色器绘制一个四边形
  • A* 在 HTML5 Canvas 中开始寻路

    我正在尝试在我的游戏中实现 A Start 路径查找 用 JavaScript HTML5 Canvas 编写 A Start 的图书馆发现了这个 http 46dogs blogspot com 2009 10 star pathrout
  • 如何清除画布元素中的多边形区域?

    我使用过clearRect函数 但没有看到多边形的等效函数 我天真地尝试过 ctx fillStyle transparent ctx beginPath ctx moveTo 0 0 ctx lineTo 100 50 ctx lineT
  • DrawBitmapMesh 如何在 Android Canvas 中工作

    我想在矩形上绘制位图 我使用以下值 this meshWidth 1 this meshHeight 1 this verts new float 8 this points 0 x float this getWidth 4 this p
  • FloorPlanner 应用程序的 SVG/Canvas 与 Flash

    我计划创建一个平面图应用程序 允许用户使用鼠标绘制 调整大小 移动和旋转对象 我只是想知道使用 Flash 或 Javascript 是否会更好 如果使用 Javascript 我应该使用 canvas 还是 SVG 该应用程序将允许拖动选
  • HTML5 canvas:有没有办法通过“最近邻居”重新采样来调整图像大小?

    我有一些 JS 对图像进行一些操作 我想要类似像素艺术的图形 所以我必须在图形编辑器中放大原始图像 但我认为用小图像进行所有操作然后使用 html5 功能放大它是个好主意 这将节省大量处理时间 因为现在my demo http anal s
  • 在画布上剪出圆形图像

    我正在使用 html5 canvas 并且我正在创建一个游戏 可以将您的脸部上传到游戏中 并将其用作主要角色 不幸的是 游戏中的角色是圆形的 就像笑脸一样 那么这将如何完成呢 是否可以拍一张照片 然后将其剪成一个圆 这样圆之外的任何东西都是
  • html5 canvas 使用图像作为蒙版

    是否可以使用具有形状的图像作为整个画布或画布内图像的蒙版 我想将图像放置在画布中 并在图像上添加蒙版 然后将其另存为新图像 您可以使用 source in globalCompositeOperation 将黑白图像用作蒙版 首先 将蒙版图
  • WPF 画布缩放/变换以适合

    我重新发布这个问题 因为上次我没有得到太多答复 希望重新措辞可能有所帮助 本质上 我想做的是创建一个数据绑定画布 它将自动缩放其内容以 填充 可用空间 有点像缩放以适应操作 不幸的是 我的 WPF 技能还不是很强 我正在努力弄清楚如何完成最
  • HTML Canvas:旋转图像 3D 效果

    我怎样才能旋转图像 例如45度 并挤压图像 假设我有一个完美的方形图像 我可以将它旋转到我想要的任何角度 但我想让旋转后的正方形被压扁 使高度比宽度小 2 3 生成的图像将不是一个完美的旋转正方形 而是一个被压扁的正方形 你知道我怎样才能达
  • Python,Tkinter:如何获取可滚动画布上的坐标

    我有一个带有滚动条的 Tkinter 画布 还有一些项目 当我单击它们时 它应该返回坐标 使用Python 这对于窗口中最初可见的对象效果很好 但是 当我向下滚动并且画布上更下方的项目进入视图时 单击时我不会获得它们的画布坐标 而是获得窗口
  • 织物与预期

    我偶然发现pexpect http sourceforge net projects pexpect 我的印象是它看起来大致类似于fabric http fabfile org 我试图找到一些比较 但没有成功 所以我在这里询问 以防有人对这
  • jsPlumb:如何使流程图连接器避免元素相交?

    是否可以使 jsPlumb Flowchart 连接器不交叉可连接的项目或指定元素 在示例中 具有 item 类的元素 默认流程图行为 想要的结果 这是我尝试过的 http jsfiddle net CcfTD 1 http jsfiddl
  • 窗口调整大小事件上的响应式画布

    我是画布概念的新手 我正在尝试使用 D3 js 绘制画布 我想让画布根据窗口屏幕大小进行响应 function onResize var element document getElementsByTagName canvas 0 var
  • 三种js更新纹理生成Canvas的最佳性能方式

    I have THREE Points with THREE PointsMaterial As a map我使用生成的动态cavas image 我需要重新渲染canvas在每一帧上 我的部分代码 function makeEnemyBa
  • 使用 javascript 将 html 文本渲染为位图,无需服务器端代码

    我需要使用 javascript 代码来转换 html 中的文章 帖子 以便最终用户以位图的形式查看 有没有办法在没有服务器端代码的情况下做到这一点 example p testing text here p 您可以使用例如html2can
  • 调整图像大小并将画布旋转 90 度

    这里有很多关于在 js 上使用画布旋转图像的主题 我阅读了其中的大部分内容 但无法找到解决我的问题的方法 我正在接收任何分辨率的图像 来自上传组件 我将其大小调整为 1024x768 如下所示 var canvas document cre

随机推荐

  • 为什么每次进入命令都要重新source /etc/profile 才能生效?

    span style color 999988 编辑JDK8 span span style color 0086b3 export span JAVA HOME 61 span style color dd1144 34 usr java
  • MySQL配置文件my.ini的一般设置

    mysqld 设置3306端口 port 61 3306 设置mysql的安装目录 basedir 61 D Software Package mysql 8 0 12 winx64 mysql 8 0 12 winx64 设置mysql数
  • Linux shell脚本编程时bad substitution解决办法

    首先 xff0c 我们要理解bad substitution的字面意思 xff0c 它的字面意思是 替换错误 的意思 这种错误的原因呢 xff0c 通常是我们编写脚本时 和 xff08 xff09 错误使用导致的 比如应该用 xff08 x
  • Vue中的watch 和computed 属性

    之前写过一篇关于computed计算属性的文章 xff0c 详见这里 computed 内的function只执行一次 xff0c 仅当function内涉及到Vue实例绑定的data的值的改变 xff0c function才会从新执行 x
  • Swift使用XMPPFramework做IM即时通信的Demo

    上一篇文章处理了文本中表情的替换 xff0c 现在来完成消息的发送功能吧 xff08 貌似前后并没有逻辑关系哈 xff09 首先为了测试 xff0c 我们需要下载spark工具 xff0c 它可以连接openfire搭建的后台来完成即时通信
  • P1591 阶乘数码

    题目描述 求n 中某个数码出现的次数 输入格式 第一行为 t t 10 xff0c 表示数据组数 接下来 t 行 xff0c 每行一个正整数n n 1000 和数码 a 输出格式 对于每组数据 xff0c 输出一个整数 xff0c 表示 n
  • nginx缓存命中率统计(转)

    转自 xff1a http www libertyvps com thread 275 1 1 html nginx提供了 upstream cache status这个变量来显示缓存的状态 xff0c 我们可以在配置中添加一个http头来
  • windows远程桌面连接到Linux服务器(ubuntu系统)、解决xrdp登录界面port问题、解决password failed

    一 xff1a 一般在windows系统安装ssh客户端远程连接Linux服务器 xff0c 可以很方便地传输文件 xff08 注意 xff1a 文件路径不能有小括号 xff0c 空格之类的 xff0c 不然会出现erro xff09 但如
  • linux之文件系统命令

    第一章 linux之帮助命令 第二章 linux命令行快捷键 第三章 linux之防火墙 第四章 linux之服务开机自启 第五章 linux之关机与重启 第六章 linux之环境变量 第七章 linux之目录操作命令 第八章 linux之
  • 解决linux底下cmake编译使用C++ 11标准库自带的thread报错问题

    本人在编写linux底下socket编程测试服务端时候 xff0c 发现使用std thread函数时候 xff0c cmake编译通过 xff0c make编译失败 xff0c CMakeLists txt如下 xff1a cmake m
  • unity UGUI 解决ScrollView加载大量Item导致卡顿的问题

    目录 1 引言2 问题分析3 代码部分4 使用举例4 1 场景搭建4 2 测试4 3 效果展示 5 Demo下载6 结束语 1 引言 我们在平常的开发中常常碰到列表类的数据处理 xff01 典型的像玩家列表这种可能数量非常庞大 xff0c
  • 使用 Amazon EC2 启动 Windows 虚拟机

    本教程将教授您如何使用 Amazon Elastic Compute Cloud EC2 来启动 配置和连接至 Windows 虚拟机 Amazon EC2 是用于在云中创建和运行虚拟机 xff08 我们将这些虚拟机称为 实例 xff09
  • linux ss 命令用法说明

    ss 是 Socket Statistics 的缩写 ss 命令可以用来获取 socket 统计信息 xff0c 它显示的内容和 netstat 类似 但 ss 的优势在于它能够显示更多更详细的有关 TCP 和连接状态的信息 xff0c 而
  • 谷歌浏览器 跨域遇到的坑 cors 错误(亲测可行)

    浏览器版本 xff1a 一 现象 xff1a 解决方案 xff1a 方案一 xff1a xff08 已论证 xff09 步骤1 xff1a 谷歌浏览器 打开 chrome flags block insecure private netwo
  • 安装Visual Studio 2015时出现安装包丢失或损坏

    1 现象描述 在线安装vs时 xff0c 在线下载一直为0 xff0c 提示网络异常 xff0c 检查网络 xff1b 实际网络是能联网的 离线安装ISO xff0c 安装1分钟左右 提示安装包损坏或丢失 xff0c 选择从inter下载或
  • 数据库实验-数据查询练习

    用SQL语句完成以下查询 1 查询所在系为 CS 的学生学号和姓名 xff1b select sno sname from student where sdept 61 39 CS 39 2 查询选修了3号课程的学生学号 xff1b sel
  • web前端播放视频基础(多种格式,mp4, ogg, flv)(普通项目和vue项目)

    前端播放视频 满足一般播放条件 话不多说 先上代码 以下包含我能做出来可以做出来播放的视频格式 测试ok 可能还有ogg和wmv的格式可以播放 但我没测试通过 所以不展示 span class token keyword if span s
  • javascript中正则匹配多个条件, 常用正则匹配, 正则详解

    javascript中正则匹配多个条件 常用正则匹配 正则表达式常用方法实现其他的常用正则匹配详解 注意 本篇文章是根据在下日常编码过程中逐渐丰富的 越往后看 收获越丰富 收藏起来以后随时回顾 准备工作 1 汉字和unicode码的在线转换
  • antd react ProTable 基本使用

    antd react pro系列 ProTable 基本使用 一 安装二 常用字段 antd 全称 Ant Design 是目前来说运用最广泛的 react 的 ui 框架 下文就用略写 antd 代替了 pro系列不做过多解释 毕竟ui框
  • canvas插件 fabric.js 使用

    fabric js使用 fabric js 是 常用的 canvas 插件1 在项目中使用2 特殊用法 基本设置 画板数据的导入导出 遮罩 Pattern 引用官网案例 多个对象合并 并设置为 fabric 背景 适用于变色和更多场景 把