canvas之自定义头像功能实现代码示例


Posted in HTML / CSS onSeptember 29, 2017

写在最前:

前两天老大跟我说老虎官网上那个自定义头像的功能是flash实现的,没有安装过的还得手动去“允许”falsh的运行。所以让我用canvas实现一个一样的功能,嘿嘿,刚好最近也在研究canvas,所以欣然答应(其实,你没研究过难道就不答应么,哈哈哈哈哈~)

成果展示:

canvas之自定义头像功能实现代码示例

Git地址:https://github.com/ry928330/portraitDIY

功能说明:

  • 拖拽左侧小方框,或者是鼠标放在小方框右下角,点击拉伸方框,方框覆盖部分的图片被自动截取下来,然后再在右侧的多个容器里面重绘。
  • 输入宽高,自定义你需要订制的头像大小,目前只支持宽高相同的头像图片。

实现细节:

因为你要对图片所在的区域进行截图,所以你得制作一张canvas,盖在图片所在的区域。这里,我们给出了一个函数,根据传入的DOM里面元素的类名创建相同位置的canvas,盖在原来的DOM元素上面:

function createCanvasByClassName(tag) {
    var canvasInitialWidth = $('.' + tag).width();
    var canvasInitialHeight = $('.' + tag).height();
    var left = $('.' + tag).offset().left - $('.' + tag).parent('.portraitContainer').offset().left + 1;
    var top = $('.' + tag).offset().top - $('.' + tag).parent('.portraitContainer').offset().top + 1;
    //var left = $('.' + tag).offset().left + 1;
    //var top = $('.' + tag).offset().top + 1;
    clearCanvasObj.left = $('.' + tag).offset().left + 1;
    clearCanvasObj.top = $('.' + tag).offset().top + 1;
    // clearCanvasObj.left = left;
    // clearCanvasObj.top = top;
    var canvasElement = $('<canvas></canvas>');
    var randomNum = Math.floor(getRandom(0, 10000));
    clearCanvasObj.canvasId = randomNum;
    canvasElement.attr({
        id: 'canvas',
        width: canvasInitialWidth,
        height: canvasInitialHeight
    });
    canvasElement.css({
        position: 'absolute',
        top: top, 
        left: left
    });
    //$('body').append(canvasElement);
    var appendEle = $('.portraitContainer').append(canvasElement);
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    //ctx.fillStyle = "rgba(211,211,216,0.5)";
    ctx.clearRect(0, 0, canvasInitialWidth, canvasInitialHeight);
    ctx.fillStyle = "rgba(0,0,0, 0.4)";
    ctx.fillRect(0, 0, canvasInitialWidth, canvasInitialHeight);
    return canvas;
}

有了这张canvas你就可以在你图片所在区域肆意的操作了。首先,降整个区域画上一个浅黑色的阴影,然后再擦除初始小方框区域里面的颜色。然后给整个页面添加mousedown,mousemove,mouseup事件,他们所做的功能就跟你在页面中实现一个拖拽的功能类似,这里重点说下mousemove里面做的操作,代码如下:

