是否可以使画布的背景带有线条或不是矩形的画布? [英] Is it possible to make canvas with background with lines or canvas that isn't a rectangle?

查看:51
本文介绍了是否可以使画布的背景带有线条或不是矩形的画布?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个

使用p5.js在Javascript代码中使用

,但是我不知道如何用线条填充这些形状.还有其他可能性,例如制作圆形的画布或类似的东西,还是我只需要分别制作每个形状?

现在我正在逐个形状地做,但是制作三角形和梯形是粗糙的...

  var sketch = function(p){with(p){让我们w,空间;p.setup = function(){createCanvas(900,400);h =高度/2;w =宽度/3;空间= 10;noLoop();};p.draw = function(){drawBackground('red','blue',0,0);shape('Circle','red','blue',0,0);drawBackground('yellow','red',w,0);shape('Square','yellow','red',w,0);drawBackground('blue','yellow',2 * w,0);形状('三角形','蓝色','红色',2 * w,0)drawBackground('red','yellow',0,h);形状('矩形','红色','蓝色',0,h)drawBackground('yellow','blue',w,h);形状('梯形','黄色','红色',w,h);drawBackground('blue','red',2 * w,h);};函数drawBackground(bColor,lColor,x,y){填充(bColor)noStroke();rect(x,y,w,h)笔画(lColor);strokeWeight(1);for(let i = 0; i< h/space; i ++){line(0 + x,i *空格+ y + 10,w + x,i *空格+ y + 10);}}函数shape(shape,bColor,lColor,x,y){填充(bColor)noStroke();让w1;开关(形状){案例圆":circle(x + w/2,y + h/2,h-空间* 6);笔画(lColor);strokeWeight(1);for(让i = 0; i< w/space; i ++){for(令j = 0; j< h; j ++){pX = i *空间+ x;pY = 0 + y + j;如果(pow(x + w/2-pX,2)+ pow(pY-(y + h/2),2)< = pow(h-space * 6 * 2-10,2)){点(pX,pY);}}}休息;案例"Square":w1 = w-(h-空间* 6);rect(x + w1/2,y +空间* 3,h-空间* 6,h-空间* 6);笔画(lColor);strokeWeight(1);for(令i = 0; i< 15; i ++){for(let j = 0; j< h-space * 6; j ++){点(x + w1/2/i *空间,y +空间* 3 + j)}}休息;案例三角形":w1 = w-(h-空间* 6);三角形(x + w1/2,h-空间* 3 + y,x + w/2,2,y +空间* 3,x + w1/2 + h-空间* 6,h-空间* 3 + y)for(让i = 0; i< w/space; i ++){for(令j = 0; j< h; j ++){pX = i *空间+ x;pY = 0 + y + j;如果(pow(x + w/2-pX,2)+ pow(pY-(y + h/2),2)< = pow(h-space * 6 * 2-10,2)){点(pX,pY);}}}休息;案例矩形":w1 = w-(h-空间* 6)/2;rect(x + w1/2,y +空格* 3,(h-空格* 6)/2,h-空格* 6)休息;案例梯形":w1 = w-(h-空间* 6);quad(x + w1/2,h-空间* 3 + y,x + w1/2 +(h-空间* 6)/4,y +空间* 3,x + w1/4 + h-空间* 6,y +空间* 3,x + w1/2 + h-空间* 6,h-空间* 3 + y)休息;案例平行四边形":w1 = w-(h-空间* 6);quad(x + w1/4,h-空间* 3 + y,x + w1/2,y +空间* 3,x + w1/2 + h-空间* 6,y +空间* 3,x + w1/4 + h-空间* 6,h-空间* 3 + y)休息;休息;}}}};让节点= document.createElement('div');window.document.getElementById('p5-container').appendChild(node);新的p5(sketch,node);  

 正文{背景颜色:#efefef;}  

 < script src ="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js></script>< div id ="p5-container"></div>  

没有消息,一切正常,我只想知道我是否必须做那么艰巨的工作...

解决方案

如果您不需要实际的线坐标(例如用于绘图),我将充分利用

您可以对其余形状应用相同的逻辑:

  function setup(){createCanvas(1620,590);让compWidth = 500;让compHeight = 250;让compSpacing = 30;令lineWeight = 1.5;让lineSpacing = 12;const BLUE = color('#005398');const YELLOW = color('#f9db44');const RED = color('#dc1215');//黄色方块circleMask = getCircleMask(compWidth,compHeight,compWidth * 0.5,compHeight * 0.5,210);redCircle = getComposition(compWidth,compHeight,RED,蓝色的,黄色的,lineSpacing,lineWeight,circleMask);//红框boxMask = getRectMask(compWidth,compHeight,(compWidth-100)* 0.5,20,100,210);redBox = getComposition(compWidth,compHeight,RED,黄色的,蓝色的,lineSpacing,lineWeight,boxMask);//黄色方块squareMask = getRectMask(compWidth,compHeight,144,20,210,210);yellowSquare = getComposition(compWidth,compHeight,YELLOW,红色的,蓝色的,lineSpacing,lineWeight,squareMask);//黄色飞人trapezeMask = getQuadMask(compWidth,compHeight,200,25,200 + 115,25,150 + 220、220、150、220);yellowTrapeze = getComposition(compWidth,compHeight,YELLOW,蓝色的,红色的,lineSpacing,lineWeight,trapezeMask);//蓝色三角形triangleMask = getTriangleMask(compWidth,compHeight,compWidth * 0.5、25,150 + 220、220、150、220);blueTriangle = getComposition(compWidth,compHeight,BLUE,黄色的,红色的,lineSpacing,lineWeight,triangleMask);//蓝色平行四边形parallelogramMask = getQuadMask(compWidth,compHeight,200,25,200 + 145,25,150 + 145、220、150、220);blueParallelogram = getComposition(compWidth,compHeight,BLUE,红色的,黄色的,lineSpacing,lineWeight,parallelogramMask);//渲染合成image(redCircle,compSpacing,compSpacing);image(redBox,compSpacing,compSpacing +(compHeight + compSpacing));image(yellowSquare,compSpacing +(compWidth + compSpacing),compSpacing);image(yellowTrapeze,compSpacing +(compWidth + compSpacing),compSpacing +(compHeight + compSpacing));image(blueTriangle,compSpacing +(compWidth + compSpacing)* 2,compSpacing);image(blueParallelogram,compSpacing +(compWidth + compSpacing)* 2,compSpacing +(compHeight + compSpacing));}函数getComposition(w,h,bgFill,bgStroke,fgStroke,space,strokeWidth,mask){让comp = createGraphics(w,h);bg = getLinesRect(w,h,bgFill,bgStroke,interval,strokeWidth,true);fg = getLinesRect(w,h,bgFill,fgStroke,interval,strokeWidth,false);//涂上口罩fg.mask(mask);//渲染到最终输出comp.image(bg,0,0);comp.image(fg,0,0);返回补偿}函数getRectMask(w,h,rx,ry,rw,rh){让mask = createGraphics(w,h);//使背景透明(alpha用于遮罩)mask.background(0,0);mask.noStroke();mask.fill(255);mask.rect(rx,ry,rw,rh);//将p5.Graphics转换为p5.Image返回mask.get();}函数getCircleMask(w,h,cx,cy,cs){让mask = createGraphics(w,h);//使背景透明(alpha用于遮罩)mask.background(0,0);mask.noStroke();mask.fill(255);mask.circle(cx,cy,cs);//将p5.Graphics转换为p5.Image返回mask.get();}函数getQuadMask(w,h,x1,y1,x2,y2,x3,y3,x4,y4){让mask = createGraphics(w,h);//使背景透明(alpha用于遮罩)mask.background(0,0);mask.noStroke();mask.fill(255);mask.quad(x1,y1,x2,y2,x3,y3,x4,y4);//将p5.Graphics转换为p5.Image返回mask.get();}函数getTriangleMask(w,h,x1,y1,x2,y2,x3,y3){让mask = createGraphics(w,h);//使背景透明(alpha用于遮罩)mask.background(0,0);mask.noStroke();mask.fill(255);mask.triangle(x1,y1,x2,y2,x3,y3);//将p5.Graphics转换为p5.Image返回mask.get();}函数getLinesRect(w,h,bg,fg,space,strokeWidth,isHorizo​​ntal){让rect = createGraphics(w,h);rect.background(bg);rect.stroke(fg);rect.strokeWeight(strokeWidth);if(isHorizo​​ntal){for(let y = 0; y< h; y + =间隔){rect.line(0,y + strokeWidth,w,y + strokeWidth);}}别的{for(让x = 0; x< w; x + =间距){rect.line(x + strokeWidth,0,x + strokeWidth,h);}}//从p5.Graphics转换为p5.Image返回rect.get();}  

 < script src ="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js></script>  

也许可以使用 getQuadMask()并充分利用坐标来绘制矩形和三角形.

请注意,我只是稍微看了一下形状,所以它们不会很完美,但是应该很容易进行调整.切记,遮罩的位置会影响垂直线的对齐方式.

可能还有其他方法可以获得相同的视觉效果.例如,使用 texture() textureWrap(REPEAT) beginShape()/ endShape(),对每条线使用像素,并在更改方向和颜色之前检查交点等.

就生成绘图线而言,我将从水平线开始,进行线与凸多边形的交点,以确定在何处停止水平线并从垂直线开始.@AgniusVasiliauskas的答案(+1)很适合这种方法.

弗雷亚·霍尔梅(FreyaHolmér)对测试有很好的视觉解释.

I'm trying to make this one https://massmoca.org/event/walldrawing340/

in Javascript code, using p5.js, but I have no clue how to fill these shapes with lines. Is there any other possibility, like making canvas that is circle or something like that, or I just have to make each shape seperately?

For now I was doing shape by shape, but making triangle and trapezoid is rough...

        var sketch = function (p) {
          with(p) {

            let h,
                w,
                space;

            p.setup = function() {
              createCanvas(900, 400);
              h = height / 2;
              w = width / 3;
              space = 10;
              noLoop();
            };
        
            p.draw = function() {
              drawBackground('red', 'blue', 0, 0);
              shape('Circle', 'red', 'blue', 0, 0);
              drawBackground('yellow', 'red', w, 0);
              shape('Square', 'yellow', 'red', w, 0);
              drawBackground('blue', 'yellow', 2 * w, 0);
              shape('Triangle', 'blue', 'red', 2 * w, 0)
              drawBackground('red', 'yellow', 0, h);
              shape('Rectangle', 'red', 'blue', 0, h)
              drawBackground('yellow', 'blue', w, h);
              shape('Trapezoid', 'yellow', 'red', w, h);
              drawBackground('blue', 'red', 2 * w, h);            
            };

            function drawBackground(bColor, lColor, x, y) {
                fill(bColor)
                noStroke();
                rect(x, y, w, h)
                stroke(lColor);
                strokeWeight(1);
                for (let i = 0; i < h / space; i++) {
                    line(0 + x, i * space + y + 10, w + x, i * space + y + 10);
                }

            }
            function shape(shape, bColor, lColor, x, y) {
                fill(bColor)
                noStroke();
                let w1;
                switch (shape) {
                    case 'Circle':
                        circle(x + w / 2, y + h / 2, h - space * 6);
                        stroke(lColor);
                        strokeWeight(1);
                        for (let i = 0; i < w / space; i++) {

                            for (let j = 0; j < h; j++) {
                                pX = i * space + x;
                                pY = 0 + y + j;
                                if (pow(x + w / 2 - pX, 2)
                                    + pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
                                    point(pX, pY);
                                }

                            }
                        }
                        break;

                    case 'Square':
                        w1 = w - (h - space * 6);
                        rect(x + w1 / 2, y + space * 3, h - space * 6, h - space * 6);
                        stroke(lColor);
                        strokeWeight(1);
                        for (let i = 0; i < 15; i++) {
                            for (let j = 0; j < h - space * 6; j++) {
                                point(x + w1 / 2 + i * space, y + space * 3 + j)
                            }
                        }
                        break;

                    case 'Triangle':
                        w1 = w - (h - space * 6);
                        triangle(x + w1 / 2, h - space * 3 + y, x + w / 2, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
                        for (let i = 0; i < w / space; i++) {

                            for (let j = 0; j < h; j++) {
                                pX = i * space + x;
                                pY = 0 + y + j;
                                if (pow(x + w / 2 - pX, 2)
                                    + pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
                                    point(pX, pY);
                                }

                            }
                        }
                        break;

                    case 'Rectangle':
                        w1 = w - (h - space * 6) / 2;
                        rect(x + w1 / 2, y + space * 3, (h - space * 6) / 2, h - space * 6)
                        break;

                    case 'Trapezoid':
                        w1 = w - (h - space * 6);
                        quad(x + w1 / 2, h - space * 3 + y, x + w1 / 2 + (h - space * 6) / 4, y + space * 3, x + w1 / 4 + h - space * 6, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
                        break;

                    case 'Parallelogram':
                            w1 = w - (h - space * 6);
                            quad(x + w1 / 4, h - space * 3 + y, x + w1 / 2, y + space * 3, x + w1 / 2 + h - space * 6, y + space * 3, x + w1 / 4 + h - space * 6, h - space * 3 + y)
                            break;
                        break;
                }

            }

          }
        };
        
        let node = document.createElement('div');
        window.document.getElementById('p5-container').appendChild(node);
        new p5(sketch, node);

    body {
      background-color:#efefef;
    }

    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
    <div id="p5-container"></div>

No messages, everything is working, I just want to know if I have to do so much arduous job...

解决方案

If you don't need actual line coordinates (for plotting for example), I'd just make most out of createGraphics() to easily render shapes and lines into (taking advantage of the fact that get() returns a p5.Image) and p5.Image's mask() function.

Here's a basic example:

function setup() {
  createCanvas(600, 300);
  
  let w = 300;
  let h = 150;
  let spacing = 12;
  let strokeWidth = 1;
  
  const BLUE   = color('#005398');
  const YELLOW = color('#f9db44');
  const RED    = color('#dc1215');
  
  bg = getLinesRect(w, h, RED, BLUE, spacing, strokeWidth, true);
  fg = getLinesRect(w, h, RED, YELLOW, spacing, strokeWidth, false);
  mask = getCircleMask(w, h, w * 0.5, h * 0.5, 100, 0);
  
  image(bg, 0, 0);
  image(fg, w, 0);
  // render opaque mask (for visualisation only), mask() requires alpha channel
  image(getCircleMask(w, h, w * 0.5, h * 0.5, 100, 255),0, h);
  
  // apply mask
  fg.mask(mask);
  // render bg + masked fg
  image(bg, w, h);
  image(fg, w, h);
  
  // text labels
  noStroke();
  fill(255);
  text("bg layer", 9, 12);
  text("fg layer", w + 9, 12);
  text("mask", 9, h + 12);
  text("bg + masked fg", w + 9, h + 12);
}

function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
  let rect = createGraphics(w, h);
  rect.background(bg);
  rect.stroke(fg);
  rect.strokeWeight(strokeWidth);
  
  if(isHorizontal){
    for(let y = 0 ; y < h; y += spacing){
      rect.line(0, y + strokeWidth, w, y + strokeWidth);
    } 
  }else{
    for(let x = 0 ; x < w; x += spacing){
      rect.line(x + strokeWidth, 0, x + strokeWidth, h);
    }
  }
  // convert from p5.Graphics to p5.Image
  return rect.get();
}

function getCircleMask(w, h, cx, cy, cs, opacity){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0, opacity);
  mask.noStroke();
  mask.fill(255);
  mask.circle(cx, cy, cs);
  // convert p5.Graphics to p5.Image
  return mask.get();
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

You can apply the same logic for the rest of the shapes:

function setup() {
  createCanvas(1620, 590);
  
  let compWidth  = 500;
  let compHeight = 250;
  let compSpacing= 30;
  
  let lineWeight = 1.5;
  let lineSpacing = 12;
  
  const BLUE   = color('#005398');
  const YELLOW = color('#f9db44');
  const RED    = color('#dc1215');
  
  // yellow square
  circleMask   = getCircleMask(compWidth, compHeight, compWidth * 0.5, compHeight * 0.5, 210);
  redCircle    = getComposition(compWidth, compHeight, RED, 
                                                    BLUE,
                                                    YELLOW,
                                                    lineSpacing, lineWeight, circleMask);
  
  
  // red box
  boxMask      = getRectMask(compWidth, compHeight, (compWidth - 100) * 0.5, 20, 100, 210);
  redBox       = getComposition(compWidth, compHeight, RED, 
                                                    YELLOW,
                                                    BLUE,
                                                    lineSpacing, lineWeight, boxMask);
  
  
  // yellow square
  squareMask   = getRectMask(compWidth, compHeight, 144, 20, 210, 210);
  yellowSquare = getComposition(compWidth, compHeight, YELLOW, 
                                                    RED,
                                                    BLUE,
                                                    lineSpacing, lineWeight, squareMask);
                                                    
  // yellow trapeze
  trapezeMask   = getQuadMask(compWidth, compHeight, 200, 25, 200 + 115, 25,
                                                     150 + 220, 220, 150, 220);
  yellowTrapeze = getComposition(compWidth, compHeight, YELLOW, 
                                                    BLUE,
                                                    RED,
                                                    lineSpacing, lineWeight, trapezeMask);
                                                    
  // blue triangle
  triangleMask   = getTriangleMask(compWidth, compHeight, compWidth * 0.5, 25,
                                                     150 + 220, 220, 150, 220);
  blueTriangle   = getComposition(compWidth, compHeight, BLUE, 
                                                    YELLOW,
                                                    RED,
                                                    lineSpacing, lineWeight, triangleMask);
                                                    
  // blue parallelogram
  parallelogramMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 145, 25,
                                                         150 + 145, 220, 150, 220);
  blueParallelogram = getComposition(compWidth, compHeight, BLUE, 
                                                    RED,
                                                    YELLOW,
                                                    lineSpacing, lineWeight, parallelogramMask);
  
  // render compositions
  image(redCircle, compSpacing, compSpacing);
  image(redBox, compSpacing, compSpacing + (compHeight + compSpacing));
  
  
  image(yellowSquare, compSpacing + (compWidth + compSpacing), compSpacing);
  image(yellowTrapeze, compSpacing + (compWidth + compSpacing), compSpacing + (compHeight + compSpacing));
  
  image(blueTriangle, compSpacing + (compWidth + compSpacing) * 2, compSpacing);
  image(blueParallelogram, compSpacing + (compWidth + compSpacing) * 2, compSpacing + (compHeight + compSpacing));
  
}

function getComposition(w, h, bgFill, bgStroke, fgStroke, spacing, strokeWidth, mask){
  let comp = createGraphics(w, h);
  
  bg = getLinesRect(w, h, bgFill, bgStroke, spacing, strokeWidth, true);
  fg = getLinesRect(w, h, bgFill, fgStroke, spacing, strokeWidth, false);
  // apply mask
  fg.mask(mask);
  // render to final output
  comp.image(bg, 0, 0);
  comp.image(fg, 0, 0);
  
  return comp;
}

function getRectMask(w, h, rx, ry, rw, rh){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.rect(rx, ry, rw, rh);
  // convert p5.Graphics to p5.Image
  return mask.get();
}

function getCircleMask(w, h, cx, cy, cs){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.circle(cx, cy, cs);
  // convert p5.Graphics to p5.Image
  return mask.get();
}

function getQuadMask(w, h, x1, y1, x2, y2, x3, y3, x4, y4){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.quad(x1, y1, x2, y2, x3, y3, x4, y4);
  // convert p5.Graphics to p5.Image
  return mask.get();
}

function getTriangleMask(w, h, x1, y1, x2, y2, x3, y3){
  let mask = createGraphics(w, h);
  // make background transparent (alpha is used for masking)
  mask.background(0,0);
  mask.noStroke();
  mask.fill(255);
  mask.triangle(x1, y1, x2, y2, x3, y3);
  // convert p5.Graphics to p5.Image
  return mask.get();
}

function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
  let rect = createGraphics(w, h);
  rect.background(bg);
  rect.stroke(fg);
  rect.strokeWeight(strokeWidth);
  
  if(isHorizontal){
    for(let y = 0 ; y < h; y += spacing){
      rect.line(0, y + strokeWidth, w, y + strokeWidth);
    } 
  }else{
    for(let x = 0 ; x < w; x += spacing){
      rect.line(x + strokeWidth, 0, x + strokeWidth, h);
    }
  }
  // convert from p5.Graphics to p5.Image
  return rect.get();
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

Probably both rectangles and the triangle could've been drawn using getQuadMask() making good use of coordinates.

Note that I've just eye balled the shapes a bit so they're not going to be perfect, but it should be easy to tweak. Bare in mind the placement of the mask will have an effect of on how the vertical lines will align.

There are probably other ways to get the same visual effect. For example, using texture() and textureWrap(REPEAT) with beginShape()/endShape(), using pixels for each line and checking intersections before changing direction and colours, etc.

In terms of generating lines for plotting I would start with horizontal lines, doing line to convex polygon intersection to determine where to stop the horizontal lines and start vertical lines. @AgniusVasiliauskas's answer(+1) is good for that approach.

Freya Holmér has a pretty nice visual explanation for the test.

这篇关于是否可以使画布的背景带有线条或不是矩形的画布?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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