Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在路径表面外画一个轮廓

在路径表面外画一个轮廓
EN

Stack Overflow用户
提问于 2015-04-15 11:09:44
回答 2查看 2.3K关注 0票数 1

我有下面的代码来绘制形状(主要用于矩形),但是HTML5绘图函数似乎绘制边框,其厚度以指定的线条为中心。我想在这个形状的表面外有一个边框,我很茫然。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Path.prototype.trace = function(elem, closePath) {
  sd.context.beginPath();
  sd.context.moveTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
  sd.context.lineCap = "square";

  for(var i=1; i<this.points.length; ++i) {
    sd.context.lineTo(this.getStretchedX(i, elem.width), this.getStretchedY(i, elem.height));
  }

  if(closePath) {
    sd.context.lineTo(this.getStretchedX(0, elem.width), this.getStretchedY(0, elem.height));
  }
}

getStrechedX和getStretchedY一旦将形状应用到设置的元素宽度、高度和偏移位置上,就返回第n个顶点的坐标。

感谢的回答,我让它在矩形上工作,但是这个解决方案不能适用于其他形状。

http://jsfiddle.net/0zq9mrch/

在这里,我画了两个“宽”边框,一个减去一半的lineWidth到每个位置,另一个添加。它不起作用(如预期的那样),因为它只会在一种情况下将粗线向上和向左,在另一种情况下和向右--而不是“在形状之外”。你也可以看到斜坡周围的白色区域。

我试着找出如何让顶点手动绘制粗边框的路径(使用fill()而不是stroke())。

但最终我还是遇到了同样的问题:如何以编程方式确定边缘是在内部还是外部。这将需要一些三角学和沉重的算法。就我目前的工作而言,这太麻烦了。我想用这个画一张建筑物的地图。房间的墙壁需要画在给定的尺寸之外,但我现在要坚持独立倾斜的墙壁。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-15 11:19:30

解决方案

您可以通过绘制两条线来解决这个问题:

  • 第一条线的厚度与预期
  • 第二线以外线宽度的50%收缩。

要收缩,增加50%到x和y,减去线宽(或2x50%)从宽度和高度。

示例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var lw50 = lineWidth * 0.5;

// outer line
ctx.lineWidth = lineWidth;         // intended line width
ctx.strokeStyle = "#975";          // color for main line
ctx.strokeRect(40, 40, 100, 100);  // full line

// inner line
ctx.lineWidth = 2;                 // inner line width
ctx.strokeStyle = "#000";          // color for inner line

ctx.strokeRect(40 + lw50, 40 + lw50, 100 - lineWidth, 100 - lineWidth);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<canvas></canvas>

复杂形状

对于更复杂的形状,您必须手动计算路径。这有点复杂,而且可能太宽泛了。你必须考虑切线,弯角,交叉口等。

“欺骗”的一种方法是:

  • 在画布上画出全部厚度的主线。
  • 然后使用重用路径作为剪辑掩码。
  • 将复合模式更改为目标-atop
  • 绘制不同方向的形状偏移量
  • 恢复裁剪
  • 为主线再次更改颜色和重用路径。

下面的offset值将决定内线的厚度,而directions将决定分辨率。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var ctx = document.querySelector("canvas").getContext("2d");
var lineWidth = 20;
var offset = 0.5;                                   // line "thickness"
var directions = 8;                                 // increase to increase details
var angleStep = 2 * Math.PI / 8;

// shape
ctx.lineWidth = lineWidth;                          // intended line width
ctx.strokeStyle = "#000";                           // color for inner line
ctx.moveTo(50, 100);                                // some random shape
ctx.lineTo(100, 20);
ctx.lineTo(200, 100);
ctx.lineTo(300, 100);
ctx.lineTo(200, 200);
ctx.lineTo(50, 100);
ctx.closePath();
ctx.stroke();

ctx.save()

ctx.clip();                                         // set as clipping mask
ctx.globalCompositeOperation = "destination-atop";  // draws "behind" existing drawings

for(var a = 0; a < Math.PI * 2; a += angleStep) {
  ctx.setTransform(1,0,0,1, offset * Math.cos(a), offset * Math.sin(a));
  ctx.drawImage(ctx.canvas, 0, 0);
}

ctx.restore();                              // removes clipping, comp. mode, transforms

// set new color and redraw same path as previous
ctx.strokeStyle = "#975";                           // color for inner line
ctx.stroke();
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<canvas height=250></canvas>

票数 4
EN

Stack Overflow用户

发布于 2015-04-15 21:34:19

我去派对迟到了,但这里有一种替代的方法,可以让我“走出一条复杂的道路”。

