0

我想创建一个画布,它可以自动适应并自动居中绘制在其上的形状。

我有:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />

    <title>Fit Canvas Content</title>

</head>

<body>
    <canvas id="myCanvas" width="500" height="500" style="border:1px solid #000000;">
        Your browser doesn't support the HTML5 canvas.
    </canvas>
    <script>
        var c = document.getElementById("myCanvas");
        var ctx = c.getContext("2d");
        ctx.fillStyle = "black";
        ctx.fillRect(-5, -50, 10, 100);
        ctx.fillRect(-50, -5, 100, 10);
    </script>
</body>
</html>

请记住,画布内容是动态的,形状可以位于任何位置并且可以具有任何大小。

画布上的形状集合

4

2 回答 2

1

我猜你想要这样的东西:http: //jsfiddle.net/e3qSP/1/

这是用于绘制包含 JSDoc 的加号的函数:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "black";
drawPlus(20, c);

/**
 * Draws plus in the middle of the canvas with specified width
 *
 * @public
 * @param {number} plusWidth The width of the plus
 * @param {canvas} canvas The canvas on which the plus should be drawn
 */
function drawPlus(plusWidth, canvas) {
    var height = parseInt(canvas.height),
        width = parseInt(canvas.width),
        size = Math.min(height, width);
    ctx.fillRect((width - plusWidth) / 2, (height - size) / 2, plusWidth, size);
    ctx.fillRect((width - size) / 2, (height - plusWidth) / 2, size, plusWidth);
}
于 2013-01-19T16:19:23.977 回答
1

This will fit and scale to the canvas. Note that there is no padding, but thats easy to add

Firstly, you need to setup something to track transforms.

this.trackTransforms = function (ctx) {
    var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
    var xform = svg.createSVGMatrix();
    ctx.getTransform = function () { return xform; };

    var savedTransforms = [];
    var save = ctx.save;

    ctx.save = function () {
        savedTransforms.push(xform.translate(0, 0));
        return save.call(ctx);
    };

    var restore = ctx.restore;
    ctx.restore = function () {
        xform = savedTransforms.pop();
        return restore.call(ctx);
    };

    var scale = ctx.scale;
    ctx.scale = function (sx, sy) {
        xform = xform.scaleNonUniform(sx, sy);
        return scale.call(ctx, sx, sy);
    };

    var rotate = ctx.rotate;
    ctx.rotate = function (radians) {
        xform = xform.rotate(radians * 180 / Math.PI);
        return rotate.call(ctx, radians);
    };

    var translate = ctx.translate;
    ctx.translate = function (dx, dy) {
        xform = xform.translate(dx, dy);
        return translate.call(ctx, dx, dy);
    };

    var transform = ctx.transform;
    ctx.transform = function (a, b, c, d, e, f) {
        var m2 = svg.createSVGMatrix();
        m2.a = a; m2.b = b; m2.c = c; m2.d = d; m2.e = e; m2.f = f;
        xform = xform.multiply(m2);
        return transform.call(ctx, a, b, c, d, e, f);
    };

    var setTransform = ctx.setTransform;
    ctx.setTransform = function (a, b, c, d, e, f) {
        xform.a = a;
        xform.b = b;
        xform.c = c;
        xform.d = d;
        xform.e = e;
        xform.f = f;
        return setTransform.call(ctx, a, b, c, d, e, f);
    };

    var pt = svg.createSVGPoint();
    ctx.transformedPoint = function (x, y) {
        pt.x = x; pt.y = y;
        return pt.matrixTransform(xform.inverse());
    }
}

Next you need to be able to actually fit the contents. My function assumes you know the absolute width and height of the contents, you'll have to figure this out yourself but should be fairly easy. Note that if something starts at -150 and goes to +150, its width is 300.

this.fitToContents = function (widthOfContents, heightOfContents) {

    var p1 = this.context.transformedPoint(0, 0);
    var p2 = this.context.transformedPoint(this.canvas.width, this.canvas.height);

    var centerX = (p2.x - p1.x) / 2;
    var centerY = (p2.y - p1.y) / 2;

    centerX -= widthOfContents / 2;
    centerY -= heightOfContents / 2;

    this.context.translate(centerX, centerY);

    var lastX = this.canvas.width / 2,
        lastY = this.canvas.height / 2;

    var scaleFactorX = this.canvas.width / widthOfContents;
    var scaleFactorY = this.canvas.height / heightOfContents;

    var scaleFactorToUse = Math.abs(scaleFactorX) < Math.abs(scaleFactorY) ? scaleFactorX : scaleFactorY;

    var pt = this.context.transformedPoint(lastX, lastY);
    this.context.translate(pt.x, pt.y);
    this.context.scale(scaleFactorToUse, scaleFactorToUse);
    this.context.translate(-pt.x, -pt.y);
}

Putting it together itll look something like this:

this.init = function (elementId) {
    this.canvas = document.getElementById(elementId);
    this.context = this.canvas.getContext('2d');

    this.trackTransforms(this.context);

    this.context.canvas.width = this.canvas.offsetWidth;
    this.context.canvas.height = this.canvas.offsetHeight;

    this.draw();
}

this.draw = function () {

    this.fitToContents(300,300);

    // you can now draw other stuff
    // you can probably only fit to contents once, 
    // in the init function, if their positions don't change
    this.drawStuff();
}
于 2015-09-07T10:43:45.577 回答