﻿ Drawing Rotated Triangles - ITCodar

# Drawing Rotated Triangles

## Drawing a rotating triangle

You can just draw the triangle always with the same path, but before drawing the path rotate the canvas to the desired rotation angle.

``canvas.save();canvas.rotate(degrees);//draw your triangle herecanvas.restore();``

There is also a

``canvas.rotate(degrees, x, y);``

if you need to give it a pivot point.

## Rotating triangle around a center point like a wheel

Use the matrix transformations to rotate, scale and translate an shape. The Operations `rotate`, `scale` and `translate` define a new transformation matrix and multiply the current matrix with the new matrix.

If you want to transform a single shape (triangle), you nee to save current matrix before the transformation with `push` and restore the matrix after the transformation with `pop`.

``push();// [...] scale, rotate, translate// [...] draw shapepop();``

If you want to rotate a shape about a local pivot point, you need to draw the shape around (0, 0). Rotate the shape and move the rotated shape to its target position:

``shapeTrasformation = translate * rotate * scale``

Local rotation of an equilateral triangle:

``push()translate(this.x, this.y, this.z);rotate(this.angle)scale(30);triangle(-0.866, 0.5, 0.866, 0.5, 0, -1);pop();this.angle += 0.01; ``

``let triangle1;let speedX;let speedY;let startColor;let endColor;let amt = 0;function setup() {    startColor = color("hsl(144, 100%, 61%)");    endColor = color("hsl(0,77%,36%)");    createCanvas(windowWidth, windowHeight);    //creer notre triangle    triangle1 = new Triangles(200, 100, 0, 4);}function draw() {    colorMode(RGB);    background(252, 238, 10);    triangle1.show();    triangle1.move();}class Triangles {    //configuration de l'objet    constructor(triX, triY, speedX, speedY) {        this.x = triX;        this.y = triY;        this.speedX = speedX;        this.speedY = speedY;        this.angle = 0;    }    show() {        if (amt >= 1) {            amt = 0;            let tmpColor = startColor;            startColor = endColor;            endColor = tmpColor;        }        amt += 0.03;        let colorTransition = lerpColor(startColor, endColor, amt);        noStroke();        fill(colorTransition);        push()        translate(this.x, this.y, this.z);        rotate(this.angle)        scale(30);        triangle(-0.866, 0.5, 0.866, 0.5, 0, -1);        pop();        this.angle += 0.01;    }    move() {        this.x += this.speedX;        this.y += this.speedY;        if (this.x > width || this.x < 0) {            this.speedX *= -1;        }        if (this.x + 25 > width || this.x + 25 < 0) {            this.speedX *= -1;        }        if (this.x - 25 > width || this.x - 25 < 0) {            this.speedX *= -1;        }        if (this.y > height || this.y < 0) {            this.speedY = this.speedY * -1;        }        if (this.y + 40 > height || this.y + 40 < 0) {            this.speedY = this.speedY * -1;        }    }}``
``<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>``

## How do I get the bottom-right X & Y of a rotated triangle

If you are going to use canvas I would recommend using `getTransform()` which returns the transform matrix that you can use to update you vertices. Here is a snippet showing the updated vertices while the triangle is being rotated.

As you'll see in this snippet I first calculate my centroid using the passed in values. Then I can subtract that amount from each vertex in order to get the transform origin to the center of the triangle.

To move the triangle around use `this.translate()`. You could also pass in those values as an argument. Using `setTransform()` we can pass in the rotation value and translate amounts and assigning `getTransform()` to a variable allows us to pass that to a function that will calculate the new vertex position.

``let canvas = document.getElementById("canvas");let ctx = canvas.getContext("2d");canvas.width = 400;canvas.height = 400;class Triangle {  constructor(ptA, ptB, ptC) {    this.ptA = ptA;    this.ptB = ptB;    this.ptC = ptC;    this.translate = {x: 155, y: 100 };    this.centroid = {      ox: (this.ptA.x + this.ptB.x + this.ptC.x) / 3,      oy: (this.ptA.y + this.ptB.y + this.ptC.y) / 3    };    this.c = "red";    this.a = 0;    this.rotation = this.a * (Math.PI / 180);    this.pts = [];  }  draw() {    let t;    this.a -= 0.5;    this.rotation = this.a * (Math.PI / 180);    const cos = Math.cos(this.rotation)    const sin = Math.sin(this.rotation)        ctx.save();    ctx.beginPath();    ctx.fillStyle = this.c;    ctx.setTransform(cos, sin, -sin, cos, this.translate.x, this.translate.y);    t = ctx.getTransform();    ctx.moveTo(this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy);    ctx.lineTo(this.ptB.x - this.centroid.ox, this.ptB.y - this.centroid.oy)    ctx.lineTo(this.ptC.x - this.centroid.ox, this.ptC.y - this.centroid.oy);    ctx.lineTo(this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy);    ctx.fill();    ctx.closePath();    ctx.restore();    this.updateVertices(t);  }  drawVertices() {    for (let i=0; i < this.pts.length; i++) {      ctx.beginPath();      ctx.fillStyle = "blue";      ctx.arc(this.pts[i].x, this.pts[i].y, 3, 0, Math.PI * 2);      ctx.fill();      ctx.closePath();    }  }  updateVertices(t) {    //Explanation:    //t is a variable for getTransform() passed in from draw() method.    //The 7th and 8th arguments are the original point of where the vertex is drawn for that point. The 9th and 10th arguments are how mush the shap has been translated by.    this.pts = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy, this.translate.x, this.translate.y)    this.pts = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptB.x - this.centroid.ox, this.ptB.y - this.centroid.oy, this.translate.x, this.translate.y)     this.pts = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptC.x - this.centroid.ox, this.ptC.y - this.centroid.oy, this.translate.x, this.translate.y)  }}let triangle = new Triangle({ x: 0, y: 0 }, { x: 50, y: 60 }, { x: 0, y: 100 })function calcVertices(a, b, c, d, e, f, pX, pY, cx, cy) {  //pX and pY are the original vertex points  let x, y;  x = (e + pX - cx) * a + (f + pY - cy) * c + (e);  y = (e + pX - cx) * b + (f + pY - cy) * d + (f);    return {x: x, y: y}}function animate() {  ctx.clearRect(0, 0, canvas.width, canvas.height);  triangle.draw();  triangle.drawVertices();  requestAnimationFrame(animate);}animate();``
``<canvas id="canvas"></canvas>``

## Rotate triangle around circle (2D)

I just edited the code you linked and replaced the rectangle with a triangle, and `animate()` with a mouse move listener, of course:

``var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");var cx = 100;var cy = 100;var radious = 10;var gap = 5;var triangleHeight = 25;var triangleBase = 10;redraw(cx + 1, cy);function redraw(mx, my){  mox = mx-cx;  moy = my-cy;  rotation = Math.atan2(moy, mox);  ctx.clearRect(0, 0, canvas.width, canvas.height);  ctx.beginPath();  ctx.arc(cx, cy, radious, 0, Math.PI * 2);  ctx.closePath();  ctx.fill();  ctx.save();  ctx.translate(cx, cy);  ctx.rotate(rotation);  ctx.beginPath();    ctx.moveTo(radious+gap, -triangleBase/2);    ctx.lineTo(radious+gap, triangleBase/2);    ctx.lineTo(radious+gap+triangleHeight, 0);    ctx.lineTo(radious+gap, -triangleBase/2)  ctx.stroke();  ctx.restore();}canvas.addEventListener("mousemove", function (e) {redraw(e.pageX, e.pageY);}, false);``
``<canvas id="canvas"></canvas>``

## Rotate individual triangles on javascript canvas

One approach is to create a `Slice` class and move the paint functions into this class. Now you create for each slice a `Slice` object/instance (`new Slice(...)`) which you can style separately (`slices.setColor('red')`). See the snippet below.

I'd suggest to improve the sample below by creating slices with identical coordinates and rotating the slice at it's correct position by a `ctx.rotate`.

``    var Slice = function(Xcenter, Ycenter, size, number, numberOfSides) {        this.scale = 1.0;        this.color = 'blue';        this.pos = [];        this.pos.push({x:Xcenter, y:Ycenter});        this.pos.push({            x:Xcenter + size * Math.cos((number+1) * 2 * Math.PI / numberOfSides),            y:Ycenter + size * Math.sin((number+1) * 2 * Math.PI / numberOfSides)        });        this.pos.push({            x: Xcenter + size * Math.cos(number * 2 * Math.PI / numberOfSides),            y: Ycenter + size * Math.sin(number * 2 * Math.PI / numberOfSides)        });    };    Slice.prototype.setScale = function(scale) {        this.scale = scale;    };    Slice.prototype.setColor = function(color) {        this.color = color;    };    Slice.prototype.draw = function(ctx) {        ctx.save();        ctx.scale(this.scale,this.scale);        ctx.beginPath();        for (var i=0; i<this.pos.length; i++) {            ctx.lineTo(this.pos[i].x, this.pos[i].y);        }        ctx.closePath();        ctx.fillStyle = this.color;        ctx.fill();        ctx.stroke();        ctx.restore();    };    function ready() {        var canvas=document.getElementById("myCanvas");        var ctx=canvas.getContext("2d");        var numberOfSides = 6,        size = 100,        Xcenter = 0,        Ycenter = 0,        prevX,        prevY,        startPX,        startPY,        angle = 0.1,        angleChange=Math.PI/180;        var slices = [];        for (var i = 1; i <= numberOfSides;i += 1) {            slices.push(new Slice(Xcenter, Ycenter, size, i, numberOfSides));        }        slices.setScale(0.9);        slices.setColor('red');        requestAnimationFrame(animate);        function animate(time){            requestAnimationFrame(animate);            ctx.clearRect(0,0,canvas.width,canvas.height);            ctx.save();            // translate and rotate the canvas            ctx.translate(canvas.width/2,canvas.height/2);            ctx.rotate(angle);            for (var i = 1; i <= numberOfSides;i += 1) {                slices[i-1].draw(ctx);            }            // restore the context to its untranslated & unrotated state            ctx.restore();            angle+=angleChange;        }        ctx.closePath();        ctx.strokeStyle = "#ffffff";        ctx.lineWidth = 1;        ctx.stroke();    }``
``<body onload="ready();"><canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas></body>``