пунктирный штрих в <canvas> - PullRequest
48 голосов
/ 02 января 2011

Я думаю, что невозможно установить свойство штриха, такое как CSS, что довольно просто.С помощью CSS мы штриховали, пунктирные, сплошные, но на холсте при рисовании линий или штрихов это, кажется, не вариант.Как вы это реализовали?

Я видел несколько примеров, но они действительно длинные для такой глупой функции.

Например:

http://groups.google.com/group/javascript-information-visualization-toolkit/browse_thread/thread/22000c0d0a1c54f9?pli=1

Ответы [ 11 ]

66 голосов
/ 02 января 2011

Веселый вопрос!Я написал собственную реализацию пунктирных линий;Вы можете попробовать это здесь .Я взял маршрут Adobe Illustrator и позволил вам указать массив длин тире / промежутков.

Для потомков stackoverflow, вот моя реализация (слегка измененная для s / o ширины линий):

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if (CP && CP.lineTo){
  CP.dashedLine = function(x,y,x2,y2,dashArray){
    if (!dashArray) dashArray=[10,5];
    if (dashLength==0) dashLength = 0.001; // Hack for Safari
    var dashCount = dashArray.length;
    this.moveTo(x, y);
    var dx = (x2-x), dy = (y2-y);
    var slope = dx ? dy/dx : 1e15;
    var distRemaining = Math.sqrt( dx*dx + dy*dy );
    var dashIndex=0, draw=true;
    while (distRemaining>=0.1){
      var dashLength = dashArray[dashIndex++%dashCount];
      if (dashLength > distRemaining) dashLength = distRemaining;
      var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) );
      if (dx<0) xStep = -xStep;
      x += xStep
      y += slope*xStep;
      this[draw ? 'lineTo' : 'moveTo'](x,y);
      distRemaining -= dashLength;
      draw = !draw;
    }
  }
}

Чтобы нарисовать линию от 20,150 до 170,10 с тире длиной 30px, за которым следует разрыв в 10px, вы должны использовать:

myContext.dashedLine(20,150,170,10,[30,10]);

Чтобы нарисовать чередующиеся тире и точки, используйте (например):

myContext.lineCap   = 'round';
myContext.lineWidth = 4; // Lines 4px wide, dots of diameter 4
myContext.dashedLine(20,150,170,10,[30,10,0,10]);

«Очень короткая» длина черты 0 в сочетании с округленной lineCap приводит к точкам вдоль вашей линии.

Если кто-либо знает оЧтобы получить доступ к текущей точке пути контекста холста, я бы хотел узнать об этом, так как это позволило бы мне записать это как ctx.dashTo(x,y,dashes) вместо того, чтобы требовать повторного указания начальной точки в вызове метода.

43 голосов
/ 12 января 2011

Эта упрощенная версия кода Phrogz использует встроенную функцию преобразования Canvas, а также обрабатывает особые случаи, например. когда dx = 0

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if (CP.lineTo) {
    CP.dashedLine = function(x, y, x2, y2, da) {
        if (!da) da = [10,5];
        this.save();
        var dx = (x2-x), dy = (y2-y);
        var len = Math.sqrt(dx*dx + dy*dy);
        var rot = Math.atan2(dy, dx);
        this.translate(x, y);
        this.moveTo(0, 0);
        this.rotate(rot);       
        var dc = da.length;
        var di = 0, draw = true;
        x = 0;
        while (len > x) {
            x += da[di++ % dc];
            if (x > len) x = len;
            draw ? this.lineTo(x, 0): this.moveTo(x, 0);
            draw = !draw;
        }       
        this.restore();
    }
}

Я думаю, что мои расчеты верны, и кажется, что все в порядке.

9 голосов
/ 10 февраля 2013

В настоящий момент, по крайней мере, setLineDash ([5,10]) работает с Chrome, а ctx.mozDash = [5,10] работает с FF:

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

if ( ctx.setLineDash !== undefined )   ctx.setLineDash([5,10]);
if ( ctx.mozDash !== undefined )       ctx.mozDash = [5,10];

ctx.beginPath();              
ctx.lineWidth="2";
ctx.strokeStyle="green";
ctx.moveTo(0,75);
ctx.lineTo(250,75);
ctx.stroke();

Установка на ноль делает линию сплошной.

6 голосов
/ 27 августа 2011

Решение Phroz великолепно. Но когда я использовал его в своем приложении, я обнаружил две ошибки.

Следующий код является отлаженной (и реорганизованной для удобства чтения) версией Phroz.

