在任何画布形状周围绘制外部和内部边框 [英] draw outer and inner border around any canvas shape

查看:203
本文介绍了在任何画布形状周围绘制外部和内部边框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在任何画布形状周围绘制外框和内框?



我在html画布上绘制几个笔画形状,我想绘制



草案示例:



有没有一个通用的为什么要做任何形状(假设它是一个封闭的笔画形状)?

解决方案

两种方法



没有内置的方法来做到这一点,我使用了两种编程方式。第一个是复杂的,涉及扩展和收缩路径,然后沿着该路径绘制。这适用于大多数情况,但会在复杂的情况下失败,解决方案有许多变量和选项,以解决这些并发症和如何处理它们。



更好的两个



下面介绍的第二个也是最简单的方法是使用 ctx.globalCompositeOperation 设置以掩盖你想要绘制与否。当沿着中心绘制笔划并且填充填充到中心时,您可以绘制所需宽度的两倍的笔划,然后屏蔽或遮掩内部或外部。



当你开始创建非常复杂的图像时,这会成为问题,因为掩蔽(全局复合操作)会干扰已经绘制的图像。



简化过程,您可以创建第二个画布与原始空间相同的大小作为临时空间。然后,您可以在他的草图画布上绘制形状,然后将草图绘制到工作的画布上。



虽然这种方法不像计算展开或收缩路径,它不受路径中移动点所面临的模糊性的影响。此方法也不会为内部或外部边缘创建具有正确的线连接或斜角的线,因为您必须使用other方法。对于大多数目的,屏蔽它是一个很好的解决方案。



