利用canvas制作图片(可缩放和平移)+相框+文字

前言:

  公司一个售前问我能不能用H5做一个手机拍照,给相片添加相框和添加文字上传到服务器的功能,我当时一琢磨觉得可行,就利用空余时间做了一个demo,去掉了拍照和上传,如果以后有机会,会给补上,当然对于开发过webApp的朋友来做到这个很简单。下面来看代码

1,思路

 首先我们需要准备素材,一个相框和一个相片,然后我们要思考,只是把他们和并且就可以了吗?答案是否定的,我还需要对照片进行编辑,比如平移和缩放等。还要可以切换相框。

2,如何合并相框和图片?

  

上面是我的界面,从界面可以看出,我有三张图片和两个相框,最右边是相框和图片合并之后的结果。看代码:

html:

    <style>
        body,html,ul,li,h1,h5,a,p,span,div{
            margin: 0px;
            padding: 0px;
        }
        ul,li{
            list-style: none;
        }
        .wrap{
            position: relative;
            margin:40px;
            width: 1000px;
            height: 400px;
            background-color: #fff;
            box-shadow: 0px 0px 1px 1px #eee;
        }
        .imgWrap,
        .photoWrap{
            width: 100px;
            height: 380px;
            float: left;
            border: 1px solid #ccc;
            margin:10px 40px 10px 40px;
            text-align: center;
        }
        .imgWrap img{
            width: 60px;
            height: 100px;
        }
        .photoWrap img{
            width: 90px;
            height: 140px;
        }
        .photoWrap_canvas{
            position: absolute;
            /*opacity: 0.4;*/
            width: 300px;
            left: 365px;
            height: 400px;
            /*background-color: red;*/
        }
    </style>

    <div class="wrap">
        <div class="photoWrap_canvas" id="photoWrap_canvas" >

        </div>
        <canvas id="myCanvas" width="300" height="400"  style="background-color:#ccc"></canvas>
        <div class="photoWrap" id="photoWrap">
            <ul>
                <li><img  src="img/xk1.png" alt=""></li>
                <li><img  src="img/xk2.png" alt=""></li>
            </ul>
        </div>
        <div class="imgWrap">
            <ul>
                <li><img   src="img/mm1.jpg" alt=""></li>
                <li><img   src="img/mm2.jpg" alt=""></li>
                <li><img   src="img/mm3.jpg" alt=""></li>
            </ul>
        </div>
        <div>
            <input type="text" id="txtKey">
            <button id="btnAddFont">输入</button>
            <button id="btnOk">完成</button>
            <button id="btnReset">还原</button>
        </div>
    </div>

js:

            var _ = function(selector){return document.getElementById(selector);}
            var util = {
                isNull:function(str){return str == null || str.length == 0 }
            }
            var c = _("myCanvas");
            var ctx = c.getContext("2d");
            var ctxW = c.width,
                ctxH = c.height;

            var img = new Image();
                img.src = "img/mm2.jpg";
            var imgW,imgH;

            img.onload=function(){

                imgW = 300 || img.width,
                imgH = 400 || img.height;

                onDraw();

                ctx.save();
            }

            function onDraw(){
                ctx.drawImage(img,0,0,300,400);
            }

            // 切换相册
            $(".photoWrap").delegate("ul li img","click",function(){
                var src = $(this).attr("src");
             $(".photoWrap_canvas").css("background","url("+src+") no-repeat").css("background-size","100% 100%").attr("data-url",src);
            })

看到上面的代码,很简单,

  1,获取一个canvas标签,然后利用getContext("2d")获取到一个画布对象;

  2,创建一个image对象,给它添加src属性

  3,图片加载完毕使用 drawImage()把img对象画到canvas里面,

  4,再给div.photoWrap的div添加背景图片,(通过给canvas添加一个透明的蒙层可以做一个切换相框的效果)

3,如何平移图片?

  