function mousemoveFunc(event) {
    /* Act on the event */
    var nowMouseX = event.clientX - clearCanvasObj.left;
    var nowMouseY = event.clientY - clearCanvasObj.top;
    if (nowMouseX >= clearCanvasObj.xStart && nowMouseX <= clearCanvasObj.xStart + clearCanvasObj.width && nowMouseY >= clearCanvasObj.yStart && nowMouseY <= clearCanvasObj.yStart + clearCanvasObj.height) {
        clearCanvasObj.isCanvasArea = true;
        //clearCanvasObj.isRightCorner = false;
        imgContainerCanvas.style.cursor = 'move';
    } else if ((nowMouseX >= clearCanvasObj.xStart + clearCanvasObj.width - 10) && (nowMouseX <= clearCanvasObj.xStart+ clearCanvasObj.width + 10) 
        && (nowMouseY >= clearCanvasObj.yStart + clearCanvasObj.height - 10) && (nowMouseY <= clearCanvasObj.yStart + clearCanvasObj.height + 10)) {
        clearCanvasObj.isCanvasArea = true;
        //clearCanvasObj.beginDraw = false;

        imgContainerCanvas.style.cursor = 'se-resize';
    } 
    else {
        clearCanvasObj.isCanvasArea = false;
        //clearCanvasObj.isRightCorner = false;
        imgContainerCanvas.style.cursor = 'default';
    }
    var outerDomWidth = $(".imgContainer").width();
    var outerDomHeight = $(".imgContainer").height();
    var xDistance = event.clientX - clearCanvasObj.mouseX;
    var yDistance = event.clientY - clearCanvasObj.mouseY;
    //var outerCTX = canvas.getContext('2d');
    //移动小方框
    if (clearCanvasObj.beginDraw && clearCanvasObj.isCanvasArea && !clearCanvasObj.isRightCorner) {
        ry_CTX.fillStyle = clearCanvasObj.color;
        // console.log('1', clearCanvasObj.xStart, clearCanvasObj.yStart)
        ry_CTX.fillRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
        //outerCTX.fillRect(0, 0, canvas.width, canvas.height);
        clearCanvasObj.xStart += xDistance;
        clearCanvasObj.yStart += yDistance;

        //判断方框是否达到边界
        if (clearCanvasObj.xStart <= 0) {
            clearCanvasObj.xStart = 0;
        }
        if (clearCanvasObj.yStart <= 0) {
            clearCanvasObj.yStart = 0;
        }
        if ((clearCanvasObj.xStart + clearCanvasObj.width) >= outerDomWidth) {
            clearCanvasObj.xStart = outerDomWidth - clearCanvasObj.width;
        }
        if ((clearCanvasObj.yStart + clearCanvasObj.height) >= outerDomHeight) {
            clearCanvasObj.yStart = outerDomHeight - clearCanvasObj.height;
        }
        // console.log('2', clearCanvasObj.xStart, clearCanvasObj.yStart)
        ry_CTX.clearRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
        produceSmallPic(clearCanvasObj.xStart+clearCanvasObj.left, clearCanvasObj.yStart+clearCanvasObj.top, clearCanvasObj.width, clearCanvasObj.height, imageURL)
        clearCanvasObj.mouseX = event.clientX;
        clearCanvasObj.mouseY = event.clientY;
    }
    //拖拽小方框
    if (clearCanvasObj.isRightCorner) {
        ry_CTX.fillStyle = clearCanvasObj.color;
        ry_CTX.fillRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
        var realDistance = Math.min(xDistance, yDistance)
        clearCanvasObj.width +=  realDistance;
        clearCanvasObj.height += realDistance;
        //拖动时边界条件的判断
        if (clearCanvasObj.xStart + clearCanvasObj.width >= outerDomWidth) {
            clearCanvasObj.width = outerDomWidth - clearCanvasObj.xStart;
            clearCanvasObj.height = outerDomWidth - clearCanvasObj.xStart;
        }
        if (clearCanvasObj.yStart + clearCanvasObj.height >= outerDomHeight) {
            clearCanvasObj.width = outerDomHeight - clearCanvasObj.yStart;
            clearCanvasObj.height = outerDomHeight - clearCanvasObj.yStart;
        }
        if (clearCanvasObj.width <= 10) {
            clearCanvasObj.width = 10;
        }
        if (clearCanvasObj.height <= 10) {
            clearCanvasObj.height = 10;
        }
        ry_CTX.clearRect(clearCanvasObj.xStart, clearCanvasObj.yStart, clearCanvasObj.width, clearCanvasObj.height);
        produceSmallPic(clearCanvasObj.xStart+clearCanvasObj.left, clearCanvasObj.yStart+clearCanvasObj.top, clearCanvasObj.width, clearCanvasObj.height, imageURL);
        clearCanvasObj.mouseX = event.clientX;
        clearCanvasObj.mouseY = event.clientY;
    }                            
}

函数里面,你需要注意拖拽的边界条件,一个是方框不能拖到图片所在DOM外的边界;另外一个就是当你鼠标放在小方框所在的区域改变鼠标的样式。方框在拖动的过程中,我们不断重绘方框移动的区域(也就是不断的画上阴影),然后在新的位置调用clearRect函数,重新擦出一个小方框出来。在拖拽或是拉伸的过程中,我们会不断调用produceSmallPic函数,在右边的容器(每个容器都是一个canvas)里面不断根据容器大小重绘出所需的头像。代码如下:

function produceSmallPic(imageURL,left, top, width, height) {
    var img = new Image();
    img.src = imageURL;
    var targetCtx = new Array();
    var targetCanvas = null;
    img.onload = function() {
        portraitGroupsArr.forEach(function(item, index) {
            targetCanvas = document.getElementById(item.class);
            targetCtx.push(targetCanvas.getContext('2d'));
            targetCtx[index].clearRect(0,0, item.width, item.height);
            targetCtx[index].drawImage(img, left - clearCanvasObj.left, top - clearCanvasObj.top, width, height, 0, 0 , item.width, item.height);
        })
    }
}

我们说下这个函数的作用,这里我们要注意一个参数imageURL,这个URL是由图片所在的DOM转化来的。因为你要把DOM所在的区域变成一张图片,这样你才能在利用drawImage函数截取你所需要的区域。所以我们先利用html2canvas库函数讲图片所在的DOM转化为canvas,这张canvas的内容是包含你所要截取的图片的,然后把这张canvas转化为图片取得图片地址imageURL,代码如下:

html2canvas(document.getElementById('imgContainer'), {
        onrendered: function(canvas) {
            var imageURL = canvasTransToImage(canavs);
            ...
        }

})
function canvasTransToImage(canvas) {
    var imageURL = canvas.toDataURL('image/png');
    return imageURL;
}

