< 返回技术文档列表

前台js实现canves画布中拖拽、放大、缩小、旋转图片和文字,设置背景图片,导出

发布时间:2022-11-15 22:11:42⊙投诉举报

最近在研究canves,想实现一个可以在画布中操作上传的内容,不经意间发现了个插件Fabric.js。Fabric.js 是一个强大的H5 canvas框架,在原生canvas之上提供了交互式对象模型,通过简洁的api即可以在画布上进行丰富的操作。该框架是个开源项目,官网地址:Fabric.js Javascript Canvas Library     


image

安装

npm安装

npm install fabric --save

cmd安装

<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>

<script src="https://unpkg.com/coco-modal/coco-modal.min.js"></script> 弹框插件

初始化

首先在html页面中写一个350 x 200的canvas标签, 这里不写宽高也行,后面可以通过js来设置宽高

<canvas id="canvas" width="350" height="200"></canvas>

初始化fabric的canvas对象,创立一个卡片(后面都用card表示画布对象)

constcard =newfabric.Canvas('canvas')// ...这里可以写canvas对象的少量配置,后面将会详情

// 假如<canvas>标签没设置宽高,可以通过js动态设置

card.setWidth(350)card.setHeight(200)

设置画布和监听事件

// 在canvas对象初始化后,通过以下方式监听

        // 比方监听画布的图层编辑事件

        exportCanves.onclick = function(e) {

            // 导出当前画布信息

            const currState = card.toJSON(); // 导出的Json如下图

            console.log(currState)

            // 加载画布信息

            // card.loadFromJSON(lastState, () => {

            //     card.renderAll();

            // });

            const dataURL = card.toDataURL({

                format: 'jpeg', // jpeg或者png

                quality: 1.8 // 图片质量,仅jpeg时可用

                // 截取指定位置和大小

                //left: 100,

                //top: 100,

                //width: 200,

                //height: 200

            });

            downloadIamge(dataURL, 'img')

        }

        card.on('object:modified', (e) => {

            console.log(e.target) // e.target为当前编辑的Object

            objectMoving(e)

            objectModified(e)

            // ...旋转,缩放,移动等编辑图层的操作都监听到

            // 所以假如有撤销/恢复的场景,这里可以保存编辑状态

        });

        // 设置画布背景颜色

        card.backgroundColor = 'white';

        // 或者者

        // card.setBackgroundColor('blue');

        let selectedObj

        // 方式二

        card.on('selection:created', (e) => {

            // 选中图层事件触发时,动态升级赋值

            console.log(e.target)

            selectedObj = e.target

            // 顺时针90°旋转

            const currAngle = selectedObj.angle; // 当前图层的角度

            const angle = currAngle === 360 ? 90 : currAngle + 90;

            // selectedObj.rotate(angle);

            // 假如是通过滑块的方式控制旋转

            // selectedObj.rotate(slideValue);

            // 水平翻转,同理垂直翻转改为scaleY属性

            // selectedObj.set({

            //     scaleX: -selectedObj.scaleX,

            // })

            //移除图层

            // card.remove(selectedObj) // 传入需要移除的object

            // 所有图层的操作之后,都需要调用这个方法

            card.renderAll()

        })

操作画布中的图层和文字

当对象移动时 限制对象的 不超出画布,当画布对象放大时限制其操出边界

<div class="button-box">

            <div class="upload-box">

                <button class="button"><label for="addBgImg">增加背景图片</label></button>

                <input style="display: none;" class="button" type="file" accept="image/*" name="uploader-input" class="uploader-file" id="addBgImg">

            </div>

            <div class="upload-box">

                <button class="button"><label for="addimg">增加图片</label></button>

                <input style="display: none;" class="button" type="file" accept="image/*" name="uploader-input" class="uploader-file" id="addimg">

            </div>

            <button class="button" id="addtext">增加文字</button>

            <button class="button" id="remove">删除元素</button>

            <button class="button" id="exportCanves">导出图片</button>

        </div>

const exportCanves = document.getElementById("exportCanves")

        const addimg = document.getElementById("addimg")

        const addBgImg = document.getElementById("addBgImg")

        const addtext = document.getElementById("addtext")

        const remove = document.getElementById("remove")