以上效果,通过移动鼠标来设置图片的位置。看代码:

      // 移动相册的动作
            var hasTouch = ‘ontouchstart‘ in window;
            // console.log(window);
            var STA_EN = hasTouch ? "touchstart" : "mousedown",
                MV_EV = hasTouch ? "touchmove":"mousemove",
                END_EV = hasTouch ? "touchend" : "mouseup",
                END_Cancel = hasTouch ? "touchcancel" : "mouseout";

            _("photoWrap_canvas").addEventListener(STA_EN,start,false);
            _("photoWrap_canvas").addEventListener(MV_EV,move,false);
            _("photoWrap_canvas").addEventListener(END_EV,end,false);
            _("photoWrap_canvas").addEventListener(END_EV,end,false);

            var bStart = 0;

            var bginX,bginY,startX = 0,startY = 0;

            var offsetX_ctx = 0,offsetY_ctx = 0;

            function start(ev){
                // console.log("32")
                ev.preventDefault();
                bStart = 1;

                var poi = getEvtLocation(ev);

                // console.log(poi.x,poi.y);
                bginX = poi.x;
                bginY = poi.y;
            }

            function move(ev){
                ev.preventDefault();

                if(bStart === 0)return;

                var poi = getEvtLocation(ev);

                var offsetX = poi.x - bginX,
                    offsetY = poi.y - bginY;

                ctx.translate(offsetX,offsetY);
                onDraw();

                bginX = poi.x;
                bginY = poi.y;
            }
            function end (ev) {
                // body...
                ev.preventDefault();

                bStart = 0;
            }
            function getEvtLocation(ev){
                if(util.isNull(ev)) return;
                // var touch = ev.touches[0];

                return{
                    x : ev.offsetX,
                    y : ev.offsetY
                }
            }

上面代码做了如下动作:

  1,首先给div.photoWrap_canvas监听鼠标事件,有些人可能会问了,为什么要给div注册事件呢?我们操作的可是 canvas啊,刚刚我们说过我们为了能达到随意的切换相框的效果就给canvas上面蒙一个层,这样的话,我们可能就没法直接给canvas添加事件,希望大家理解。

  2,在鼠标刚开始点击的时候执行 start()方法,他记住鼠标在div内部起点的位置,并告诉浏览器我们可以滑动了(bStart = 1)。

  3,在鼠标移动的时候会先判断 是否执行过 start(),如果有的话,计算移动位置和开始位置的偏移值,然后赋值给 translate()方法。图片就可移动了

  4,结束移动的时候,可以设置bStart = 0,等待下次启动

4,如何消除移动痕迹?

  以上讲述的能让我们的图片随之鼠标的移动而移动,不过在移动的过程中,我们会发现,移动方向的相反位置会留下,很多痕迹。

上面的图片可以看到,很多痕迹,就像电脑卡顿住了一样,,那如何去除呢?

我们想明白造成这样的原因是什么?随着我们的移动,图片的位置也在做相应的改变,注意,我们调用drawImage()的时候,我是画上去,就像画画一样,当然有痕迹,幸好,canvas对象也给我们提供了清除的方法 clearRect()--清除矩形,没错使用这个方法,我们就能清除痕迹了。

让我们重写onDraw()方法:

            function onDraw(){
                ctx.clearRect(- ctxW,-ctxH, 2 * ctxW, 2 * ctxH);

                ctx.drawImage(img,0,0,300,400);
            }

重写之后的效果:

但是,当我们想左移动的时候会发现,还是会有痕迹,怎么回事呢?

在已上代码是指,在图片右下角的相反方向,清除一个是当前canvas大小2的范围。(在这里需要大家注意一点,外面的那个框是 c 这个dome元素,而我们现在对canvas做的任何操作,都是有 c 这个元素生成的 ctx对象上,所以,图像移动,那么图片的右下角也移动,当然它本身还是图片的右下角)其实不难理解,canvas初始化的时候,ctxW和ctxH这个就作为画布的右下角,为什么要用负号呢,因为clearRect(x,y,width,height)这个方法的使用是以(x,y)为起点,向右清除一个矩形范围的,注意是向右,那我们肯定是不能向右的(再向右的话,就什么也没有了),当然向左也不行,那怎么办呢?

