Home > Software design >  How to convert a python list of tuples to an array in JavaScript?
How to convert a python list of tuples to an array in JavaScript?

Time:11-11

I am trying to make a website using Flask, where I pass in HTML canvas data to a database and then use that data in another route. When I retrieve the data from the database, it's in the form of a list, here's an example of that list with only one element :

[(1, 'circle', '{"pencil":[{"startx":346,"starty":105,"endx":346,"endy":105,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":344,"endy":104,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":341,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":338,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":333,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":330,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":338,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":338,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":109,"thick":2,"color":"#000000"}],"line":[],"rectangle":[],"circle":[],"eraser":[]}', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu4AAAHCCAYAAACwm0waAAAAAXNSR0IArs4c6QAAIABJREFUeF7t3W2SI9lVBuDr/vD8gOgmAsLegNkGrB22Ke4KQjEiAAAECBAgQIEBAcbcHCBAgQIAAAQIECCQQ D/vr4ThKs0KewAAAABJRU5ErkJggg==', '10', '10', '100', '100')]

Following several previous answers given in this type of question, I tried the following approach, first I used json.dumps():

In Flask:

files = json.dumps(files)
return render_template("edit.html", files=files)

In edit.html, I pass it into a function simply as:

<button id="show" onclick="loadImages(`{{ files }}`)">View</button>

Finally in edit.js, I try to read it in an array as follows:

function loadImages(sources) {
    var canvas = document.getElementById("paint");    
    var ctx = canvas.getContext("2d");

    console.log(sources);
    
    sources = JSON.parse(sources);
    console.log(typeof(sources)); 
    for(var i = 0; i < sources.length; i  ) {
        ctx.drawImage(sources[i][3], sources[i][4], sources[i][5], sources[i][6], sources[i][7]);
    
    }
  }

But this returns an error:

Uncaught SyntaxError: Unexpected token p in JSON at position 18
    at JSON.parse (<anonymous>)
    at loadImages (edit.js:16)
    at HTMLButtonElement.onclick (edit:39)

The output of the console.log(sources) in the loadImages function is :

[[1, "circle", "{"pencil":[{"startx":346,"starty":105,"endx":346,"endy":105,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":344,"endy":104,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":341,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":338,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":333,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":330,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":326,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":326,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":322,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":319,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":317,"endy":103,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":315,"endy":104,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":314,"endy":104,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":312,"endy":104,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":311,"endy":105,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":310,"endy":106,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":308,"endy":106,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":307,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":306,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":304,"endy":109,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":302,"endy":110,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":301,"endy":111,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":107,"thick":2,"color":"#000000"},{"startx":346,"starty":105,"endx":336,"endy":109,"thick":2,"color":"#000000"}],"line":[],"rectangle":[],"circle":[],"eraser":[]}", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu4AAAHCCAYAAACwm0waAAAAAXNSR0IArs4c6QAAIABJREFUeF7t3W2SI9lVBuDr/vD8gOgmAsLegNkGrB22ARuAgAimDT/G022ItCuH7LRUkkpS3vPxTITDMK5Snvu8N1VvZ6eyfjX8Q4AAAQIECBAgQIBAeIFfhZ/QgAQIECBAgAABAgQIDMXdJiBAgAABAgQIECCQQEBxTxCSEQkQIECAAAECBAgo7vYAAQIECBAgQIAAgQQCinuCkIxIgAABAgQIECBAQHG3BwgQIECAAAECBAgkEFDcE4RkRAIECBAgQIAAAQKKuz1AgAABAgQIECBAIIGA4p4gJCMSIECAAAECBAgQUNztAQIECBAgQIAAAQIJBBT3BCEZkQABAgQIECBAgIDibg8QIECAAAECBAgQSCCguCcIyYgECBAgQIAAAQIEFHd7gAABAgQIECBAgEACAcU9QUhGJECAAAECBAgQIKC42wMECBAgQIAAAQIEEggo7glCMiIBAgQIECBAgAABxd0eIECAAAECBAgQIJBAQHFPEJIRCRAgQIAAAQIECCju9gABAgQIECBAgACBBAKKe4KQjEiAAAECBAgQIEBAcbcHCBAgQIAAAQIECCQQUNwThGREAgQIECBAgAABAoq7PUCAAAECBAgQIEAggYDiniAkIxIgQIAAAQIECBBQ3O0BAgQIECBAgAABAgkEFPcEIRmRAAECBAgQIECAgOJuDxAgQIAAAQIECBBIIKC4JwjJiAQIECBAgAABAgQUd3uAAAECBAgQIECAQAIBxT1BSEYkQIAAAQIECBAgoLjbAwQIECBAgAABAgQSCCjuCUIyIgECBAgQIECAAAHF3R4gQIAAAQIECBAgkEBAcU8QkhEJECBAgAABAgQIKO72AAECBAgQIECAAIEEAop7gpCMSIAAAQIECBAgQEBxtwcIECBAgAABAgQIJBBQ3BOEZEQCBAgQIECAAAECirs9QIAAAQIECBAgQCCBgOKeICQjEiBAgAABAgQIEFDc7QECBAgQIECAAAECCQQU9wQhGZEAAQIECBAgQICA4m4PECBAgAABAgQIEEggoLgnCMmIBAgQIECAAAECBBR3e4AAAQIECBAgQIBAAgHFPUFIRiRAgAABAgQIECCguNsDBAgQIECAAAECBBIIKO4JQjIiAQIECBAgQIAAAcXdHiBAgAABAgQIECCQQEBxTxCSEQkQIECAAAECBAgo7vYAAQIECBAgQIAAgQQCinuCkIxIgAABAgQIECBAQHG3BwgQIECAAAECBAgkEFDcE4RkRAIECBAgQIAAAQKKuz1AgAABAgQIECBAIIGA4p4gJCMSIECAAAECBAgQUNztAQIECBAgQIAAAQIJBBT3BCEZkQABAgQIECBAgIDibg8QIECAAAECBAgQSCCguCcIyYgECBAgQIAAAQIEFHd7gAABAgQIECBAgEACAcU9QUhGJECAAAECBAgQIKC42wMECBAgQIAAAQIEEggo7glCMiIBAgQIECBAgAABxd0eIECAAAECBAgQIJBAQHFPEJIRCRAgQIAAAQIECCju9gABAgQIECBAgACBBAKKe4KQjEiAAAECBAgQIEBAcbcHCBAgQIAAAQIECCQQUNwThGREAgQIECBAgAABAoq7PUCAAAECBAgQIEAggYDiniAkIxIgQIAAAQIECBBQ3O0BAgQIECBAgAABAgkEFPcEIRmRAAECBAgQIECAgOJuDxAgQIAAAQIECBBIIKC4JwjJiAQIECBAgAABAgQUd3uAAAECBAgQIECAQAIBxT1BSEYkQIAAAQIECBAgoLjbAwQIECBAgAABAgQSCCjuCUIyIgECBAgQIECAAAHF3R4gQIAAAQIECBAgkEBAcU8QkhEJECBAgAABAgQIKO72AAECBAgQIECAAIEEAop7gpCMSIAAAQIECBAgQEBxtwcIECBAgAABAgQIJBBQ3BOEZEQCBAgQIECAAAECirs9QIAAAQIECBAgQCCBgOKeICQjEiBAgAABAgQIEFDc7QECBAgQIECAAAECCQQU9wQhGZEAAQIECBAgQICA4m4PECBAgAABAgQIEEggoLgnCMmIBAgQIECAAAECBBR3e4AAAQIECBAgQIBAAgHFPUFIRiRAgAABAgQIECCguNsDBAgQIECAAAECBBIIKO4JQjIiAQIECBAgQIAAAcXdHiBAgAABAgQIECCQQEBxTxCSEQkQIECAAAECBAgo7vYAAQIECBAgQIAAgQQCinuCkIxIgAABAgQIECBAQHG3BwgQ6CLwxzHGke95X8cYH7vgWicBAgQIPF/gyB9iz1 NIxAgQODPAj OMT4FwfjfMca7ILMYgwABAgQSCyjuicMzOgECJwVeK 1HlOifxxgfdpMtV/vfy4sAAQIECNwggg==", "10", "10", "100", "100"]]

I tried multiple approaches to get this done, but this was the closest I could reach to what I want, how do I proceed to correct this?

CodePudding user response:

I found few problems in this code - all with template:

  1. template in flask escapes data (to make it safer) so using {{ file }} it creates HTML with

    [[1, &#34;circle&#34;, &#34;{\&#34;pencil\&#34;:[
    

    You can see it in browser if you use Show Page Source ( Ctrl U).

    It needs {{ file|safe }} to create correct HTML

    [[1, "circle", "{\"pencil\":[ 
    
  2. it doesn't need ticks in loadImages( ``...`` )

  3. because files puts string with " " so loadImage has to be in ' '

    onclick='loadImages({{ files|safe }})'
    
  4. browser treats text from files as normal code so it parses data at loading and it doesn't need JSON.parse()

  5. to draw image you have to create Image and assign data to .src

         var img = new Image();
         img.src = sources[i][3];
    
         ctx.drawImage(img, ...)
    

Minimal working code

EDIT:

You don't have to use json.dumps(data) but {{ data|tojson }}

Eventually you can use {{ data|safe }} but it will need to change some " " into ' '.

from flask import Flask, request, render_template_string
import json

app = Flask(__name__)

data = [(1, 'circle',
         '{"pencil":[\
             {"startx":346,"starty":105,"endx":346,"endy":105,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":344,"endy":104,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":341,"endy":103,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":338,"endy":103,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":336,"endy":103,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":333,"endy":103,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":330,"endy":103,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":338,"endy":107,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":338,"endy":107,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":336,"endy":107,"thick":2,"color":"#000000"},\
             {"startx":346,"starty":105,"endx":336,"endy":109,"thick":2,"color":"#000000"}],\
          "line":[],"rectangle":[],"circle":[],"eraser":[]\
         }',
         'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAAAAACoWZBhAAAAMklEQVR4nEXNwQkAMBACwfFI/y2bxwXia8FFUwF1pCCNJTIIwaD04ctsKRyaldI/9i8u1iwOE6FA880AAAAASUVORK5CYII=',
         '10', '10', '10', '10'
)]

@app.route('/', methods=['GET', 'POST'])
def index():
    text = json.dumps(data)
    return render_template_string('''
<script>
function loadImages(sources) {
    console.log(sources);

    var canvas = document.getElementById("paint");    
    var ctx = canvas.getContext("2d");
    
    for(var i = 0; i < sources.length; i  ) {
        var data = sources[i]
        console.log(data[3]);
        var img = new Image();
        img.src = data[3];
        ctx.drawImage(img, data[4], data[5]); //, data[6], data[7]);
    }
}
</script>

<body>
<h1>files</h1>
<pre>{{ files }}</pre>
<h1>files|safe</h1>
<pre>{{ files|safe }}</pre>
<h1>files|tojson</h1>
<pre>{{ files|tojson }}</pre>
<hr>

<canvas id="paint" width="100" height="100"></canvas><br/>

<button id="show" onclick='loadImages({{ files|safe <button id="show" onclick='loadImages({{ files|safe }})'>View files|safe</button>

<button id="show" onclick='loadImages({{ data|tojson }})'>View data|tojson</button>

<button id="show" onclick="loadImages({{ data|safe }})">View data|safe</button>

</body>
''', files=text, data=data)
if __name__ == '__main__':
    #app.debug = True 
    app.run()

For your data:image I get error image broken so I use my small icon 10x10

enter image description here

but I don't know why but sometimes I have to click button two times to see image.

  • Related