7

I'm trying to draw through on a HTML5 canvas. I managed to draw on the canvas but I need to do it dynamically. This is my JavaScript code:

var c=document.getElementById("yellow");
var ctx=c.getContext("2d");

ctx.beginPath();
ctx.moveTo(247,373);
ctx.lineTo(0,390);
ctx.lineTo(5,21);
ctx.lineTo(245,0);
ctx.lineTo(247,373);
ctx.closePath();
ctx.fillStyle="#ffca05";
ctx.globalAlpha=0.7;
ctx.strokeStyle = '#ffca05';
ctx.fill();
ctx.stroke();

I need to read the data from this json array and draw using these coordinates.

[{"x":"247", "y":"373"}, {"x":"0", "y":"390"},{"x":"5", "y":"21"},{"x":"245", "y":"0"}, {"x":"247", "y":"373"}]
Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
Bruno Laise
  • 117
  • 2
  • 6
  • 1
    Have you tried it with a `for` loop that repeatedly executes `ctx.lineTo(json[i].x,json[i].y);`? (The first `ctx.lineTo` acts like a `ctx.moveTo`). – Sebastian Simon Apr 27 '15 at 19:58

2 Answers2

3

All you have to do is iterate over the JS object in a for loop and repeatedly execute ctx.lineTo(). Note: the first ctx.lineTo() after a ctx.beginPath() acts like a ctx.moveTo().

You can run this code snippet to verify the result:

var c=document.getElementById("yellow");
var ctx=c.getContext("2d");
var json=[
  {"x":"247", "y":"373"},
  {"x":"0",   "y":"390"},
  {"x":"5",   "y":"21" },
  {"x":"245", "y":"0"  },
  {"x":"247", "y":"373"}
];

ctx.beginPath();
for(var i in json){
  ctx.lineTo(json[i].x,json[i].y);
}
ctx.closePath();
ctx.fillStyle="#ffca05";
ctx.globalAlpha=0.7;
ctx.strokeStyle="#ffca05";
ctx.fill();
ctx.stroke();
<canvas id="yellow" width="250" height="400"></canvas>

PS: I can notice that the top corner at the top edge of the canvas (and presumably the left one as well) are a bit cut off. Just add 1 or so to each coordinate to fix this:

[
  {"x":"248", "y":"374"},
  {"x":"1",   "y":"391"},
  {"x":"6",   "y":"22" },
  {"x":"246", "y":"1"  },
  {"x":"248", "y":"374"}
];
Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
  • one more question, and if my file is external? – Bruno Laise Apr 27 '15 at 20:52
  • @BrunoLaise You mean your JSON file? I guess you have to [get it via AJAX](http://jaskokoyn.com/2013/07/24/external-json-file/) or so… I don’t know, I’ve never done this. – Sebastian Simon Apr 27 '15 at 21:10
  • 1
    It is a [bad idea to use `for...in` to iterate over an array](http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such-a-bad-idea). [`Array.prototype.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) or just a normal [`for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) statement would be better. – Useless Code Apr 27 '15 at 22:05
  • @UselessCode Does this even apply here? `for … in` only doesn’t work for missing keys in an Array but there’s no such thing in the above example. – Sebastian Simon Apr 27 '15 at 22:20
  • @Xufox That is not the only difference, look at some of the other answers to that question. Particularly important to this case is the fact that [you can't depend on `for...in` to iterate over the items in numeric order.](http://stackoverflow.com/a/21558566/778975). `for...in` is intended to be used to iterate over object properties. It is capable of iterating over arrays because they are actually "list-like objects". Most JS engines will iterate in the order you expected but it is not guaranteed. – Useless Code Apr 28 '15 at 04:42
  • The new [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) statement on the other hand [does guarantee the correct order](http://stackoverflow.com/q/29477973/778975) and avoids some of the [other](http://stackoverflow.com/a/4261096/778975) [problems](http://stackoverflow.com/a/15403248/778975) with using `for..in` with arrays. Unfortunately at the current time for of is not well [supported](http://kangax.github.io/compat-table/es6/#for..of_loops) by all browsers. – Useless Code Apr 28 '15 at 04:44
0

I cannot comment just yet, but as to the matter of reading an external JSON file: If your file is available on some URL, you can use AJAX through jQuery to easily get the JSON data you need, parse it and store it in a variable local to your webpage/application. Quick example:

var myJSON; //the json object data you're going to draw to canvas with

$(document).ready(function(){
        $.ajax({
            url: "myurl.com/myjsonfile",
            dataType: "text",
            success: function(data) {
                myJSON = $.parseJSON(data);
                drawToCanvas(myJSON); //you can, perhaps, make the code
                                      //Xufox provided into a function that
                                      //you pass your myJSON var to once it
                                      //is loaded.
            }
        });
    })

The '$.ajax' call will handle obtaining the data from the URL you specified above, and will execute the 'drawToCanvas()' method only once the data has been loaded and passed to myJSON (which is then passed to the method).

You could reference the parameter directly in your function, or store it in a local variable:

function drawToCanvas(jsonObj) {
    var json = jsonObj;

    ctx.beginPath();
    for(var i in json){
       ctx.lineTo(json[i].x,json[i].y);
    }
    ...
JLP1990
  • 41
  • 1
  • 6
  • 1
    [`for...in` should not be used for iterating over an array](http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such-a-bad-idea). [`Array.prototype.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) or a normal [`for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) statement would be better. – Useless Code Apr 27 '15 at 22:09
  • Yes. I simply copied the code a prior commenter provided to Bruno. It would be pretty easy to use a forEach here, as each of the objects is contained in an array. – JLP1990 Apr 27 '15 at 23:33