在这里呢,我也通过查找博文找到了方案,就是我们用图片的的中心点,当然我们canvas的原点,什么意思呢?让我们来修改下代码:

            img.onload=function(){

                imgW = 300 || img.width,
                imgH = 400 || img.height;

                // 把canvas的原点设置为图片的中心点,但是现实的时候,要还原,否则图片会已左上角钉在canvas的中心点上
                ctx.translate(imgW /2,imgH/2);

                onDraw();

                ctx.save();
            }

  以上代码,修改了图片刚加载完毕之后,我们做的操作,就是给canvas先平移下位置,平移的位置就是图片大小的中心点上,这就完成了图片中心点偏移。

偏移之后,我们页面刚开始的时候,不能就这么显示对吧?不然会被客户骂的,那我们要进行显示还原。

            function onDraw(){

                // 这是清除图片因为平移而造成的痕迹,-ctxw是图片平移的反方向的位置,2*ctxW,是清除的面积
                ctx.clearRect(- ctxW,-ctxH, 2 * ctxW, 2 * ctxH);

                // -imgW/2 是为了让图片显示的回复正常,因为上面显示的时候做了旋转
                ctx.drawImage(img,-imgW / 2, -imgH / 2,300,400);
            }

代码:drawImage()的时候,(x,y)的值,本来是(0,0)的,也就是canvas的左上角,但是,我们把原点偏移了,通过显示的时候把这个偏移量给补回来就好了,所有就是(-imgW/2,-imgH/2);

好了,写到这儿,我们这个功能算是完成了一半,我们实现了相框的切换和图片的平移,下面就是图的缩放和图片合并了。

5,图片缩放

            // 注册鼠标滚轮事件,,暂时只做除去  firfox之外的浏览器
            window.onmousewheel = document.onmousewheel = scrollFnc;

            var scale = 1;
            function scrollFnc(ev){
                var delta = ev.wheelDelta;
                if(delta > 0 && scale <= 5){    //滚轮向上
                    scale += 0.1;
                }else if(delta < 0 && scale >= 1){
                    scale -= 0.2;
                }
                ctx.scale(scale,scale);
                onDraw();
            }

注意,我们这边缩放是通过鼠标的滚轮来做的,当然了,如果使用手机来的话,那就需要手势的操作了,通过计算两个手指或则三个手指之间的距离来进行缩放操作,以后我会补上,现在先这么做吧。

  代码很简单,获取鼠标在元素上滚轮的动作如果是负数就缩小,正数就放大,scale(w,h),放大缩小的函数。

6,图片和相框的合并

  我们可以进行图片的缩放和平移了,那么下步就是把图片和相框进行合并,我刚才说了,为了能够随意的切换相框,那我就先用div的背景来做,并不是直接加入到canvas中,那样会很麻烦。

// 完成
            var newxCtx;
            $("#btnOk").click(function(){
                    newCanvas = document.createElement(‘canvas‘);
                    newCanvas.width = 300;
                    newCanvas.height = 400;
                    newxCtx = newCanvas.getContext("2d");

                var img = new Image();
                    img.src = $(".photoWrap_canvas").attr("data-url");
                img.onload=function(){

                    $(".photoWrap_canvas").hide();

                    // var x = (-ctxW / 2) - offsetX_ctx,
                    //     y =  (-ctxH / 2) - offsetY_ctx;
                    // console.log(offsetX_ctx,offsetY_ctx);
                    newxCtx.drawImage(c,0,0);
                    newxCtx.drawImage(img,0,0,300,400);  //-ctxW /2, -ctxH / 2

                    $(".wrap").prepend(newCanvas);
                }
            })

其实大家看看到了,我是把相框和canvas(图片)再重新drawImage到一个新的canvas里面去的,那为什么这么做呢?直接把相框draw到原有的canvas不久行了吗?

我先给大家看下如果这么做的效果是什么:

可以明显的看出,相框随着图片的小而小,位置也发生了变化,当然了,位置我们可以给他设置偏移,但是大小却不一定,至少,我还没有找到方法,那我就是想到了一个办法,再创建一个canvas这个专门为相框而做的,然后把做好的相片在画到相框这个canvas里面就可以了。

7,写入文字

// 添加文字
            $("#btnAddFont").click(function(){
                var val = $("#txtKey").val();
                if(val == null || val.length == 0) return;
                if(util.isNull(newxCtx)) return;

                newxCtx.font="40px Arial";
                newxCtx.fillText(val,50,100);
            })

写入文字很简单,对不对,得到想要的之,使用 fillText()就可以了,,,

