Подтвердить что ты не робот

Пунктирный штрих в <холст>

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

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

Например:

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

4b9b3361

Ответ 1

Веселый вопрос! Я написал специальную реализацию пунктирных линий; вы можете попробовать здесь. Я взял маршрут 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 приводит к точкам вдоль вашей линии.

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

Ответ 2

Эта упрощенная версия кода 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();
    }
}

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

Ответ 3

В настоящий момент работает как минимум 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();

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

Ответ 5

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

Следующий код отлаживается (и обновляется для чтения) версии 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

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

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

загрузите его в холст и нарисуйте с ним маленький прямоугольник.

  var img=document.getElementById("cvpattern1");
  var pat=ctx.createPattern(img,"repeat");
  ctx.strokeStyle = pat;
  ctx.strokeRect(20,20,150,100);

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

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

Ответ 8

Поддержка в Firefox как минимум

ctx.mozDash = [5,10];

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

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

Ответ 9

Я сделал модифицированную функцию 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();
    };
}

Ответ 10

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

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