最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to draw a smooth oval in canvas - Stack Overflow

programmeradmin2浏览0评论

I am trying to draw a smooth oval using ctx.clip property in my canvas.I have done with drawing part i am facing problem with oval arc line clarity.Any one have any idea regarding this just let me know? Here is my code.

<canvas id="c" width="400" height="400"></canvas>


var canvas = new fabric.Canvas('c');
var ctx = canvas.getContext('2d');
var cx=180;
var cy=200;
var w=300;
var h=250;
    // Quadratric curves example
    ctx.beginPath();
    var lx = cx - w/2,
        rx = cx + w/2,
        ty = cy - h/2,
        by = cy + h/2;
    var magic = 0.551784;
    var xmagic = magic*w/2;
    var ymagic = h*magic/2;
    ctx.moveTo(cx,ty);
    ctx.bezierCurveTo(cx+xmagic,ty,rx,cy-ymagic,rx,cy);
    ctx.bezierCurveTo(rx,cy+ymagic,cx+xmagic,by,cx,by);
    ctx.bezierCurveTo(cx-xmagic,by,lx,cy+ymagic,lx,cy);
    ctx.bezierCurveTo(lx,cy-ymagic,cx-xmagic,ty,cx,ty);

    ctx.fill();
    ctx.stroke();
    ctx.clip();



var text;
text = new fabric.Text('Honey', {
  fontSize: 50,
  left: 150,
  top: 150,
  lineHeight: 1,
  originX: 'left',
  fontFamily: 'Helvetica',
  fontWeight: 'bold'
});
canvas.add(text);

Here is my fiddle link

You can see this output over here the line border of oval not much clear.

I am trying to draw a smooth oval using ctx.clip property in my canvas.I have done with drawing part i am facing problem with oval arc line clarity.Any one have any idea regarding this just let me know? Here is my code.

<canvas id="c" width="400" height="400"></canvas>


var canvas = new fabric.Canvas('c');
var ctx = canvas.getContext('2d');
var cx=180;
var cy=200;
var w=300;
var h=250;
    // Quadratric curves example
    ctx.beginPath();
    var lx = cx - w/2,
        rx = cx + w/2,
        ty = cy - h/2,
        by = cy + h/2;
    var magic = 0.551784;
    var xmagic = magic*w/2;
    var ymagic = h*magic/2;
    ctx.moveTo(cx,ty);
    ctx.bezierCurveTo(cx+xmagic,ty,rx,cy-ymagic,rx,cy);
    ctx.bezierCurveTo(rx,cy+ymagic,cx+xmagic,by,cx,by);
    ctx.bezierCurveTo(cx-xmagic,by,lx,cy+ymagic,lx,cy);
    ctx.bezierCurveTo(lx,cy-ymagic,cx-xmagic,ty,cx,ty);

    ctx.fill();
    ctx.stroke();
    ctx.clip();



var text;
text = new fabric.Text('Honey', {
  fontSize: 50,
  left: 150,
  top: 150,
  lineHeight: 1,
  originX: 'left',
  fontFamily: 'Helvetica',
  fontWeight: 'bold'
});
canvas.add(text);

Here is my fiddle link

You can see this output over here the line border of oval not much clear.

Share Improve this question edited Sep 28, 2013 at 13:56 Alex W 38.3k13 gold badges111 silver badges114 bronze badges asked Sep 28, 2013 at 13:37 Sanjay NakateSanjay Nakate 2,0986 gold badges43 silver badges77 bronze badges 2
  • 2 A one pixel line is not going to be very clear, you'd have to anti-alias it – Ruan Mendes Commented Sep 28, 2013 at 13:54
  • what exacly @JuanMendes – Sanjay Nakate Commented Sep 28, 2013 at 13:55
Add a ment  | 

5 Answers 5

Reset to default 3

try this it will help you //Script

var canvas = new fabric.Canvas('c');
 var w;
 var h;
 var ctx = canvas.getContext('2d');
 w=canvas.width / 4;
 h=canvas.height / 2.4;
canvas.clipTo = function(ctx) {
 ctx.save();
 ctx.scale(2, 1.2);
 ctx.arc(w, h, 90, 0, 2 * Math.PI, true);
 ctx.stroke();
 ctx.restore();
}