function downloadIamge(imgsrc, name) { //下载图片地址和图片名

            let image = new Image();

            // 处理跨域 Canvas 污染问题

            image.setAttribute("crossOrigin", "anonymous");

            image.onload = function() {

                let canvas = document.createElement("canvas");

                canvas.width = image.width;

                canvas.height = image.height;

                let context = canvas.getContext("2d");

                context.drawImage(image, 0, 0, image.width, image.height);

                let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据

                let a = document.createElement("a"); // 生成一个a元素

                let event = new MouseEvent("click"); // 创立一个单击事件

                a.download = name || "photo"; // 设置图片名称

                a.href = url; // 将生成的URL设置为a.href属性

                a.dispatchEvent(event); // 触发a的单击事件

            };

            image.src = imgsrc;

        }

        //点击增加背景图片

        addBgImg.onchange = function(event) {

            var $file = event.currentTarget;

            var formData = new FormData();

            var file = $file.files;

            formData = new FormData();

            formData.append(file[0].name, file[0]);

            var path = window.URL.createObjectURL(file[0]);

            // 读取图片地址,设置画布背景图片

            fabric.Image.fromURL(path, (img) => {

                img.set({

                    // 通过scale来设置图片大小,这里设置和画布一样大

                    scaleX: card.width / img.width,

                    scaleY: card.height / img.height,

                });

                // 设置背景

                card.setBackgroundImage(img, card.renderAll.bind(card));

                card.renderAll();

            });

        }

        // 点击增加文字

        addtext.onclick = function(e) {

            getDialog()

        }

        // 点击删除元素

        remove.onclick = function(e) {

            card.remove(card.getActiveObject())

            card.renderAll()

        }

        // 当对象移动时 限制对象的 不超出画布

        function objectMoving(e) {

            var obj = e.target;

            if (obj.currentHeight > obj.canvas.height || obj.currentWidth > obj.canvas.width) {

                return;

            }

            obj.setCoords();

            // top-left corner

            if (obj.getBoundingRect().top < 0 || obj.getBoundingRect().left < 0) {

                obj.top = Math.max(obj.top, obj.top - obj.getBoundingRect().top);

                obj.left = Math.max(obj.left, obj.left - obj.getBoundingRect().left);

            }

            // bot-right corner

            if (obj.getBoundingRect().top + obj.getBoundingRect().height > obj.canvas.height || obj.getBoundingRect().left + obj.getBoundingRect().width > obj.canvas.width) {

                obj.top = Math.min(obj.top, obj.canvas.height -

                    obj.getBoundingRect().height + obj.top -

                    obj.getBoundingRect().top);

                obj.left = Math.min(obj.left, obj.canvas.width -

                    obj.getBoundingRect().width + obj.left - obj.getBoundingRect().left);

            }

        }

        // 当画布对象放大时限制其操出边界:

        //在对象修改时方法里即可以调用了。

        function objectModified(e) {

            let obj = e.target;

            let boundingRect = obj.getBoundingRect(true);

            if (boundingRect.left < 0 || boundingRect.top < 0 || boundingRect.left + boundingRect.width > obj.canvas.getWidth() || boundingRect.top + boundingRect.height > obj.canvas.getHeight()) {

                obj.top = obj._stateProperties.top;

                obj.left = obj._stateProperties.left;

                obj.angle = obj._stateProperties.angle;

                obj.scaleX = obj._stateProperties.scaleX;

                obj.scaleY = obj._stateProperties.scaleY;

                obj.setCoords();

                obj.saveState();

            } else {

                obj.saveState();

            }

        }

        //输入弹框

        function getDialog() {

            window.CocoConfig = {

                maskClose: true,

                header: true,

                footer: true,

                title: '提醒',

                text: '',

                width: '300px',

                top: '30vh',

                inputAttrs: true,

                escClose: true,

                okButton: true,

                cancelButton: true,

                okText: '确定',

                cancelText: '取消',

                closeButton: true,

                html: '',

                zIndexOfModal: 1995,

                zIndexOfMask: 2008,

                zIndexOfActiveModal: 2020,

                autoFocusOkButton: true,

                autoFocusInput: true,

                fullScreen: false,

                borderRadius: '6px',

                blur: false,

                buttonColor: '#4285ff',

                hooks: {

                    open() {},

                    opened() {

                    },

                    close() {},

                    closed() {},

                },

                destroy: true,

                animation: true

            }

            coco({

                title: "请输入你要增加的内容",

                html: '',

            }).onClose((cc, isOk, done) => {

                let tmr = null;

                if (cc) { //true 确认

                    isOk.showLoading();

                    if (addtextByCanves(isOk.inputValue)) {

                        isOk.hideLoading();

                        done();

                    }

                } else {

                    clearTimeout(tmr);

                    isOk.hideLoading();

                    done();

                }

            });

        }

        //将输入的内容加入到canves中

        function addtextByCanves(text) {

            const contant = new fabric.Textbox(text, {

                left: 50,

                top: 50,

                width: 150,

                fontSize: 20, // 字体大小

                fontWeight: 800, // 字体粗细

                // fill: 'red', // 字体颜色

                // fontStyle: 'italic',  // 斜体

                // fontFamily: 'Delicious', // 设置字体

                // stroke: 'green', // 描边颜色

                // strokeWidth: 3, // 描边宽度

                hasControls: false,

                borderColor: 'orange',

                editingBorderColor: 'blue' // 点击文字进入编辑状态时的边框颜色

            });

            // 增加文字

            card.add(contant);

            return true

        }

        //上传图片事件

        document.getElementById('addimg').addEventListener('change', function(event) {

            var $file = event.currentTarget;

            var formData = new FormData();

            var file = $file.files;

            formData = new FormData();

            formData.append(file[0].name, file[0]);

            let path = window.URL.createObjectURL(file[0]);

            addimgByCanves(path)

        });

        //将图片加入canves

        function addimgByCanves(imgUrl) {

            fabric.Image.fromURL(imgUrl, (img) => {

                img.set({

                    hasControls: true, // 能否开启图层的控件

                    borderColor: 'orange', // 图层控件边框的颜色

                });

                //生成的图片缩放到指定的尺寸。

                // img.scaleToWidth(500);

                img.scaleToHeight(100);

                // 增加对象

                card.add(img);

            });

        }


/template/Home/Zkeys/PC/Static