惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
小众软件
小众软件
D
Docker
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
V2EX
博客园 - 叶小钗
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Stack Overflow Blog
Stack Overflow Blog
B
Blog RSS Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
IT之家
IT之家
博客园 - 司徒正美
M
MIT News - Artificial intelligence
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog

MDN Blog

Introducing the MDN MCP server | MDN Blog Under the hood of MDN's new frontend | MDN Blog Image formats: Codecs and compression tools | MDN Blog A beginner-friendly guide to view transitions in CSS | MDN Blog Launching MDN's new front end | MDN Blog Image formats: Pixel data from encoders to decoders | MDN Blog Celebrating 20 years of MDN | MDN Blog Image formats: Color models for humans and devices | MDN Blog Default styles for h1 elements are changing | MDN Blog Implications of Global Privacy Control | MDN Blog JavaScript Temporal is coming | MDN Blog Fix your website's Largest Contentful Paint by optimizing image loading | MDN Blog MDN 2024 content projects | MDN Blog A new learning experience on MDN | MDN Blog Countdown to the holidays with daily coding challenges | MDN Blog Monitoring and optimizing website performance | MDN Blog How to land your first developer job | MDN Blog Introducing the new MDN Community page | MDN Blog Fixing your website's JavaScript performance | MDN Blog Get back to school! Supercharge your learning with MDN and Scrimba | MDN Blog Efficient data handling with the Streams API | MDN Blog Locale-sensitive text segmentation in JavaScript with Intl.Segmenter | MDN Blog Optimize your workflow with Git stash | MDN Blog How to debug mobile apps across devices | MDN Blog Exclusive accordions using the HTML details element | MDN Blog Exploring the Broadcast Channel API for cross-tab communication | MDN Blog MDN partners with Scrimba to enhance web development learning | MDN Blog Introducing the MDN HTTP Observatory | MDN Blog Static Site Generation (SSG) with Next.js | MDN Blog New JavaScript Set methods | MDN Blog
How to draw any regular shape with just one JavaScript fu...
Ruth John May 26, 2023 4 minutes read · 2023-05-26 · via MDN Blog

Ok alright, I know I used a clickbait title, but bear with me. I want to share a function I've been using for ages. I originally wrote it to draw a hexagon – hexagons are cool, lots of hexagons are better, and tessellated hexagons are the best. So I wrote a function to draw one, which I could then repeat.

As I was doing so, I started modifying the hexagon to enable drawing a number of shapes that are based on just a couple of parameters. Let's begin with what I did with the hexagon and we'll take it from there.

Drawing a hexagon with JavaScript

Hexagons have six equal sides. If we imagine our starting point as the center of the hexagon, we can move around this point six times, joining each point as we go to make the sides.

Let's start off by creating a <canvas> with a 2d drawing context. We'll fix the size of the canvas to 400 x 200 pixels for this example and set the center point as (200, 100).

const canvas = document.querySelector("canvas");
canvas.width = 400;
canvas.height = 200;

const ctx = canvas.getContext("2d");
const cx = 200;
const cy = 100;

Now we need to figure out the x (horizontal) and y (vertical) position of points around the center, which when joined with a line, will make six equal sides. For this, we use the measurement from the center to the point (we'll call this the radius) and the angle of direction from the center.

As there are 360 degrees in a full rotation and six points we want to create, we can divide 360/6 and know we'll make a point every 60 degrees. However, there's a tiny caveat to this – JavaScript works with radians rather than degrees. One thing I always remember is that the value pi in radians is 180 degrees, or half a circle. So (Math.PI*2)/6 would give us each rotation in radians or even simpler Math.PI/3.

Next we need to add a bit of trigonometry to find the x and y position of each point. For the x position, we can use the sum radius multiplied by cos(angle) and for the y position radius multiplied by sin(angle). Let's put it all together, adding to our JavaScript code above:

// set the radius of the hexagon
const radius = 50;

// move the canvas to the center position
ctx.translate(cx, cy);

for (let i = 0; i < 6; i++) {
  // calculate the rotation
  const rotation = (Math.PI / 3) * i;

  // for the first point move to
  if (i === 0) {
    ctx.moveTo(radius * Math.cos(rotation), radius * Math.sin(rotation));
  } else {
    // for the rest draw a line
    ctx.lineTo(radius * Math.cos(rotation), radius * Math.sin(rotation));
  }
}

// close path and stroke it
ctx.closePath();
ctx.stroke();

Drawing a shape with any number of sides

Let's say we wanted to draw a triangle, a square, or an octagon. All we would need to modify in the above function, used to draw the hexagon, is the number of times we draw lines in our for loop and the angle for each point.

Let's turn this into a function that takes the center point, the radius, and number of sides as parameters:

const canvas = document.querySelector("canvas");
canvas.width = 400;
canvas.height = 200;

const ctx = canvas.getContext("2d");
function drawShape(x, y, r, sides) {
  // move the canvas to the center position
  ctx.translate(x, y);

  for (let i = 0; i < sides; i++) {
    // calculate the rotation
    const rotation = ((Math.PI * 2) / sides) * i;

    // for the first point move to
    if (i === 0) {
      ctx.moveTo(r * Math.cos(rotation), r * Math.sin(rotation));
    } else {
      // for the rest draw a line
      ctx.lineTo(r * Math.cos(rotation), r * Math.sin(rotation));
    }
  }

  // close path and stroke it
  ctx.closePath();
  ctx.stroke();

  // reset the translate position
  ctx.resetTransform();
}

Now we can draw different shapes by adjusting the sides parameter:

drawShape(100, 100, 50, 3);
drawShape(225, 100, 50, 7);
drawShape(350, 100, 50, 4);

Summary

This was a little introduction to the <canvas> element for drawing on a web page and a few of the methods you can use to draw shapes. If you want to dive deeper into how all the pieces work, here's a recap of what we used:

To calculate the position of each point, we used a little bit of maths and trigonometry:

  • Math.cos() to calculate the x position of a point
  • Math.sin() to calculate the y position of a point
  • Math.PI to calculate the angle of rotation in radians

To get some more inspiration for what you can do with the <canvas> element, check out the Canvas tutorial that starts off with the basics and then covers more advanced topics like animation and pixel manipulation.

There are plenty of ways you can expand on this basic shape function. I like to include an inner radius, so you can create diamonds and stars. I've also experimented a little with curves instead of straight lines - feel free to experiment for yourself. Or try some tessellation, which is always fun!

An image of colorful hexagons and diamonds in a tessellated pattern

Let me know if you try out this function and if you like it as much as I do. As always, feel free to leave any feedback on the GitHub discussion or join us for a chat in the MDN Web Docs Discord server.