下面是一个演示的屏蔽方法来绘制内部或外部路径。如果通过包括绘制描边和填充来修改蒙版,您还可以设置一个偏移,以便轮廓或内联将偏移一定数量的像素。我已经为你离开了。 (提示添加笔划,并将绘制掩码时的线宽设置为偏移距离的两倍)。

  var demo = function * fullScreenCanvas.js begin ** / var canvas =(function(){canvas = document.getElementById(canv); if(canvas!== null){document.body.removeChild(canvas);} //创建一个空白图像与2d上下文canvas = document.createElement(canvas); canvas.id =canv; canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.style.position =absolute canvas.style.top =0px; canvas.style.left =0px; canvas.style.zIndex = 1000; canvas.ctx = canvas.getContext(2d); document.body.appendChild(canvas); return canvas;})(); var ctx = canvas.ctx; / ** fullScreenCanvas.js end ** / / ** CreateImage.js begin ** / //使用2d上下文创建一个空白图像var createImage = function(w,h){var image = document.createElement(canvas) ; image.width = w; image.height = h; image.ctx = image.getContext(2d);返回图像; } / ** CreateImage.js end ** / //为演示定义一个形状var shape = [0.1,0.1,0.9,0.1,0.5,0.5,0.8,0.9,0.1,0.9]; // draw the shape as a stroke var strokeShape = function(ctx){var w,h,i; w = canvas.width; h = canvas.height; ctx.beginPath();对于(i = 2; i  

p>

How to draw outer and inner border around any canvas shape?

I'm drawing several stroke-only shapes on an html canvas, and I would like to draw an inner and outer border around them.

draft example:

Is there a generic why to do it for any shape (assuming it's a closed stroke-only shape)?

解决方案

Two methods

There is no inbuilt way to do this and there are two programmatic ways that I use. The first is complicated and involves expanding and contracting the path then drawing along that path. This works for most situations but will fail in complex situation, and the solution has many variables and options to account for these complications and how to handle them.

The better of the two

The second and easiest way that I present below is by using the ctx.globalCompositeOperation setting to mask out what you want drawn or not. As the stroke is drawn along the center and the fill fills up to the center you can draw the stroke at twice the desired width and then either mask in or mask out the inner or outer part.

This does become problematic when you start to create very complex images as the masking (Global Composite Operation) will interfere with what has already been drawn.

To simplify the process you can create a second canvas the same size as the original as a scratch space. You can then draw the shape on he scratch canvas do the masking and then draw the scratch canvas onto the working one.

Though this method is not as fast as computing the expanded or shrunk path, it does not suffer from the ambiguities faced by moving points in the path. Nor does this method create the lines with the correct line join or mitering for the inside or outside edges, for that you must use a the other method. For most purposes the masking it is a good solution.

Below is a demo of the masking method to draw an inner or outer path. If you modify the mask by including drawing a stroke along with the fill you can also set an offset so that the outline or inline will be offset by a number of pixels. I have left that for you. (hint add stroke and set the line width to twice the offset distance when drawing the mask).

var demo = function(){
    
    /** fullScreenCanvas.js begin **/
    var canvas = ( function () {
        canvas = document.getElementById("canv");
        if(canvas !== null){
            document.body.removeChild(canvas);
        }
        // creates a blank image with 2d context
        canvas = document.createElement("canvas"); 
        canvas.id = "canv";    
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight; 
        canvas.style.position = "absolute";
        canvas.style.top = "0px";
        canvas.style.left = "0px";
        canvas.style.zIndex = 1000;
        canvas.ctx = canvas.getContext("2d"); 
        document.body.appendChild(canvas);
        return canvas;
    })();
    var ctx = canvas.ctx;
    /** fullScreenCanvas.js end **/
    
    
    
    /** CreateImage.js begin **/
    // creates a blank image with 2d context
    var createImage = function(w,h){
        var image = document.createElement("canvas");  
        image.width = w;
        image.height =h; 
        image.ctx = image.getContext("2d"); 
        return image;
    }  
    /** CreateImage.js end **/
    
    
    
    // define a shape for demo
    var shape = [0.1,0.1,0.9,0.1,0.5,0.5,0.8,0.9,0.1,0.9];
    
    // draws the shape as a stroke
    var strokeShape = function (ctx) {
        var w, h, i;
        w = canvas.width;
        h = canvas.height;
        ctx.beginPath();
        ctx.moveTo(shape[0]  *w, shape[1]  *h)
        for (i = 2; i < shape.length; i += 2) {
            ctx.lineTo(shape[i] * w, shape[i + 1] * h);
        }
        ctx.closePath();
        ctx.stroke();
    }
    // draws the shape as filled
    var fillShape = function (ctx) {
        var w, h, i;       
        w = canvas.width;
        h = canvas.height;
        
        ctx.beginPath();
        ctx.moveTo(shape[0] * w,shape[1] * h)
        for (i = 2; i < shape.length; i += 2) {
            ctx.lineTo(shape[i]*w,shape[i+1]*h);
        }
        ctx.closePath();
        ctx.fill();
    }
    
    var drawInOutStroke = function(width,style,where){
        //  clear the workspace
        workCtx.ctx.globalCompositeOperation ="source-over";
        workCtx.ctx.clearRect(0, 0, workCtx.width, workCtx.height);
      
        // set the width to double 
        workCtx.ctx.lineWidth = width*2;
        workCtx.ctx.strokeStyle = style;
      
        // fill colour does not matter here as its not seen
        workCtx.ctx.fillStyle = "white";
      
        // can use any join type
        workCtx.ctx.lineJoin = "round";
      
        // draw the shape outline at double width
        strokeShape(workCtx.ctx);
      
        // set comp to in. 
        // in means leave only pixel that are both in the source and destination
        if (where.toLowerCase() === "in") {
            workCtx.ctx.globalCompositeOperation ="destination-in";
        } else {
            // out means only pixels on the destination that are not part of the source
            workCtx.ctx.globalCompositeOperation ="destination-out";
        }
        fillShape(workCtx.ctx);
        ctx.drawImage(workCtx, 0, 0);
    }
    
    // clear in case of resize
    ctx.globalCompositeOperation ="source-over";
    ctx.clearRect(0,0,canvas.width,canvas.height);
    
    // create the workspace canvas
    var workCtx = createImage(canvas.width, canvas.height);
    
    // draw the outer stroke
    drawInOutStroke((canvas.width + canvas.height) / 45, "black", "out");
  
    // draw the inner stroke
    drawInOutStroke((canvas.width + canvas.height) / 45, "red", "in");
    
    // draw the shape outline just to highlight the effect
    ctx.strokeStyle = "white";
    ctx.lineJoin = "round";
    ctx.lineWidth = (canvas.width + canvas.height) / 140;

    strokeShape(ctx);
    
};
// run the demo
demo();
// incase fullscreen redraw it all
window.addEventListener("resize",demo)

这篇关于在任何画布形状周围绘制外部和内部边框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