javascript - lineas - dibujar en canvas html5
trazo punteado en<canvas> (11)
Actualmente no hay soporte en la especificación HTML5 Canvas para líneas discontinuas.
mira esto:
http://davidowens.wordpress.com/2010/09/07/html-5-canvas-and-dashed-lines/
o
Echa un vistazo a la Biblioteca Raphael JS:
Supongo que no es posible establecer propiedades de trazo como CSS, que es bastante fácil. Con CSS hemos marcado, punteado, sólido, pero en el lienzo al dibujar líneas / o trazos esto no parece ser una opción. ¿Cómo has implementado esto?
He visto algunos ejemplos, pero son realmente largos para una función tan tonta.
Por ejemplo:
Encontré las propiedades mozDash
y mozDashOffset
en la especificación Mozilla:
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl
Están probablemente usados para controlar guiones, pero no los he usado.
Esta versión simplificada del código de Phrogz utiliza la funcionalidad de transformación incorporada de Canvas y también maneja casos especiales, por ejemplo, cuando 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();
}
}
Creo que mis cálculos son correctos y parece que están bien.
Hay soporte para esto en Firefox al menos
ctx.mozDash = [5,10];
Parece que ctx.webkitLineDash
funcionaba antes, pero lo eliminaron porque tenía algunos problemas de compatibilidad .
Las especificaciones W3C dicen ctx.setLineDash([5,10]);
pero parece que todavía no está implementado en ninguna parte.
Hay una manera mucho más simple de hacer esto. De acuerdo con http://www.w3.org/TR/2dcontext/#dom-context-2d-strokestyle strokeStyle acepta cadenas, CanvasGradients o CanvasPatterns. Entonces tomamos una imagen como esta:
<img src="images/dashedLineProto.jpg" id="cvpattern1" width="32" height="32" />
cárguelo en un lienzo y dibuje nuestro pequeño rectángulo con él.
var img=document.getElementById("cvpattern1");
var pat=ctx.createPattern(img,"repeat");
ctx.strokeStyle = pat;
ctx.strokeRect(20,20,150,100);
eso no resulta en una línea discontinua perfecta, pero es muy sencillo y modificable. Por supuesto, los resultados pueden volverse imperfectos cuando dibuja líneas que no son horizontales o verticales, un patrón de puntos puede ayudar.
PD. tenga en cuenta que SOP se aplica cuando intenta usar imgs de fuentes externas en su código.
Hice modificada la función dashedLine
para agregar soporte para compensación. Utiliza líneas punteadas nativas si el navegador admite ctx.setLineDash
y ctx.lineDashOffset
.
Ejemplo: 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();
};
}
La solución de Phroz es genial. Pero cuando lo usé en mi aplicación, encontré dos errores.
El siguiente código está depurado (y refactorizado para la legibilidad) de la versión de 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++;
}
}
Mozilla ha estado trabajando en una implementación de stroked de líneas discontinuas para Canvas, por lo que podemos ver que se agregue a las especificaciones en el futuro cercano.
Parece que context.setLineDash está prácticamente implementado. Mira this
"context.setLineDash ([5]) dará como resultado una línea discontinua donde tanto los guiones como los espacios tienen un tamaño de 5 píxeles".
Por el momento al menos setLineDash ([5,10]) funciona con Chrome y ctx.mozDash = [5,10] funciona con 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();
Establecer en nulo hace que la línea sea sólida.
Pregunta divertida! He escrito una implementación personalizada de líneas punteadas; puedes probarlo aquí . Tomé la ruta de Adobe Illustrator y le permití especificar una serie de longitudes de trazo / espacio.
Para la posteridad de , aquí está mi implementación (ligeramente alterada para anchos de línea 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;
}
}
}
Para dibujar una línea de 20,150
a 170,10
con guiones de 30px de largo seguidos de un espacio de 10px, se usaría:
myContext.dashedLine(20,150,170,10,[30,10]);
Para dibujar guiones y puntos alternados, use (por ejemplo):
myContext.lineCap = ''round'';
myContext.lineWidth = 4; // Lines 4px wide, dots of diameter 4
myContext.dashedLine(20,150,170,10,[30,10,0,10]);
La longitud del tablero "muy corta" de 0
combinada con la línea redondeadaCap resulta en puntos a lo largo de su línea.
Si alguien sabe de una forma de acceder al punto actual de una ruta de contexto del lienzo, me encantaría saber al respecto, ya que me permitiría escribir esto como ctx.dashTo(x,y,dashes)
lugar de requerir que vuelva a especificar el punto de inicio en la llamada al método.