OK,到这,都写完了,希望对你有帮助.

时间: 2024-11-08 19:16:25

利用canvas制作图片(可缩放和平移)+相框+文字的相关文章

利用canvas 导出图片

使用canvas绘制图片,并将图片导出. 将不同域下图片绘制到canvas上时,不能使用toDataURL来获取imgdata,因为 canvas 使用了没有权限的跨域图片在使用canvas.toDataURL()等数据导出函数的时候会报错! img.crossOrigin = "Anonymous" ,它开启了本地的跨域允许.当然服务器存储那边也要开放相应的权限才行,如果是设置了防盗链的图片在服务端就没有相应的权限的话你本地端开启了权限也是没有用的. function downloa

利用canvas制作乱跑的小球

canvas制作乱跑的小球 说明:将下面的代码放到html的body就可以,键盘控制上(W)下(S)左(A)右(D) <body> <canvas id="canvas" style="border: 1px solid #000;display: block;margin:30px auto;"></canvas> <script type="text/javascript"> var myCan

利用canvas制作一个时钟

先上张效果图. 利用canvas来画出一个时钟,想想都是一件神奇又美妙的事情.话不多说,先上代码吧. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-sca

利用canvas制作小游戏的关键点

主要就这四个思路: 游戏图片素材需要全部加载完成后,才初始化游戏 利用new Image(), 将所有数据存放在dataStore.js中,通过单例模式,让全局都可以调用同一个堆内存中的数据 canvas图片素材,是通过将图片剪切,放置在画布上,所以可以写成一个公用JS,ctx.drawImage(img,startX,startY,endX,endY,x,y,width,height) 小游戏绘制的刷新不再是用定时器,而是通过帧率的刷新方法,不停的刷新,给人视觉误差,看起来就像动画一样 let

Android多点触控技术,实现对图片的放大缩小平移,惯性滑动等功能

首先推荐一下鸿洋大大的打造个性的图片预览与多点触控视频教程,这套教程教我们一步一步实现了多点触控实现对图片的平移和缩放的功能,这篇文章我将在鸿洋大大的基础之上做了一些扩展功能: 1.图片的惯性滑动 2.图片缩放小于正常比例时,松手会自动回弹成正常比例 3.图片缩放大于最大比例时,松手会自动回弹成最大比例 实现图片的缩放,平移,双击缩放等基本功能的代码如下,每一行代码我都做了详细的注释 public class ZoomImageView extends ImageView implements

Android图片旋转,缩放,位移,倾斜,对称完整示例(一)——imageView.setImageMatrix(matrix)和Matrix

MainActivity如下: import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; import android.app.Activity; import android.graphics.Matrix; /** * Demo描述:

HTML5 file API加canvas实现图片前端JS压缩并上传 (转载)

一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅,同时大大降低了网络异常导致上传失败风险. 最最重要的体验改进点:省略了图片的再加工成本.很多网站的图片上传功能都会对图片的大小进行限制,尤其是头像上传,限制5M或者2M以内是非常常见的.然后现在的数码设备拍摄功能都非常出众,一张原始图片超过2M几乎是标配,此时如果用户想把手机或相机中的某个得意图片

WPF设置VistualBrush的Visual属性制作图片放大镜效果

原文:WPF设置VistualBrush的Visual属性制作图片放大镜效果 效果图片: 原理:设置VistualBrush的Visual属性,利用它的Viewbox属性进行缩放. XAML代码:// Window1.xaml<Window x:Class="MagnifyingGlass.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns

用Canvas制作简单的画图工具

今天用Canvas制作了一个画图工具,非常简单,功能也不是很多,主要有背景网格,画线,画圆,画矩形和画圆角矩形,也用到了canvas的一些基本知识,在这里一一列举. 1.线段的绘制: 如何绘制真正的1像素的线段? 如果在像素边界处绘制一条1像素宽的垂直线段,那么canvas的绘图环境对象会试着将半个像素画在边界中线的右边,将另外半个像素画在边界中线的左边.然而,在一个整像素的范围内绘制半个像素宽的线段是不可能的,,所以左右两个方向上的半像素都被扩展为1像素.如图所示 本来我们想要将线段绘制在深灰