{"id":20010,"date":"2020-06-26T14:25:32","date_gmt":"2020-06-26T13:25:32","guid":{"rendered":"http:\/\/www.highcharts.com\/blog\/?p=20010"},"modified":"2026-01-13T09:54:02","modified_gmt":"2026-01-13T09:54:02","slug":"a-snake-game-with-highcharts","status":"publish","type":"post","link":"https:\/\/www.highcharts.com\/blog\/tutorials\/a-snake-game-with-highcharts\/","title":{"rendered":"A snake game with Highcharts"},"content":{"rendered":"<p>Highcharts is a highly customizable library that allows users to create almost any interactive SVG based visualization one can imagine, even a game!<br \/>\nPreviously we looked at creating an <a href=\"https:\/\/www.highcharts.com\/blog\/tutorials\/build-an-interactive-puzzle-using-highcharts-gantt\/\" target=\"_blank\" rel=\"noopener noreferrer\">interactive puzzle<\/a> using Highcharts Gantt. In this tutorial, we will look at the Highcharts library at a lower level in an effort to transform your charts into a snake game (see below):<\/p>\n<p class=\"demo-container\"><iframe loading=\"lazy\" src=\"\/\/jsfiddle.net\/BlackLabel\/ray3fn4z\/embedded\/result\/\" width=\"100%\" height=\"600\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\" title=\"A snake game created using Highcharts library. By Mateusz Kornecki\"><\/iframe><\/p>\n<p>The article has two main sections. The first section will walk through some basic concepts such as SVG Renderer and SVG Element. In the second section, you will see how to create the snake, how to make it move, and how to feed the snake.<\/p>\n<h2>SVG Renderer<\/h2>\n<p>An essential tool that might help implement custom elements that are not included in the Highcharts core is the Highcharts SVG renderer. It can be used to add to your chart a custom SVG element that can be created in any shape \u2013 the only thing that limits you is your imagination if you have used canvas API before you will feel at home.<\/p>\n<h2>SVG Elements<\/h2>\n<p>There are a few basic elements that can be rendered, you could create a <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#circle\" target=\"_blank\" rel=\"noopener noreferrer\">circle<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#rect\" target=\"_blank\" rel=\"noopener noreferrer\">arc<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#rect\" target=\"_blank\" rel=\"noopener noreferrer\">rectangle<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#text\" target=\"_blank\" rel=\"noopener noreferrer\">text element<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#label\" target=\"_blank\" rel=\"noopener noreferrer\">label<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#button\" target=\"_blank\" rel=\"noopener noreferrer\">button<\/a>, <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#symbol\" target=\"_blank\" rel=\"noopener noreferrer\">symbol<\/a>, or draw a <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#path\" target=\"_blank\" rel=\"noopener noreferrer\">path<\/a>. This time we will focus on rendering a rectangle that will be used to create a snake body.<\/p>\n<h2>Create a snake<\/h2>\n<p>Before we can start rendering, we need to create a layer where we may place rendered elements. For this purpose, you could use the chart already existing, but it is worth mentioning that it is possible to create an <a href=\"https:\/\/jsfiddle.net\/gh\/get\/library\/pure\/highcharts\/highcharts\/tree\/master\/samples\/highcharts\/members\/renderer-on-chart\" target=\"_blank\" rel=\"noopener noreferrer\">independent SVG drawing<\/a>.<br \/>\nBecause I wanted to create a game that could be interactive with the chart, I\u2019m starting from a basic scatter chart.<\/p>\n<pre>const chart = Highcharts.chart('container', {\r\n  chart: {\r\n    type: 'scatter'\r\n  },\r\n  series: [{\r\n    data: [4, 3, 5, 6, 2, 3]\r\n  }]\r\n});<\/pre>\n<p>Now the renderer can be accessed straight from the chart that we just created. To use it and create the first rectangle, we can use <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGRenderer#rect\" target=\"_blank\" rel=\"noopener noreferrer\">renderer.rect(x, y, width, height)<\/a> method. The method takes four arguments:<\/p>\n<ol>\n<li>x \u2013 distance (in px) from the left side of the container<\/li>\n<li>y \u2013 distance from the top of the container<\/li>\n<li>width of the rectangle<\/li>\n<li>height of the rectangle<\/li>\n<\/ol>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-20357\" src=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2020\/06\/26142634\/image1.jpg\" alt=\"renderer rect\" width=\"282\" height=\"284\" \/><\/p>\n<p>Using the renderer method returns an SVG element with the given coordinates and sizes. Still, before adding it to our chart, we need to apply some attributes like <code>fill<\/code>, <code>stroke<\/code>, or <code>stroke-width<\/code> to make our rectangle visible. To do that we, could use the <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGElement#attr\" target=\"_blank\" rel=\"noopener noreferrer\">attr()<\/a> method. After specifying those attributes, we could finally add the SVG element to our chart using the <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGElement#add\" target=\"_blank\" rel=\"noopener noreferrer\">add()<\/a> method.<\/p>\n<pre>const snake = chart.renderer.rect(0, 0, 20, 20)\r\n  .attr({\r\n    fill: 'red'\r\n  })\r\n  .add();<\/pre>\n<h2>Let it move!<\/h2>\n<p>In the previous paragraph, we learned how to render a simple rectangle, but it is only static. Our snake should be more lively. To wake it up, we need to learn about <code>translate()<\/code> method. It will allow us to move the element by a certain x and y values. So if we want to move snake by 100px to the right side should use:<\/p>\n<pre>snake.translate(100,0);<\/pre>\n<p>Now we can use that knowledge to tell our snake to continuously move to the right size until it cannot move further (we don\u2019t want him to run away, right?). To achieve that, we could create a simple interval that each time will move the snake by an increased value. Then we need to find a chart property that will allow us to define the boundaries that will keep the snake inside the chart. In this case, we can use the <code>chart.plotWidth<\/code> property. Additionally, we may use another chart properties \u2013 <code>chart.plotLeft<\/code> and <code>chart.plotTop<\/code> to update the snake\u2019s initial position (right now it is rendered outside of the plot area, we want him to be inside it).<\/p>\n<pre>const snake = chart.renderer.rect(\r\n    chart.plotLeft,\r\n    chart.plotTop,\r\n    20,\r\n    20\r\n  )\r\n  .attr({\r\n    fill: 'red'\r\n  })\r\n  .add();\r\nlet x = 0;\r\nsetInterval(() = &gt; {\r\n  if (x + 20 &lt; chart.plotWidth) {\r\n    x += 20;\r\n    snake.translate(x, 0);\r\n  }\r\n}, 250);<\/pre>\n<h2>Feed the snake<\/h2>\n<p>So far we have learned how to create a snake, give him the ability to move, but he still lacks a very important skill \u2013 eating points. To do that, we need to remove a point somehow when it has the same position as our snake. To make it easier, I will set the same value for all points and the <a href=\"https:\/\/api.highcharts.com\/highcharts\/xAxis.min\" target=\"_blank\" rel=\"noopener noreferrer\">min<\/a> and <a href=\"https:\/\/api.highcharts.com\/highcharts\/xAxis.max\" target=\"_blank\" rel=\"noopener noreferrer\">max<\/a> properties values for both axes.<\/p>\n<pre>const chart = Highcharts.chart('container', {\r\n  chart: {\r\n    type: 'scatter'\r\n  },\r\n  xAxis: {\r\n    min: 0,\r\n    max: 8\r\n  },\r\n  yAxis: {\r\n    min: 0,\r\n    max: 8\r\n  },\r\n  series: [{\r\n    pointStart: 1,\r\n    data: [8, 8, 8, 8, 8, 8, 8, 8]\r\n  }]\r\n});<\/pre>\n<p>Now we are ready to implement this feature. All we have to do is to compare the pixel position of the snake with the points.<br \/>\nTo get the actual snake position, we need to add a translate value to its initial position. Translate value can be found under <code>snake.translateX<\/code> property, to get the initial position, we could use the <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.SVGElement#attr\" target=\"_blank\" rel=\"noopener noreferrer\">attr()<\/a> method to return a value of a certain attribute.<\/p>\n<pre>const snakePosX = snake.attr('x') + snake.translateX;<\/pre>\n<p>There are several ways to find a pixel coordinates of a point, but the easiest one is to use axis <a href=\"https:\/\/api.highcharts.com\/class-reference\/Highcharts.Axis#toPixels\" target=\"_blank\" rel=\"noopener noreferrer\">toPixels()<\/a> method that will return a pixel position of the value on the chart or axis.<\/p>\n<pre>const pointPosX = xAxis.toPixels(point.x)<\/pre>\n<p>Now, all we have to do is create a simple function that will iterate over all points and remove whose distance is smaller than a snake size. To remove a point, we can use the <code>remove()<\/code> method. Then we are able to call that function inside the interval that is responsible for moving the snake. Our snake finally learned how to eat chart points.<\/p>\n<pre>function onCollision() {\r\n  const xAxis = chart.xAxis[0],\r\n    points = chart.series[0].points,\r\n    snakePosX = snake.attr('x') + snake.translateX;\r\n\r\n  points.forEach(point = &gt; {\r\n    const pointPosX = xAxis.toPixels(point.x);\r\n\r\n    if (Math.abs(snakePosX - pointPosX) &lt; 20) {\r\n      point.remove();\r\n    }\r\n  })\r\n}<\/pre>\n<p>Our snake has learned some basic abilities. Of course, to create a fully functional game, we still have a lot to improve, but the most important parts related to the snake\u2019s integration with the Highcharts library are described in this article.<\/p>\n<p>Feel free to check the final version of the <a href=\"https:\/\/mateuszkornecki.github.io\/highcharts-snake-game\/\" target=\"_blank\" rel=\"noopener noreferrer\">game<\/a> with the <a href=\"https:\/\/github.com\/mateuszkornecki\/highcharts-snake-game\/tree\/master\/src\" target=\"_blank\" rel=\"noopener noreferrer\">code<\/a>. Let me know if you have any questions or comments, I will be happy to hear from you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Step by step tutorial to create a snake game with Highcharts.<\/p>\n","protected":false},"author":253,"featured_media":20012,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"meta_title":"","meta_description":"","hc_selected_options":[],"footnotes":""},"categories":[210],"tags":[1094],"coauthors":[831],"class_list":["post-20010","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-highcharts-core"],"_links":{"self":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/users\/253"}],"replies":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/comments?post=20010"}],"version-history":[{"count":1,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20010\/revisions"}],"predecessor-version":[{"id":29306,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20010\/revisions\/29306"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media\/20012"}],"wp:attachment":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media?parent=20010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/categories?post=20010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/tags?post=20010"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/coauthors?post=20010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}