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

javascript - In HTML5 Canvas, can I make the y axis go up rather than down? - Stack Overflow

programmeradmin7浏览0评论

I'm drawing a graph in Canvas and struggling with the fact that the y-axis is "backward." The origin is in the top-left corner, and increasing values go down rather than up.

(0,0)            (x,0)       (0,y) ^
      +-------------->             |
      |                            |
      |    CANVAS                  |     INSTEAD
      |    DOES THIS               |     OF THIS
      |                            |
      |                            +----------------->
(0,y) v                       (0,0)              (x,0) 

I know that I can move the origin to the bottom-left corner using translate().

context.translate(0, canvas.height);

And I know that I can invert the y-axis using scale().

context.scale(1, -1);

That seems to work, except that it causes text to appear upside-down. Is there a way to make Canvas's coordinates work the way I expect?

I'm drawing a graph in Canvas and struggling with the fact that the y-axis is "backward." The origin is in the top-left corner, and increasing values go down rather than up.

(0,0)            (x,0)       (0,y) ^
      +-------------->             |
      |                            |
      |    CANVAS                  |     INSTEAD
      |    DOES THIS               |     OF THIS
      |                            |
      |                            +----------------->
(0,y) v                       (0,0)              (x,0) 

I know that I can move the origin to the bottom-left corner using translate().

context.translate(0, canvas.height);

And I know that I can invert the y-axis using scale().

context.scale(1, -1);

That seems to work, except that it causes text to appear upside-down. Is there a way to make Canvas's coordinates work the way I expect?

Share Improve this question edited Dec 2, 2010 at 13:20 user372551 asked Dec 2, 2010 at 13:16 Patrick McElhaneyPatrick McElhaney 59.2k41 gold badges137 silver badges169 bronze badges 2
  • 1 My advice to my 10 years ago self is to use the builder pattern. Instead of drawing directly on the canvas, create a model of the thing you're trying to draw and write code to translate a model to the canvas. That way, if you want to switch to another medium (such as SVG) later, you don't have to rewrite any code. All of you have to do is create a new translator. – Patrick McElhaney Commented Sep 26, 2020 at 13:12
  • It might be simplest to use the transformation, then fix it up for drawing text. That way you only need to override one function, not all of them. I guess we would also need to override anything that draws images. – Sam Watkins Commented Jul 16, 2021 at 2:19
Add a comment  | 

5 Answers 5

Reset to default 27

For more modern setup, you can use context.transform(1, 0, 0, -1, 0, canvas.height). This flips y axis and moves the whole canvas one screenful.

More on available transformations: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform

I think you'd do much better to just get used to it. The origin is in the top left with most pixel-based video/screen APIs.

Here's a discussion on the subject.

Plot graph_height - y.

eg: http://jsfiddle.net/nVUUM/

<canvas></canvas>

<script>
var e = document.getElementsByTagName('canvas')[0];
var c = e.getContext('2d');

function plot(x,y) {
  c.fillRect(x, e.height-y, 5, 5);  
}

plot(100,50);
plot(200,100);
</script>

It depends on where you put the .scale I just tried this and it didn't work at first. You need to put the .scale between the moveTo();

ctx.arc(50,50,50,0,2*Math.PI); ctx.moveTo(50,50); ctx.scale(1,-1); ctx.lineTo(50,100); ctx.stroke();

That seems to work, except that it causes text to appear upside-down.

No one seems to have given a full answer that addresses the core issue with text flipping.

In order to render the text correctly, we need to do a last-minute adjustment which flips the y axis back, but centered around the origin of where the text is actually rendered.

That way it won't interfere with the desired global flip of the y axis.

We can achieve this by temporarily translating and scaling, and then restoring our previous transformation afterwards.

ctx.textAlign = "center"; // optional
ctx.textBaseline = "middle"; // optional

ctx.save();
ctx.translate(text_x, text_y);
ctx.scale(1, -1);
ctx.fillText("Hello, World!", 0, 0); // must be zero;zero
ctx.restore();

We can wrap this in a nice little function.

const fillTextFlipped = (ctx, text, x, y) => {
    ctx.save();
    ctx.translate(x, y);
    ctx.scale(1, -1);
    ctx.fillText(text, 0, 0);
    ctx.restore();
};

fillTextFlipped(ctx, "Hello, World!", text_x, text_y);
发布评论

评论列表(0)

  1. 暂无评论