它使用一个PathObject来简化创建外部笔画的过程。

PathObject保存用于定义复杂路径的所有命令和参数。

此PathObject还可以重放命令--从而可以重新定义/重新绘制保存的路径。

PathObject类是可重用的。您可以使用它来保存您需要重新绘制的任何路径(简单或复杂)。

Html5画布很快就会有自己的Path2D对象内置到上下文中,但是下面的示例有一个跨浏览器的填充,可以在实现Path2D对象之前使用。

一种用外部笔画画出的有一线希望的云彩的插图。

“这是怎么做的……”

  • 创建一个PathObject,它可以保存用于定义复杂路径的所有命令和参数。这个PathObject还可以重放命令--从而可以重新定义保存的路径。Html5画布不久将有自己的Path2D对象内置到上下文中,但下面的示例是一个跨浏览器的填充,可以一直使用到实现Path2D对象为止。
  • 使用PathObject保存复杂路径。
  • 在主画布上播放路径命令,并按需要填充/笔画。
  • 在临时内存中的画布上播放路径命令。
  • 在临时画布上:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- Set a `context.lineWidth` of twice your desired outside stroke width and do the stroke.
- Set `globalCompositeOperation='destination-out'` and fill. This will cause the inside of the complex path to be cleared and made transparent.

  • 将临时画布画到主画布上。这将导致主画布上现有的复杂路径从内存中的画布中获取“外部笔画”。

这里的示例代码和演示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        function log(){console.log.apply(console,arguments);}

        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var canvas1=document.getElementById("canvas1");
        var ctx1=canvas1.getContext("2d");


// A "class" that remembers (and can replay) all the 
// commands & arguments used to define a context path
var PathObject=( function(){

    // Path-related context methods that don't return a value
    var methods = ['arc','beginPath','bezierCurveTo','clip','closePath',
      'lineTo','moveTo','quadraticCurveTo','rect','restore','rotate',
      'save','scale','setTransform','transform','translate','arcTo'];

    var commands=[];
    var args=[];

    function PathObject(){       
        // add methods plus logging
        for (var i=0;i<methods.length;i++){   
            var m = methods[i];
            this[m] = (function(m){
                return function () {
                    if(m=='beginPath'){
                        commands.length=0;
                        args.length=0;
                    }
                    commands.push(m);
                    args.push(arguments);
                    return(this);
            };}(m));
        }
        
        
    };

    // define/redefine the path by issuing all the saved
    //     path commands to the specified context
    PathObject.prototype.definePath=function(context){
        for(var i=0;i<commands.length;i++){
            context[commands[i]].apply(context, args[i]);            
        }
    }   

    //
    PathObject.prototype.show=function(){
        for(var i=0;i<commands.length;i++){
            log(commands[i],args[i]);
        }
    }

    //
    return(PathObject);
})();




var x=75;
var y=100;
var scale=0.50;

// define a cloud path
var path=new PathObject()
.beginPath()
.save()
.translate(x,y)
.scale(scale,scale)
.moveTo(0, 0)
.bezierCurveTo(-40,  20, -40,  70,  60,  70)
.bezierCurveTo(80,  100, 150, 100, 170,  70)
.bezierCurveTo(250,  70, 250,  40, 220,  20)
.bezierCurveTo(260, -40, 200, -50, 170, -30)         
.bezierCurveTo(150, -75,  80, -60,  80, -30)
.bezierCurveTo(30,  -75, -20, -60,   0,   0)
.restore();


// fill the blue sky on the main canvas
ctx.fillStyle='skyblue';
ctx.fillRect(0,0,canvas.width,canvas.height);

// draw the cloud on the main canvas
path.definePath(ctx);
ctx.fillStyle='white';
ctx.fill();
ctx.strokeStyle='black';
ctx.lineWidth=2;
ctx.stroke();

// draw the cloud's silver lining on the temp canvas
path.definePath(ctx1);
ctx1.lineWidth=20;
ctx1.strokeStyle='silver';
ctx1.stroke();
ctx1.globalCompositeOperation='destination-out';
ctx1.fill();

// draw the silver lining onto the main canvas
ctx.drawImage(canvas1,0,0);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
body{ background-color: ivory; }
canvas{border:1px solid red;}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h4>Main canvas with original white cloud + small black stroke<br>The "outside silver lining" is from the temp canvas</h4>
<canvas id="canvas" width=300 height=300></canvas>
<h4>Temporary canvas used to create the "outside stroke"</h4>
<canvas id="canvas1" width=300 height=300></canvas>

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29658761

复制
相关文章

相似问题

添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文