aboutsummaryrefslogblamecommitdiffstats
path: root/public/js/app.js
blob: 65bb92f80da8e0ea5ccdad3035d5500eb7577ca3 (plain) (tree)




















                                                                               
                                          



                             







                                                        




                                                                                  



                                                                                 
                                            


                                      
                                                                
                            

                                                    
 
                                           


                         














                                               
                                


















                                                
                                                
 
                                  


                              

                             



                                            
                                        
                      


                                                                              




                                          
                                       

                                   
                                                   






                                                                
                              

                                   




                                                                                  

                                           
                                



                                                     
                                      
                                                                                  

                                      
                                                                    


         
                                

                           



                                                                           
                             

                                                

                                           
                       


                                         
                       
                       
 

                                                      
 

                                                    





                                                           

                                                            

                                              
 


                                                                                                                      


                              
                                                                              
                                            

                                                   
 
                                




                                                    
                                                                       
      
  
/*
    Social program for Ramaskrik.
    Copyright (C) 2019  Harald Eilertsen <haraldei@anduin.net>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

function load_screenings(data_done) {
    let req = new XMLHttpRequest()
    req.addEventListener("load", data_done)
    req.open("GET", "ramaskrik-2019.json")
    req.responseType = "json"
    req.send()
}

function pad(num) {
    return num > 9 ? num.toString() : "0" + num
}

function time_f(t) {
    return pad(t.getHours()) + ":" + pad(t.getMinutes())
}

function date_f(d) {
    let opts = { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }
    return new Intl.DateTimeFormat('nb-NO', opts).format(d)
}

function isodate(d) {
    return d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate())
}

window.addEventListener("load", function() {
    let screenings_by_date = new Map()

    function _add(screening) {
        let d = new Date(screening.date || screening.start_time)
        let key = isodate(d)
        if (!screenings_by_date.has(key))
            screenings_by_date.set(key, new Array())

        let s = screenings_by_date.get(key)
        s.push(screening)
    };

    function break_text(c, text, x, y, width) {
        let len = c.measureText(text).width
        if (len < width) {
            c.fillText(text, x, y)
            return
        }

        let expl = text.split(' ')
        let space = c.measureText(' ').width
        let llen = 0
        let lpos = 0

        for (let frag of expl) {
            flen = c.measureText(frag).width
            llen += flen
            if (llen >= width) {
                llen = 0
                lpos = 0
                y += 15
            }
            c.fillText(frag, x + lpos, y)
            lpos += flen + space
        }
    }

    function center_text(c, text, x, y, width) {
        let len = c.measureText(text).width
        let xpos = Math.ceil((width - len) / 2)
        c.fillText(text, x + xpos, y)
    }

    let margin = 30;
    let xmargin = 50;

    function draw_timescale(c, start, end) {
        let dur = Math.ceil((end - start) / 100)

        c.font = '10px sans-serif'
        c.lineWidth = 'thin'
        c.strokeStyle = '#ccc'

        let canvas = c.canvas

        for (let y = 0; y <= dur; y += 30) {
            let ypos = y + margin;
            c.beginPath()
            c.moveTo(35, ypos)
            c.lineTo(canvas.width, ypos)
            c.stroke()

            let label = time_f(new Date(start.valueOf() + y * 30000 + margin))
            c.fillText(label, 5, ypos + 3)
        }
    }

    function draw_room_headers(c, rooms) {
        let x = 0;
        c.font = 'bold 15px sans-serif'

        for (let r of [...rooms]) {
            center_text(c, r, xmargin + x, 15, 100)
            x += 150
        }
    }

    function draw_screenings(c, screenings, start_time, rooms) {
        let r = [...rooms]

        c.strokeStyle = '#cfc'

        for (let s of screenings) {
            let stt = new Date(s.start_time)
            let ett = new Date(s.end_time)
            let ystart = Math.ceil((stt - start_time) / 30000) + margin;
            let height = Math.ceil((ett - start_time ) / 30000) + margin - ystart;
            let ri = r.findIndex(el => el == s.room.name)
            let xstart = xmargin + ri * 150

            c.fillStyle = '#cc8'
            c.fillRect(xstart, ystart, 100, height)
            c.strokeRect(xstart, ystart, 100, height)

            c.fillStyle = '#000'
            c.font = '10px sans-serif'
            c.fillText(time_f(stt) + " - " + time_f(ett), xstart + 5, ystart + 10)

            c.font = '12px sans-serif'
            break_text(c, s.film.title, xstart + 5, ystart + 25, 85)
        }
    }

    load_screenings(function() {
        let ts = Date.now()

        this.response.forEach(_add)

        console.log("Screenings in " + screenings_by_date.size + " days: ")
        for (let date of screenings_by_date.keys()) {
            console.log(date)

            let s = screenings_by_date.get(date)
            let start_time = new Date(s
                .map( el => el.start_time )
                .sort()
                .shift())
            let end_time = new Date(s
                .map( el => el.end_time )
                .sort()
                .pop())

            console.log("  Start time: " + start_time)
            console.log("  End time  : " + end_time)

            let dur = (end_time - start_time) / 1000
            console.log("  Duration  : " + dur)

            // Each line in the canvas equals half a minute
            let canvas_height = Math.ceil(dur / 30) + 60

            let p = document.querySelector('#program')
            let day = document.createElement('section')
            let rooms = new Set(s.map( el => el.room.name ))
            let width = xmargin + 150 * rooms.size
            let dateobj = new Date(date)
            console.log("dateobj: " + dateobj)

            day.id = "program-" + isodate(dateobj)
            day.innerHTML = '<h2>' + date_f(dateobj) + '</h2>'
                + '<canvas id="canvas-' + isodate(dateobj) + '" height="' + canvas_height + '" width="' + width + '">'
                + '</canvas>'
            p.appendChild(day)

            let canvas = document.getElementById('canvas-' + isodate(dateobj))
            let c = canvas.getContext('2d');
            c.fillStyle = '#233'
            c.fillRect(0, 0, width, canvas_height);

            c.fillStyle = '#fff'
            draw_room_headers(c, rooms)
            draw_timescale(c, start_time, end_time)
            draw_screenings(c, s, start_time, rooms)
        }

        console.log("Total elapsed time: " + (Date.now() - ts) + "ms.")
    })
})