2017-11-14 4 views
1

내 케이스는 CSS 테두리 렌더링을 모방 한 것입니다. 메서드를 CanvasRenderingContext2D::setLineDash과 함께 사용하면 CSS 렌더러와 동일한 테두리 그림을 시뮬레이트 할 수 있습니다 (예 : border: 5px dashed red). 이 예제를 고려하십시오같은 방법으로 캔버스에 점선 및 점선으로 된 사각형을 그립니다. css border가 작동합니다. 동일한 가장자리 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

CSS border-style: dashed 알고리즘은 사양에 묶여 있지 않으므로 캔버스 API에서 정확히 같은 것을 렌더링 할 수 없습니다.

그런 다음, 당신도 CSS가 라인으로 라인을 렌더링하는 것을 알고있어 : border 모든 border-top-XXX, border-right-XXX, border-bottom-XXX, border-left-XXX을위한 속기이다.
그 이유는 다음과 같습니다. 각 경계선은 다른 경계선과는 별도로 라인 대시가 설정되어 있습니다.

어쨌든 캔버스 API로 처리하려면 가장 쉬운 방법은 네 줄을 사용하고 줄 대시를 개별적으로 설정하는 것입니다. 만 사용하려면, 그래서 지금

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, 대시를 모두 포함하는 하나의 거대한 대시 배열을 만들 수도 있습니다 ...

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

관련 문제