Fiddle Demo

One problem is in the nature of your display screen...

Since pixels are rectangles and you're drawing a curve, your result will have "jaggies" as the curve tries to fit itself in rectangular spaces.

You can use an optical illusion to trick the eye into seeing a less jagged oval.

An optical trick:

Reduce the contrast between the background color and the oval color.

This is not a cure...the jaggies are still there.

But the eye recognizes less contrast and perceives the oval as more smooth.

So if your design acmodates this style change, this optical illusion might help.

Here's code and a Fiddle: http://jsfiddle/m1erickson/vDWR3/

var cx=180;
var cy=200;
var w=300;
var h=250;

// Start with a less-contrasting background
ctx.fillStyle="#ddd";
ctx.fillRect(0,0,canvas.width,canvas.height);

ctx.beginPath();
var lx = cx - w/2,
    rx = cx + w/2,
    ty = cy - h/2,
    by = cy + h/2;
var magic = 0.551784;
var xmagic = magic*w/2;
var ymagic = h*magic/2;
ctx.moveTo(cx,ty);
ctx.bezierCurveTo(cx+xmagic,ty,rx,cy-ymagic,rx,cy);
ctx.bezierCurveTo(rx,cy+ymagic,cx+xmagic,by,cx,by);
ctx.bezierCurveTo(cx-xmagic,by,lx,cy+ymagic,lx,cy);
ctx.bezierCurveTo(lx,cy-ymagic,cx-xmagic,ty,cx,ty);

ctx.fillStyle="#555";
ctx.strokeStyle=ctx.fillStyle;
ctx.lineWidth=1.5;
ctx.stroke();

Here is another alternative routine, but it looks visually the same as the other methods. This is primarily to do with the finite resolution of the display device, though you may be able to make some improvement using a thicker pencil, optical illusions or performing some anti-aliasing. Otherwise I think you will have to accept what you have.

Javascript

var canvas = new fabric.Canvas('c'),
    ctx = canvas.getContext("2d"),
    steps = 100,
    step = 2 * Math.PI / steps,
    h = 200,
    k = 180,
    r = 150,
    factor = 0.8,
    theta,
    x,
    y,
    text;

ctx.beginPath();

for (theta = 0; theta < 2 * Math.PI; theta += step) {
    x = h + r * Math.cos(theta);
    y = k - factor * r * Math.sin(theta);
    ctx.lineTo(x, y);
}

ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.clip();

text = new fabric.Text('Honey', {
    fontSize: 50,
    left: 150,
    top: 150,
    lineHeight: 1,
    originX: 'left',
    fontFamily: 'Helvetica',
    fontWeight: 'bold'
});

canvas.add(text);

jsfiddle

Note: by changing the number of steps and the factor, you can create other shapes: circles, squares, hexagons, other polygons ....

<canvas id="thecanvas" width="400" height="400"></canvas>

<script>
var canvas = document.getElementById('thecanvas');

if(canvas.getContext) 
{
  var ctx = canvas.getContext('2d');
  drawEllipse(ctx, 10, 10, 100, 60);
  drawEllipseByCenter(ctx, 60,40,20,10);
}

function drawEllipseByCenter(ctx, cx, cy, w, h) {
  drawEllipse(ctx, cx - w/2.0, cy - h/2.0, w, h);
}

function drawEllipse(ctx, x, y, w, h) {
  var kappa = .5522848,
      ox = (w / 2) * kappa, // control point offset horizontal
      oy = (h / 2) * kappa, // control point offset vertical
      xe = x + w,           // x-end
      ye = y + h,           // y-end
      xm = x + w / 2,       // x-middle
      ym = y + h / 2;       // y-middle

  ctx.beginPath();
  ctx.moveTo(x, ym);
  ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  ctx.closePath();
  ctx.stroke();
}

</script>

http://jsbin./ovuret/2/edit

A possibility is to use a thicker line, it's not great but it's better

ctx.lineWidth = 3;

http://jsfiddle/xadqg/7/

I also noticed that using quadraticCurveTo seems to anti alias the line http://jsfiddle/d4JJ8/298/ I didn't change your code to use it but the jsfiddle I posted shows that it's true. You should modify your code and try it

发布评论

评论列表(0)

  1. 暂无评论