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

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

问题描述

我正在尝试制作这个

在 Javascript 代码中,使用 p5.js,但我不知道如何用线条填充这些形状.有没有其他可能性,比如制作圆形的画布或类似的东西,或者我只需要单独制作每个形状?

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

 var sketch = function (p) {与(p){让 h,,空间;p.setup = function() {createCanvas(900, 400);h = 高度/2;w = 宽度/3;空间 = 10;无环();};p.draw = function() {drawBackground('红色', '蓝色', 0, 0);shape('圆', '红色', '蓝色', 0, 0);drawBackground('黄色', '红色', w, 0);shape('方形', '黄色', '红色', w, 0);drawBackground('blue', 'yellow', 2 * w, 0);形状('三角形','蓝色','红色',2 * w,0)drawBackground('red', 'yellow', 0, h);shape('矩形', '红色', '蓝色', 0, h)drawBackground('黄色', '蓝色', w, h);shape('梯形', '黄色', '红色', w, h);drawBackground('blue', 'red', 2 * w, h);};函数 drawBackground(bColor, lColor, x, y) {填充(bColor)noStroke();矩形(x,y,w,h)中风(lColor);行程重量(1);for (let i = 0; i 

 body {背景色:#efefef;}

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

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

解决方案

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

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

function setup() {创建画布(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);//渲染合成图像(redCircle,compSpacing,compSpacing);图像(红框,compSpacing,compSpacing +(compHeight + compSpacing));图像(yellowSquare,compSpacing +(compWidth + compSpacing),compSpacing);图像(黄色梯形,compSpacing +(compWidth + compSpacing),compSpacing +(compHeight + compSpacing));图像(blueTriangle,compSpacing +(compWidth + compSpacing)* 2,compSpacing);图像(蓝色平行四边形,compSpacing +(compWidth + compSpacing)* 2,compSpacing +(compHeight + compSpacing));}函数 getComposition(w, h, bgFill, bgStroke, fgStroke, 间距,strokeWidth, mask){让 comp = createGraphics(w, h);bg = getLinesRect(w, h, bgFill, bgStroke, 间距,strokeWidth, true);fg = getLinesRect(w, h, bgFill, fgStroke, 间距,strokeWidth, false);//应用蒙版fg.mask(掩码);//渲染到最终输出comp.image(bg, 0, 0);comp.image(fg, 0, 0);回报补偿;}函数 getRectMask(w, h, rx, ry, rw, rh){让掩码 = createGraphics(w, h);//使背景透明(alpha 用于遮罩)mask.background(0,0);mask.noStroke();掩码填充(255);mask.rect(rx,ry,rw,rh);//将 p5.Graphics 转换为 p5.Image返回掩码.get();}函数 getCircleMask(w, h, cx, cy, cs){让掩码 = createGraphics(w, h);//使背景透明(alpha 用于遮罩)mask.background(0,0);mask.noStroke();掩码填充(255);mask.circle(cx, cy, cs);//将 p5.Graphics 转换为 p5.Image返回掩码.get();}函数 getQuadMask(w, h, x1, y1, x2, y2, x3, y3, x4, y4){让掩码 = createGraphics(w, h);//使背景透明(alpha 用于遮罩)mask.background(0,0);mask.noStroke();掩码填充(255);mask.quad(x1, y1, x2, y2, x3, y3, x4, y4);//将 p5.Graphics 转换为 p5.Image返回掩码.get();}函数 getTriangleMask(w, h, x1, y1, x2, y2, x3, y3){让掩码 = createGraphics(w, h);//使背景透明(alpha 用于遮罩)mask.background(0,0);mask.noStroke();掩码填充(255);mask.triangle(x1, y1, x2, y2, x3, y3);//将 p5.Graphics 转换为 p5.Image返回掩码.get();}函数getLinesRect(w,h,bg,fg,间距,strokeWidth,isHorizo​​ntal){让 rect = createGraphics(w, h);矩形背景(背景);rect.stroke(fg);rect.strokeWeight(strokeWidth);如果(是水平){for(let y = 0 ; y 

<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) 适合这种方法.

Freya Holmé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天全站免登陆