我有下面的代码来绘制形状(主要用于矩形),但是HTML5绘图函数似乎绘制边框,其厚度以指定的线条为中心。我想在这个形状的表面外有一个边框,我很茫然。
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个顶点的坐标。
感谢的回答,我让它在矩形上工作,但是这个解决方案不能适用于其他形状。
在这里,我画了两个“宽”边框,一个减去一半的lineWidth到每个位置,另一个添加。它不起作用(如预期的那样),因为它只会在一种情况下将粗线向上和向左,在另一种情况下和向右--而不是“在形状之外”。你也可以看到斜坡周围的白色区域。
我试着找出如何让顶点手动绘制粗边框的路径(使用fill()
而不是stroke()
)。
但最终我还是遇到了同样的问题:如何以编程方式确定边缘是在内部还是外部。这将需要一些三角学和沉重的算法。就我目前的工作而言,这太麻烦了。我想用这个画一张建筑物的地图。房间的墙壁需要画在给定的尺寸之外,但我现在要坚持独立倾斜的墙壁。
发布于 2015-04-15 11:19:30
解决方案
您可以通过绘制两条线来解决这个问题:
要收缩,增加50%到x和y,减去线宽(或2x50%)从宽度和高度。
示例
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);
<canvas></canvas>
复杂形状
对于更复杂的形状,您必须手动计算路径。这有点复杂,而且可能太宽泛了。你必须考虑切线,弯角,交叉口等。
“欺骗”的一种方法是:
下面的offset
值将决定内线的厚度,而directions
将决定分辨率。
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();
<canvas height=250></canvas>
发布于 2015-04-15 21:34:19
我去派对迟到了,但这里有一种替代的方法,可以让我“走出一条复杂的道路”。
它使用一个PathObject
来简化创建外部笔画的过程。
PathObject
保存用于定义复杂路径的所有命令和参数。
此PathObject还可以重放命令--从而可以重新定义/重新绘制保存的路径。
PathObject类是可重用的。您可以使用它来保存您需要重新绘制的任何路径(简单或复杂)。
Html5画布很快就会有自己的Path2D对象内置到上下文中,但是下面的示例有一个跨浏览器的填充,可以在实现Path2D对象之前使用。
一种用外部笔画画出的有一线希望的云彩的插图。
“这是怎么做的……”
PathObject
,它可以保存用于定义复杂路径的所有命令和参数。这个PathObject
还可以重放命令--从而可以重新定义保存的路径。Html5画布不久将有自己的Path2D
对象内置到上下文中,但下面的示例是一个跨浏览器的填充,可以一直使用到实现Path2D
对象为止。- 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.
这里的示例代码和演示:
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);
body{ background-color: ivory; }
canvas{border:1px solid red;}
<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>
https://stackoverflow.com/questions/29658761
复制相似问题