接着,你就可以便利右侧的canvas容器,讲图片重回到里面了,整个过程就这样结束,回头看来是不是很简单。

相关依赖:

复制代码
代码如下:

<script src="<a href="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js"></script">https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.min.js"></script</a>>

写在最后:

canvas的操作,要多多注意那些边界条件,什么时候该重绘什么时候该清除,这些是比较重要的。逻辑清晰了,canvas本身的API也就那么几个,操作起来也就没那么麻烦了,最后,谢谢大家查阅,写的不是很清楚,有不懂的可以一起讨论~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
css3 position fixed固定居中问题解决方案
Aug 19 HTML / CSS
一款纯css3实现的响应式导航
Oct 31 HTML / CSS
什么是CSS3 HSLA色彩模式?HSLA模拟渐变色条
Apr 26 HTML / CSS
CSS3中的@keyframes关键帧动画的选择器绑定
Jun 13 HTML / CSS
html5仿支付宝密码框的实现代码
Sep 06 HTML / CSS
HTML5等待加载动画效果
Jul 27 HTML / CSS
html5嵌入内容_动力节点Java学院整理
Jul 07 HTML / CSS
HTML5的革新 结构之美
Jun 20 HTML / CSS
Html5游戏开发之乒乓Ping Pong游戏示例(二)
Jan 21 HTML / CSS
详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)
Dec 15 HTML / CSS
html5超简单的localStorage实现记住密码的功能实现
Sep 07 HTML / CSS
Html5踩坑记之mandMobile使用小记
Apr 02 HTML / CSS
html5如何在Canvas中实现自定义路径动画示例
Sep 18 #HTML / CSS
HTML5在线预览PDF的示例代码
Sep 14 #HTML / CSS
HTML5 拖放(Drag 和 Drop)详解与实例代码
Sep 14 #HTML / CSS
HTML5页面中尝试调起APP功能
Sep 12 #HTML / CSS
html5使用canvas实现弹幕功能示例
Sep 11 #HTML / CSS
基于HTML5+CSS3实现简单的时钟效果
Sep 11 #HTML / CSS
html5超简单的localStorage实现记住密码的功能实现
Sep 07 #HTML / CSS
You might like
Joomla语言翻译类Jtext用法分析
2016/05/05 PHP
PHP实现生成数据字典功能示例
2018/05/24 PHP
js模拟弹出效果代码修正版
2008/08/07 Javascript
JavaScript 学习初步 入门教程
2010/03/25 Javascript
js中的onchange和onpropertychange (onchange无效的解决方法)
2014/03/08 Javascript
nodejs npm install全局安装和本地安装的区别
2014/06/05 NodeJs
用jquery实现动画跳到顶部和底部(这个比较简单)
2014/09/01 Javascript
基于jquery的手风琴图片展示效果实现方法
2014/12/16 Javascript
jQuery使用$.get()方法从服务器文件载入数据实例
2015/03/25 Javascript
深入理解JavaScript中Ajax
2016/08/02 Javascript
Vue入门之数据绑定(小结)
2018/01/08 Javascript
nginx部署访问vue-cli搭建的项目的方法
2018/02/12 Javascript
JS逻辑运算符短路操作实例分析
2018/07/09 Javascript
vue多层嵌套路由实例分析
2019/03/19 Javascript
微信网页登录逻辑与实现方法
2019/04/29 Javascript
防止Layui form表单重复提交的实现方法
2019/09/10 Javascript
vue 解决移动端弹出键盘导致页面fixed布局错乱的问题
2019/11/06 Javascript
vue-video-player视频播放器使用配置详解
2020/10/23 Javascript
python统计文本字符串里单词出现频率的方法
2015/05/26 Python
Python爬虫工程师面试问题总结
2018/03/22 Python
python读取目录下最新的文件夹方法
2018/12/24 Python
Python爬虫学习之获取指定网页源码
2019/07/30 Python
关于python导入模块import与常见的模块详解
2019/08/28 Python
使用python写一个自动浏览文章的脚本实例
2019/12/05 Python
Python实现中英文全文搜索的示例
2020/12/04 Python
Intimissimi德国网上商店:意大利知名内衣品牌
2018/04/03 全球购物
Koral官方网站:女性时尚运动服
2019/04/10 全球购物
物业客服专员岗位职责
2013/11/30 职场文书
内业资料员岗位职责
2014/01/04 职场文书
缴纳养老保险的证明
2014/01/10 职场文书
机工车间主任岗位职责
2014/03/05 职场文书
纪检干部先进事迹材料
2014/08/23 职场文书
致创业的您:这类人不适合餐饮创业
2019/08/19 职场文书
goland设置颜色和字体的操作
2021/05/05 Golang
浅谈mysql增加索引不生效的几种情况
2021/06/23 MySQL
openEuler 搭建java开发环境的详细过程
2022/06/10 Servers