// Fixed: Minus xStep bug (when x2 < x, original code bugs)
// Fixed: Vertical line bug (when abs(x - x2) is zero, original code bugs because of NaN)
var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if(CP && CP.lineTo) CP.dashedLine = function(x, y, x2, y2, dashArray){
    if(! dashArray) dashArray=[10,5];
    var dashCount = dashArray.length;
    var dx = (x2 - x);
    var dy = (y2 - y);
    var xSlope = (Math.abs(dx) > Math.abs(dy));
    var slope = (xSlope) ? dy / dx : dx / dy;

    this.moveTo(x, y);
    var distRemaining = Math.sqrt(dx * dx + dy * dy);
    var dashIndex = 0;
    while(distRemaining >= 0.1){
        var dashLength = Math.min(distRemaining, dashArray[dashIndex % dashCount]);
        var step = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
        if(xSlope){
            if(dx < 0) step = -step;
            x += step
            y += slope * step;
        }else{
            if(dy < 0) step = -step;
            x += slope * step;
            y += step;
        }
        this[(dashIndex % 2 == 0) ? 'lineTo' : 'moveTo'](x, y);
        distRemaining -= dashLength;
        dashIndex++;
    }
}
6 голосов
/ 16 июня 2011

Mozilla работает над реализацией штриховых штрихов для canvas, поэтому мы можем увидеть, что это добавится к спецификации в ближайшем будущем.

5 голосов
/ 27 июля 2012

Есть гораздо более простой способ сделать это.Согласно http://www.w3.org/TR/2dcontext/#dom-context-2d-strokestyle strokeStyle принимает строки, CanvasGradients или CanvasPatterns.Итак, мы просто берем изображение вроде этого:

  <img src="images/dashedLineProto.jpg" id="cvpattern1" width="32" height="32" />

загружаем его в холст и рисуем с ним наш маленький прямоугольник.это не приводит к прекрасной пунктирной линии, но это действительно просто и модифицируемо.Результаты могут, конечно, стать несовершенными, когда вы рисуете линии, которые не горизонтальные или вертикальные, в этом может помочь пунктирный рисунок.

PS.имейте в виду, что SOP применяется, когда вы пытаетесь использовать imgs из внешних источников в вашем коде.

3 голосов
/ 02 января 2011

В настоящее время нет поддержки в спецификации HTML5 Canvas для пунктирных линий.

проверить это:

http://davidowens.wordpress.com/2010/09/07/html-5-canvas-and-dashed-lines/

или

Проверьте библиотеку Raphael JS:

http://raphaeljs.com/

2 голосов
/ 08 февраля 2014

Похоже, context.setLineDash в значительной степени реализован. Смотрите это .

"context.setLineDash ([5]) приведет к пунктирной линии, где штрихи и пробелы имеют размер 5 пикселей. «

2 голосов
/ 31 декабря 2013

Я изменил функцию dashedLine, добавив поддержку смещения. Он использует собственные пунктирные линии, если браузер поддерживает ctx.setLineDash и ctx.lineDashOffset.

Пример: http://jsfiddle.net/mLY8Q/6/

var CP = window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype;
if (CP.lineTo) {

    CP.dashedLine = CP.dashedLine || function (x, y, x2, y2, da, offset) {

        if (!da) da = [10, 5];
        if (!offset) offset = 0;

        if (CP.setLineDash && typeof (CP.lineDashOffset) == "number") {
            this.save();
            this.setLineDash(da);
            this.lineDashOffset = offset;

            this.moveTo(x, y);
            this.lineTo(x2, y2);

            this.restore();
            return;
        }


        this.save();
        var dx = (x2 - x),
            dy = (y2 - y);
        var len = Math.sqrt(dx * dx + dy * dy);
        var rot = Math.atan2(dy, dx);
        this.translate(x, y);
        this.moveTo(0, 0);
        this.rotate(rot);
        var dc = da.length;
        var di = 0;

        var patternLength = 0;
        for (var i = 0; i < dc; i++) {
            patternLength += da[i];
        }
        if (dc % 2 == 1) {
            patternLength *= 2;
        }

        offset = offset % patternLength;
        if (offset < 0) {
            offset += patternLength;
        }

        var startPos = 0;
        var startSegment = 0;
        while (offset >= startPos) {



            if (offset >= startPos + da[startSegment % dc]) {
                startPos += da[startSegment % dc];
                startSegment++;
            } else {
                offset = Math.abs(offset - startPos);
                break;
            }


            if (startSegment > 100) break;
        }
        draw = startSegment % 2 === 0;
        x = 0;
        di = startSegment;


        while (len > x) {
            var interval = da[di++ % dc];
            if (x < offset) {
                interval = Math.max(interval - offset, 1);
                offset = 0;
            }

            x += interval;
            if (x > len) x = len;
            draw ? this.lineTo(x, 0) : this.moveTo(x, 0);
            draw = !draw;
        }
        this.restore();
    };
}
2 голосов
/ 22 августа 2012

Есть поддержка в Firefox по крайней мере

ctx.mozDash = [5,10];

похоже, что ctx.webkitLineDash работал раньше, но они удалили его, потому что у него были проблемы совместимости .

В спецификации W3C написано ctx.setLineDash([5,10]);, но, похоже, он еще нигде не реализован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...