2017-11-14 6 views
1

私のユースケースはCSSの境界線のレンダリングを模倣することです。 CanvasRenderingContext2D::rectメソッドをCanvasRenderingContext2D::setLineDashと使用して、CSSレンダラと同じ境界線描画をシミュレートすることができます(border: 5px dashed redなど)。この例を考えてみましょう:同じ方法でキャンバスに点線の四角形と点線の四角形を描くCSS境界線が動作する:同じ4つの辺を描画する

let canvas = document.querySelector('canvas'); 
 
let ctx = canvas.getContext('2d'); 
 
ctx.lineWidth = 5 
 
ctx.strokeStyle = 'red' 
 
ctx.lineCap = 'square' 
 
ctx.setLineDash([10, 10]); 
 
ctx.beginPath(); 
 
ctx.moveTo(2.5,2.5); 
 
ctx.rect(2.5, 2.5, 195, 65); 
 
ctx.stroke();
div { 
 
    border: 5px dashed red; 
 
    width: 200px; 
 
    height: 70px; 
 
    box-sizing: border-box; 
 
    margin-bottom: 5px; 
 
} 
 

 
canvas { 
 
    display: block; 
 
    width: 200px; 
 
    height: 70px; 
 
}
<div></div> 
 
<canvas width=200 height=70></canvas>

あなたは問題がエッジである気づくことがあります。

Not pretty line joins on edges

私はギャップやダッシュのサイズを変更しようとしていたが、CSSの例と同じ動作を取得することは不可能と思われる:エッジ上のラインはサイドのライン、その後大きくなっています。回避策として、すべての面を線で描くことが想像できますが、rectメソッドを使用して1つの線を描画したいと考えています。

ありがとうございます。

答えて

1

CSS border-style: dashedアルゴリズムは仕様に縛られていないため、キャンバスAPIで正確に同じものをレンダリングすることはできません。

次に、あなたもCSSは、行ごとにそれをレンダリングすることを知っているんだ:borderはすべてborder-top-XXXborder-right-XXXborder-bottom-XXXborder-left-XXXの省略形です。
それはそういうふうに振る舞います。それぞれの枠線は、他の枠線とは独立した線ダッシュを持っています。

とにかくキャンバスAPIを使用したい場合、最も簡単な解決策は、4行を使用して行ダッシュを別々に設定することです。あなただけ使用したい場合は、今では

var ctx = c.getContext('2d'); 
 
ctx.lineCap = 'square'; 
 

 
// returns a normalized dashArray per segment 
 
// This in no way does the same as any browser's implementation, 
 
// this is just a lazy way to always get dashes start and end at edges 
 
function getLineDash(x1, y1, x2, y2) { 
 
    var length = Math.hypot((x2 - x1), (y2 - y1)); 
 
    var dash_length = length/8; 
 
    var nb_of_dashes = length/dash_length; 
 
    var dash_gap = (dash_length * 0.66); 
 
    dash_length -= dash_gap * 0.33; 
 
    return [dash_length, dash_gap]; 
 
} 
 

 
function draw() { 
 
    ctx.lineWidth = lineWidth_.value; 
 
    ctx.clearRect(0, 0, c.width, c.height); 
 

 
    var points = [ 
 
    [x1_.value, y1_.value], 
 
    [x2_.value, y2_.value], 
 
    [x3_.value, y3_.value], 
 
    [x4_.value, y4_.value] 
 
    ]; 
 

 
    points.forEach(function(pt, i) { 
 
    var next = points[(i + 1) % points.length]; 
 
    ctx.beginPath(); 
 
    ctx.moveTo(pt[0], pt[1]); 
 
    ctx.lineTo(next[0], next[1]); 
 
    ctx.setLineDash(getLineDash(pt[0], pt[1], next[0], next[1])); 
 
    ctx.stroke(); 
 
    }); 
 

 
} 
 

 
draw(); 
 
document.oninput = function(e) { 
 
    if (e.target.parentNode.parentNode === inputs_) { 
 
    draw(); 
 
    } 
 
}
label { 
 
    display: inline-block; 
 
} 
 

 
input { 
 
    max-width: 50px; 
 
}
<div id="inputs_"> 
 
    <label>x1<input type="number" id="x1_" value="10"></label> 
 
    <label>y1<input type="number" id="y1_" value="25"></label> 
 
    <label>x2<input type="number" id="x2_" value="350"></label> 
 
    <label>y2<input type="number" id="y2_" value="25"></label> 
 
    <label>x3<input type="number" id="x3_" value="350"></label> 
 
    <label>y3<input type="number" id="y3_" value="225"></label> 
 
    <label>x4<input type="number" id="x4_" value="10"></label> 
 
    <label>y4<input type="number" id="y4_" value="225"></label> 
 
    <label>lineWidth<input type="number" id="lineWidth_" value="3"></label> 
 

 
</div> 
 
<canvas id="c" width="400" height="400"></canvas>


:ここ

は、彼らが常に起動して、エッジで終了得るためにダッシュを正規化でラフな試みでありますXXXRectの場合は、すべてのダッシュを含む1つの大きなダッシュアレーを作成することもできます。

var ctx = c.getContext('2d'); 
 
ctx.lineCap = 'square'; 
 

 
function getRectDashes(width, height) { 
 
    var w_array = getLineDashes(width, 0, 0, 0); 
 
    var h_array = getLineDashes(0, height, 0, 0); 
 
    dashArray = [].concat.apply([], [w_array, 0, h_array, 0, w_array, 0, h_array]); 
 
    return dashArray; 
 
} 
 
// same as previous snippet except that it does return all the segment's dashes 
 
function getLineDashes(x1, y1, x2, y2) { 
 
    var length = Math.hypot((x2 - x1), (y2 - y1)); 
 
    var dash_length = length/8; 
 
    var nb_of_dashes = length/dash_length; 
 

 
    var dash_gap = dash_length * 0.66666; 
 
    dash_length -= dash_gap * 0.3333; 
 

 
    var total_length = 0; 
 
    var dasharray = []; 
 
    var next; 
 
    while (total_length < length) { 
 
    next = dasharray.length % 2 ? dash_gap : dash_length; 
 
    total_length += next; 
 
    dasharray.push(next); 
 
    } 
 
    return dasharray; 
 
} 
 

 
function draw() { 
 
    ctx.clearRect(0, 0, c.width, c.height); 
 
    ctx.lineWidth = lineWidth_.value; 
 
    var w = width_.value, 
 
    h = height_.value; 
 
    ctx.setLineDash(getRectDashes(w, h)); 
 
    ctx.strokeRect(20, 20, w, h); 
 
} 
 
draw(); 
 
document.oninput = function(e) { 
 
    if (e.target.parentNode.parentNode === inputs_) 
 
    draw(); 
 
};
label { 
 
    display: inline-block; 
 
} 
 

 
input { 
 
    max-width: 50px; 
 
}
<div id="inputs_"> 
 
    <label>width<input type="number" id="width_" value="200"></label> 
 
    <label>height<input type="number" id="height_" value="225"></label> 
 
    <label>lineWidth<input type="number" id="lineWidth_" value="3"></label> 
 
</div> 
 
<canvas id="c" width="400" height="400"></canvas>

+0

説明とデモにはありがとうございます。私は、ダッシュをレンダリングする最も予測可能で正しい方法のように見えるので、線を使用します。また、 'round' – tenbits

関連する問題