• HTML5 CANVAS 高级


    加载图片

    获取图像有三种方式:

    a : createImageData(),没有效率,一个像素一个像素的绘制;

    b :

    var img= document.getElementById("imageId");

    c : 加载外部图片,这种方式需要等待外部图片加载完毕:

    var img = new Image();

    img.src = "some/location/imgname.jpg";

    canvasのlengthとwidth

    不要在css样式中这顶canvas的长和宽,它极有可能会导致canvas的显示不正常。

    <canvas width="100px" height="200px"></canvas>

    以上代码会正常显示canvas,canvas里面的内容也可以正常显示。

    如果加上

    canvas {
    width: 200px;
    height: 400px;
    }

    以上样式的话,那么canvas会被拉伸到200px*400px。换句话说,canvas确实是css指定的那么大,但是已经经过缩放或者拉伸了。

    绘图

    在指定的location(x, y)处画image图片。图片大小为图片的实际大小。

    context.drawImage(image, x, y);

    在指定的location(x, y)处画image图片。图片会被进行拉伸或压缩,大小为width*height,

    context.drawImage(image, x, y, width, height);

    在指定的location(x, y)处画image图片。图片已经被剪裁了,剪裁的位置为原始图片的(x_location, y_location)处,剪裁大小为x_width*y_width。图片会压缩为width*height大小。

    context.drawImage(image, x_location, y_location, x_width, y_width, x, y, width, height);

    写文本: 挺有用的

    首先设置字体相关的信息:

    context.font,用来设定文本的字体,如: "italic bold 20px Arial, Consolas"

    context.textBaseline, 用来设定文本的位置。 "alphabetic|top|hanging|middle|ideographic|bottom",这些值是可以选择的。

    如下用来填充文本,

    context.fillStyle = "#112233";
    context.fillText("something want to wirte", x, y); 

    如下用来描文本的边,

    context.strokeStyle = "blue";
    context.strokeText("something want to wirte", x, y);

    阴影

    context.shadowColor = "#aabbcc";  // 设置阴影的颜色

    context.shadowBlur = 10;  // 设置阴影的锐利(官方的说话)程度,取值在1~20之间就可以,一般大于3

    context.shadowOffsetX = 10;  // X轴方向上阴影的距离

    context.shadowOffsetY = 10;  // Y轴方向上阴影的距离

    阴影的想象返回包括,文本,图形,图片等。

    填充图案

    可能就是所谓的背景图片了

    var pattern;
    var bgimg = new Image();
    
    bgimg.onload = function(){
      pattern = context.createPattern(bgimg, "repeat|repeat-x|repeat-y");
    }
    
    context.fillStyle = pattern;
    // context.fillRect(0, 0, canvas.width, canvas.height);
    context.rect(0, 0, canvas.width, canvas.height);
    context.fill();

    渐变色背景

    线性渐变

    var linear = context.createLinearGradient(x_start, y_start, x_end, y_end);

    (x_start, y_start)和(x_end, y_end)指定了渐变色的起点和终点,两点之间连成一条线。

    linear.addColorStop(0, "color1");

    linear.addColorStop(0.5, "color2");

    linear.addColorStop(1, "color3");

    context.fillStyle = linear;

    起点之前的颜色为color1指定的颜色,终点之后的颜色为color3指定的颜色。

    context.drawSomthing();

    画完图之后,调用:context.fill();渐变背景色就显示出来了。。。

    放射性渐变

    var radial = context.createRadialGradient(x_start, y_start, radius_start, x_end, y_end, radius_end);

    其它的基本一样。

    canvas交互

    canvas并不记录其上有什么图形,什么线条。它什么也不知道,仅仅是一个图片,甚至连一个容器都算不上。

    那么如何使canvas具有交互能力呢?利用javascript!

    首先javascript的构造函数:

    function Circle(x, y, radius){
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = "pink";
    }

    真心不了解javascript!以上代码中的this.x中的x到底是个什么东西?什么时候出现的,什么时候赋的值?

    按照小猿的理解,这个函数创建的时候,给它分配了空间,而其内部写的所有的this.something中的something都是它的成员变量。

    为什么要写这个东西呢?他能干吗?

    我们用它来保留canvas中所谓对象的状态!

    怎么保存,要是有很多个呢?

    在javascript中设定全部变量,这个变量是一个数组,声明如: var circles = [];

    如此一来,circles就成了真正的容器了。

    你说这些东西有毛用啊?

    canvas的碰撞会有很大的用途!

    假如,我们鼠标点击了canvas中的一个点,需要判断这个点是否碰撞上了一个圆。

    var circle = new Circle(100, 100, 30);
    
    function clickCheck(event){
        var p_x = event.pageX - canvas.offsetLeft;
        var p_y = event.pageY - canvas.offsetTop;
    
        // 检测(p_x, p_y)是否在circle范围内
        var distance = Math.sqrt(Math.pow(p_x - circle.x, 2) + Math.pow(p_y - circle.y, 2));
    if (distance > circle)
    // 在圈里
    else
    // 不在圈里

    拖动一个圆圈跑

    如果一个像素一个像素的移动,那么看上去就是在拽着图片跑。

    var mouseDown;
    window.onload = function(){
        // some other things
    
        canvas.onmousedown = mousecheck;
        canvas.onmousemove = circlemove;
        canvas.onmouseup = mousecheck;
    }
    
    function circlemove(e){
        if (mousedown){
            var x = e.pageX - canvas.offsetLeft;
            var y = e.pageY - canvas.offsetTop;
    
            circle.x = x;
            circle.y = y;
    
            drawCanvas();
        }
    }
    
    function drawCanvas(){
        // start
        context.beginPath();
        context.arc(circle.x, circle.y, circle.radius);
        context.fillStyle = "#121212";
        context.fill();
        context.stroke();
    }

    动画

    动画的关键是如何让它动,在任何一个固定的时间点,所有的东西都是静止的!只不过随着时间的推移,这些东西的位置发生了变化而已。

    整的像那么回事儿似的。好吧,我错了。

    所以我们要做的就是在任意一个时间点都画canvas。需要用到的就是javascript的setTimeout()或者setInterval()。

    setTimeout(functionName, millseconds);在指定的millseconds之后,执行functionName指定的函数。

    通常functionName中也包含setTimeout,以保证动画执行下去。

    setInterval(functionName, millseconds);每隔millseconds之后,执行functionName指定的函数。

    这个方法有一个缺陷,就是不能保证functionName指定的function能够在millseconds指定的时间内完成,如果不能完成的话就会出现所谓的卡顿现象。

    这个方法有一个有点,就是只需要调用一次即可,当不想再执行的时候,clearInterval()方法可以让它停止。

    示例:

    var x_position = 10;
    var y_postition = 0;
    
    window.onload = function(){
        // get canvas, context
    
        setTimeout(drawFrame, 200);
    }
    
    function dramFrame(){
        context.clearRect(0, 0, canvas.width, canvas.height);
        
        context.beginPath();
    
        context.fillStyle = "#343434";
        context.fillRect(x_position, y_position, 10, 20);
        context.strokeStyle = "#999999";
        context.strokeRect(x_position, y_position, 10, 20);
    
        y_position += 1;
    
        if ( y_position < canvas.height ) setTimeout(dramFrame, 200);
    
    }

    稍稍总结一下:

    动画中肯定要有一个被重复调用的function,而这个function基本上都是在window.onload或者image.onload中调用的。

    而这个function所做的无外乎,清除画布,把画布中所有的对象重新绘制。

    按键响应

    var dx = 0;
    var dy = 0;
    function keyPress(event) {
        // 先让图片停止下来
        dx = 0;
        dy = 0;
    
        if (event.keyCode == 37)
            dx = -1;
        if (event.keyCode == 38)
            dy = -1;
        
        ...
    }

    颜色碰撞:它相对于距离计算来说稍微复杂一点,但是仍然也是十分有效的方式。

    先说说颜色,我们知道rgb(254,100,80),也应该知道rgba(254, 100, 80, 0.5)。这是数值都是准确的,也就是说改变其中任何一个值都会造成所表示的颜色不一致。

    canvas就利用这一点来实现的颜色碰撞。其实也有些弊端,一会儿再说。

    var imgData = context.getImagedata(0, 0, 100, 50);

    以上代码获得(0,0)这个位置开始,沿X方向走100,沿Y方向走50这一块儿canvas图片对应的图片数据。

    imgData的data属性是一个数组,其个数是其中像素点个数*4。因为每一个像素点都由4个值组成。

    这里需要注意的是最后一个值也是[0, 255)里的,而不是[0, 1]。

    关键就是r = xxx; g = yyy; b = xxx;

    而如果rgb正好是某一个值,那么就算碰上了。。。

      弊端: 如果图片中有相同的颜色,但是可以走的话就没治了!

  • 相关阅读:
    连通域搜索
    识别深色浅色
    新年,博客搬家了!!!
    C++11 —— 使用 thread 实现线程池
    自己实现的网络字节序转换函数
    GUI 编程 —— QT 的 QSlider 鼠标点击定位问题
    单生产者/单消费者 的 FIFO 无锁队列
    用模板类特化的方式实现工厂模式
    C++11 —— 简易的旋转锁类
    C++11 —— 获取 tuple 参数列表中指定数据类型的索引位置
  • 原文地址:https://www.cnblogs.com/voctrals/p/4134777.html
Copyright © 2020-2023  润新知