Descubrí que solo hay un rectángulo de relleno, pero no es uno de esquina redondeada, ¿cómo puedo hacer eso?Cómo dibujar un rectángulo redondeado en el lienzo HTML?
Respuesta
El lienzo HTML5 no proporciona un método para dibujar un rectángulo con esquinas redondeadas.
¿Qué le parece usar los métodos lineTo()
y arc()
?
También puede utilizar el método quadraticCurveTo()
en lugar del método arc()
.
Por alguna razón, parece que tengo problemas con arcTo en Firefox 3.5 y Opera 10.0. Similar a este sitio: http://ditchnet.org/canvas/CanvasRoundedCornerExample.html – bgw
arcTo se ha corregido en la última versión de FF. –
Necesitaba hacer lo mismo y crear un método para hacerlo.
// Now you can just call
var ctx = document.getElementById("rounded-rect").getContext("2d");
// Draw using default border radius,
// stroke it but no fill (function's default values)
roundRect(ctx, 5, 5, 50, 50);
// To change the color on the rectangle, just manipulate the context
ctx.strokeStyle = "rgb(255, 0, 0)";
ctx.fillStyle = "rgba(255, 255, 0, .5)";
roundRect(ctx, 100, 5, 100, 100, 20, true);
// Manipulate it again
ctx.strokeStyle = "#0f0";
ctx.fillStyle = "#ddd";
// Different radii for each corner, others default to 0
roundRect(ctx, 300, 5, 200, 100, {
tl: 50,
br: 25
}, true);
/**
* Draws a rounded rectangle using the current state of the canvas.
* If you omit the last three params, it will draw a rectangle
* outline with a 5 pixel border radius
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x The top left x coordinate
* @param {Number} y The top left y coordinate
* @param {Number} width The width of the rectangle
* @param {Number} height The height of the rectangle
* @param {Number} [radius = 5] The corner radius; It can also be an object
* to specify different radii for corners
* @param {Number} [radius.tl = 0] Top left
* @param {Number} [radius.tr = 0] Top right
* @param {Number} [radius.br = 0] Bottom right
* @param {Number} [radius.bl = 0] Bottom left
* @param {Boolean} [fill = false] Whether to fill the rectangle.
* @param {Boolean} [stroke = true] Whether to stroke the rectangle.
*/
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
if (typeof stroke == 'undefined') {
stroke = true;
}
if (typeof radius === 'undefined') {
radius = 5;
}
if (typeof radius === 'number') {
radius = {tl: radius, tr: radius, br: radius, bl: radius};
} else {
var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};
for (var side in defaultRadius) {
radius[side] = radius[side] || defaultRadius[side];
}
}
ctx.beginPath();
ctx.moveTo(x + radius.tl, y);
ctx.lineTo(x + width - radius.tr, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
ctx.lineTo(x + width, y + height - radius.br);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
ctx.lineTo(x + radius.bl, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
ctx.lineTo(x, y + radius.tl);
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
ctx.closePath();
if (fill) {
ctx.fill();
}
if (stroke) {
ctx.stroke();
}
}
<canvas id="rounded-rect" width="500" height="200">
<!-- Insert fallback content here -->
</canvas>
- radios diferentes por esquina proporcionada por Corgalore
- Ver http://js-bits.blogspot.com/2010/07/canvas-rounded-corner-rectangles.html para una explicación más detallada
Funciona perfectamente. Esta debería ser la respuesta seleccionada. +1 –
Guau, acabo de recibir el primer voto negativo de esta respuesta, sería bueno que el que menospreció explicara por qué –
Respuesta perfecta ... ¿Cómo es que todavía no es nativo del lienzo? Gracias. – andygoestohollywood
Aquí hay una que escribí ... usa arcos en vez de curvas cuadráticas para un mejor control sobre el radio Además, deja la caricia y llenando hasta que
/* Canvas 2d context - roundRect
*
* Accepts 5 parameters, the start_x and start_y points, the end_x and end_y points, and the radius of the corners
*
* No return value
*/
CanvasRenderingContext2D.prototype.roundRect = function(sx,sy,ex,ey,r) {
var r2d = Math.PI/180;
if((ex - sx) - (2 * r) < 0) { r = ((ex - sx)/2); } //ensure that the radius isn't too large for x
if((ey - sy) - (2 * r) < 0) { r = ((ey - sy)/2); } //ensure that the radius isn't too large for y
this.beginPath();
this.moveTo(sx+r,sy);
this.lineTo(ex-r,sy);
this.arc(ex-r,sy+r,r,r2d*270,r2d*360,false);
this.lineTo(ex,ey-r);
this.arc(ex-r,ey-r,r,r2d*0,r2d*90,false);
this.lineTo(sx+r,ey);
this.arc(sx+r,ey-r,r,r2d*90,r2d*180,false);
this.lineTo(sx,sy+r);
this.arc(sx+r,sy+r,r,r2d*180,r2d*270,false);
this.closePath();
}
He aquí un ejemplo:
var _e = document.getElementById('#my_canvas');
var _cxt = _e.getContext("2d");
_cxt.roundRect(35,10,260,120,20);
_cxt.strokeStyle = "#000";
_cxt.stroke();
¿Cómo te da esto un mejor control sobre el radio? Pensé que ibas a permitir x/y radios (esquinas ovales), y también especificando diferentes radios para cada esquina –
Tu 'r2d' probablemente se llame' d2r'. – Grumdrig
@JuanMendes: Las formas (a base de arco) de las esquinas redondeadas en esta solución son más circulares que las de su solución (cuadrática). Creo que eso es lo que quiso decir con "mejor control sobre el radio". – nobar
Juan, hice una ligera mejora a su método para que puedan cambiar cada radio de la esquina del rectángulo de forma individual:
/**
* Draws a rounded rectangle using the current state of the canvas.
* If you omit the last three params, it will draw a rectangle
* outline with a 5 pixel border radius
* @param {Number} x The top left x coordinate
* @param {Number} y The top left y coordinate
* @param {Number} width The width of the rectangle
* @param {Number} height The height of the rectangle
* @param {Object} radius All corner radii. Defaults to 0,0,0,0;
* @param {Boolean} fill Whether to fill the rectangle. Defaults to false.
* @param {Boolean} stroke Whether to stroke the rectangle. Defaults to true.
*/
CanvasRenderingContext2D.prototype.roundRect = function (x, y, width, height, radius, fill, stroke) {
var cornerRadius = { upperLeft: 0, upperRight: 0, lowerLeft: 0, lowerRight: 0 };
if (typeof stroke == "undefined") {
stroke = true;
}
if (typeof radius === "object") {
for (var side in radius) {
cornerRadius[side] = radius[side];
}
}
this.beginPath();
this.moveTo(x + cornerRadius.upperLeft, y);
this.lineTo(x + width - cornerRadius.upperRight, y);
this.quadraticCurveTo(x + width, y, x + width, y + cornerRadius.upperRight);
this.lineTo(x + width, y + height - cornerRadius.lowerRight);
this.quadraticCurveTo(x + width, y + height, x + width - cornerRadius.lowerRight, y + height);
this.lineTo(x + cornerRadius.lowerLeft, y + height);
this.quadraticCurveTo(x, y + height, x, y + height - cornerRadius.lowerLeft);
this.lineTo(x, y + cornerRadius.upperLeft);
this.quadraticCurveTo(x, y, x + cornerRadius.upperLeft, y);
this.closePath();
if (stroke) {
this.stroke();
}
if (fill) {
this.fill();
}
}
utilizar de esta manera:
var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
c.fillStyle = "blue";
c.roundRect(50, 100, 50, 100, {upperLeft:10,upperRight:10}, true, true);
empecé con solución de @ jhoff, pero volvió a escribir para utilizar parámetros de anchura/altura, y el uso de arcTo
hace que sea un poco más concisa:
CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
if (w < 2 * r) r = w/2;
if (h < 2 * r) r = h/2;
this.beginPath();
this.moveTo(x+r, y);
this.arcTo(x+w, y, x+w, y+h, r);
this.arcTo(x+w, y+h, x, y+h, r);
this.arcTo(x, y+h, x, y, r);
this.arcTo(x, y, x+w, y, r);
this.closePath();
return this;
}
También regresa el contexto así se pueden encadenar un poco. Por ejemplo:
ctx.roundRect(35, 10, 225, 110, 20).stroke(); //or .fill() for a filled rect
No me meteré con el contexto de representación de lienzo, a excepción de esa buena solución. –
El problema con esta solución es que no puede controlar el radio para cada esquina de forma independiente. No lo suficientemente flexible. Vea mi solución a continuación. – Corgalore
+1 para una solución elegante muy agradable. – TachyonVortex
Para hacer la función más consistente con los medios normales de utilización de un contexto lienzo, la clase de contexto de la lona se puede ampliar para incluir una 'fillRoundedRect
' método - que se puede llamar de la misma manera fillRect
se llama:
var canv = document.createElement("canvas");
var cctx = canv.getContext("2d");
// If thie canvasContext class doesn't have a fillRoundedRect, extend it now
if (!cctx.constructor.prototype.fillRoundedRect) {
// Extend the canvaseContext class with a fillRoundedRect method
cctx.constructor.prototype.fillRoundedRect =
function (xx,yy, ww,hh, rad, fill, stroke) {
if (typeof(rad) == "undefined") rad = 5;
this.beginPath();
this.moveTo(xx+rad, yy);
this.arcTo(xx+ww, yy, xx+ww, yy+hh, rad);
this.arcTo(xx+ww, yy+hh, xx, yy+hh, rad);
this.arcTo(xx, yy+hh, xx, yy, rad);
this.arcTo(xx, yy, xx+ww, yy, rad);
if (stroke) this.stroke(); // Default to no stroke
if (fill || typeof(fill)=="undefined") this.fill(); // Default to fill
}; // end of fillRoundedRect method
}
el código comprueba si el prototipo del constructor para el objeto de contexto contiene un lienzo 'fillRoundedRect
' propiedad y añade uno - la primera vez. Se invoca de la misma manera como el método fillRect
:
ctx.fillStyle = "#eef"; ctx.strokeStyle = "#ddf";
// ctx.fillRect(10,10, 200,100);
ctx.fillRoundedRect(10,10, 200,100, 5);
El método utiliza el método arcTo
como lo hizo Grumdring. En el método, this
es una referencia al objeto ctx
. El argumento de trazo se predetermina a falso si no está definido. El argumento de relleno está predeterminado para llenar el rectángulo si no está definido.
(probado en Firefox, no sé si todas las implementaciones permiten la extensión de esta manera.)
Sugiero agregar: 'rad = Math.min (rad, ww/2, hh/2);' para que funcione con radios grandes como en la versión de @ Grumdrig. – nobar
Opera, FFS.
if (window["CanvasRenderingContext2D"]) {
/** @expose */
CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
if (w < 2*r) r = w/2;
if (h < 2*r) r = h/2;
this.beginPath();
if (r < 1) {
this.rect(x, y, w, h);
} else {
if (window["opera"]) {
this.moveTo(x+r, y);
this.arcTo(x+r, y, x, y+r, r);
this.lineTo(x, y+h-r);
this.arcTo(x, y+h-r, x+r, y+h, r);
this.lineTo(x+w-r, y+h);
this.arcTo(x+w-r, y+h, x+w, y+h-r, r);
this.lineTo(x+w, y+r);
this.arcTo(x+w, y+r, x+w-r, y, r);
} else {
this.moveTo(x+r, y);
this.arcTo(x+w, y, x+w, y+h, r);
this.arcTo(x+w, y+h, x, y+h, r);
this.arcTo(x, y+h, x, y, r);
this.arcTo(x, y, x+w, y, r);
}
}
this.closePath();
};
/** @expose */
CanvasRenderingContext2D.prototype.fillRoundRect = function(x, y, w, h, r) {
this.roundRect(x, y, w, h, r);
this.fill();
};
/** @expose */
CanvasRenderingContext2D.prototype.strokeRoundRect = function(x, y, w, h, r) {
this.roundRect(x, y, w, h, r);
this.stroke();
};
}
Dado que Opera se va a WebKit, esto también debería seguir siendo válido en el caso heredado.
La función drawPolygon
a continuación se puede utilizar para dibujar cualquier polígono con esquinas redondeadas.
function drawPolygon(ctx, pts, radius) {
if (radius > 0) {
pts = getRoundedPoints(pts, radius);
}
var i, pt, len = pts.length;
ctx.beginPath();
for (i = 0; i < len; i++) {
pt = pts[i];
if (i == 0) {
ctx.moveTo(pt[0], pt[1]);
} else {
ctx.lineTo(pt[0], pt[1]);
}
if (radius > 0) {
ctx.quadraticCurveTo(pt[2], pt[3], pt[4], pt[5]);
}
}
ctx.closePath();
}
function getRoundedPoints(pts, radius) {
var i1, i2, i3, p1, p2, p3, prevPt, nextPt,
len = pts.length,
res = new Array(len);
for (i2 = 0; i2 < len; i2++) {
i1 = i2-1;
i3 = i2+1;
if (i1 < 0) {
i1 = len - 1;
}
if (i3 == len) {
i3 = 0;
}
p1 = pts[i1];
p2 = pts[i2];
p3 = pts[i3];
prevPt = getRoundedPoint(p1[0], p1[1], p2[0], p2[1], radius, false);
nextPt = getRoundedPoint(p2[0], p2[1], p3[0], p3[1], radius, true);
res[i2] = [prevPt[0], prevPt[1], p2[0], p2[1], nextPt[0], nextPt[1]];
}
return res;
};
function getRoundedPoint(x1, y1, x2, y2, radius, first) {
var total = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
idx = first ? radius/total : (total - radius)/total;
return [x1 + (idx * (x2 - x1)), y1 + (idx * (y2 - y1))];
};
la función recibe una matriz con los puntos del polígono, como este:
var canvas = document.getElementById("cv");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#000000";
ctx.lineWidth = 5;
drawPolygon(ctx, [[20, 20],
[120, 20],
[120, 120],
[ 20, 120]], 10);
ctx.stroke();
Este es un puerto y una versión más genérico de una solución publicada here.
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(100,100);
ctx.arcTo(0,100,0,0,30);
ctx.arcTo(0,0,100,0,30);
ctx.arcTo(100,0,100,100,30);
ctx.arcTo(100,100,0,100,30);
ctx.fill();
- 1. Cómo dibujar un rectángulo redondeado en Core Graphics/Quartz 2D?
- 2. Cómo dibujar un rectángulo de líneas discontinuas en el lienzo?
- 3. ¿Cómo puedo dibujar un rectángulo redondeado Etiqueta o Vista?
- 4. UIButton de rectángulo redondeado sin el borde
- 5. Cómo dibujar un rectángulo?
- 6. Lienzo HTML - Dibujar flechas curvas
- 7. Cómo dibujar un rectángulo redondeado en la interfaz de usuario de Android?
- 8. Cómo dibujar un rectángulo redondeado con un borde de ancho variable dentro de límites específicos
- 9. (iOS) Cómo animar un rectángulo redondeado con shapeLayer?
- 10. ¿Cómo dibujar texto en lienzo?
- 11. Cómo dibujar polígonos en un lienzo HTML5?
- 12. Fabric.js - Dibujar un rectángulo gratuito
- 13. android cómo dibujar triángulo, estrella, cuadrado, corazón en el lienzo
- 14. Cómo dibujar un rectángulo en el sitio web para resaltar?
- 15. Dibujo de Python Imaging Library (PIL) - Rectángulo redondeado con degradado
- 16. ¿Puedo dibujar un rectángulo en XML?
- 17. Rectángulo en HTML5 El lienzo está estirado
- 18. UIView con rectángulo redondeado y sombra paralela: la sombra aparece sobre el rectángulo
- 19. Android: dibujar un lienzo en un ImageView
- 20. Rectángulo WPF dibujar borde
- 21. Lienzo de relleno fuera del rectángulo
- 22. Dibujar texto girado en un lienzo HTML5
- 23. Dibujar texto sobre lienzo en el ángulo
- 24. iOS - Crear la subclase UIView para el rectángulo redondeado
- 25. ¿Cómo giro un único objeto en un lienzo html 5?
- 26. dibujar texto "ellipsized" en un lienzo
- 27. dibujar una forma transparente en el lienzo
- 28. Cómo dibujar un triángulo relleno en un lienzo Android?
- 29. iPhone - Cómo dibujar texto en medio de un rectángulo
- 30. Cómo dibujar un rectángulo en MouseDown/Move C#
Este tipo puso cómo hacer rectángulos redondeados (rellenos, con borde ...) en un buen método: http://js-bits.blogspot.com/2010/07/canvas-rounded-corner- rectangles.html – nerdess