Browse Source

WIP passage à vue.js pour le frontend

Baptiste Jonglez 6 years ago
parent
commit
b24de055b0

+ 89 - 0
panorama/management/commands/test_projections.py

@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals, division, print_function
+
+from math import log, tan, pi, radians
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+from django.core.management.base import BaseCommand, CommandError
+from django.conf import settings
+
+from panorama.models import Panorama, Reference
+
+def bearing_diff(b1, b2):
+    """In degrees"""
+    return (b1 - b2) % 360
+
+def projection_factory(transform):
+    def projection(location, p1, p2):
+        """For now, simply returns the scaling factors for x and y given two reference points"""
+        dx = (p2.x - p1.x) / (radians(bearing_diff(location.bearing(p2.reference_point), location.bearing(p1.reference_point))))
+        dy = (p2.y - p1.y) / (transform(location.elevation(p2.reference_point)) - transform(location.elevation(p1.reference_point)))
+        return (dx, dy)
+    return projection
+
+equirectangular = projection_factory(lambda phi: radians(phi))
+cylindrical = projection_factory(lambda phi: tan(radians(phi)))
+mercator = projection_factory(lambda phi: log(tan(pi/4 + radians(phi)/2)))
+projections = [('equirectangular', equirectangular),
+               ('cylindrical', cylindrical),
+               ('mercator', mercator)]
+
+class Command(BaseCommand):
+
+    def add_arguments(self, parser):
+        parser.add_argument('pano_id', type=int)
+
+    def handle(self, *args, **options):
+        p = Panorama.objects.get(pk=options['pano_id'])
+        for proj_name, proj in projections:
+            self.stdout.write("\n{}".format(proj_name))
+            data = {'distx': [], 'disty': [], 'dx': [], 'dy': [], 'ref1': [], 'ref2': [], 'middlex': [], 'ref1.x': []}
+            for ref1 in p.panorama_references.order_by('x'):
+                for ref2 in p.panorama_references.order_by('x'):
+                    if ref2 == ref1:
+                        continue
+                    if ref2.x >= ref1.x:
+                        (dx, dy) = proj(p, ref1, ref2)
+                    else:
+                        (dx, dy) = proj(p, ref2, ref1)
+                    distx = ref2.x - ref1.x
+                    disty = ref2.y - ref1.y
+                    middlex = (ref2.x + ref1.x) / 2
+                    data['ref1'].append(ref1)
+                    data['ref2'].append(ref2)
+                    data['ref1.x'].append(ref1.x)
+                    data['distx'].append(distx)
+                    data['disty'].append(disty)
+                    data['middlex'].append(middlex)
+                    data['dx'].append(dx)
+                    data['dy'].append(dy)
+                    #self.stdout.write('{} - {}'.format(ref1.reference_point.name, ref2.reference_point.name))
+                    #self.stdout.write('dx = {}'.format(dx))
+                    #self.stdout.write('dy = {}'.format(dy))
+            # Detect outliers
+            for axis in ['dx', 'dy']:
+                median = np.median(data[axis])
+                self.stdout.write("\nMedian for {}: {}".format(axis, median))
+                for ref1, ref2, d in zip(data['ref1'], data['ref2'], data[axis]):
+                    if ref2.pk < ref1.pk:
+                        continue
+                    if abs(d - median) / median >= 0.15:
+                        self.stdout.write("Outlier: ({:5}, {:5}) - ({:5}, {:5}) → {}={}".format(ref1.x, ref1.y, ref2.x, ref2.y, axis, d))
+            mediandx = np.median(data['dx'])
+            mediandy = np.median(data['dy'])
+            if proj_name == 'equirectangular':
+                for xvar in ['distx', 'disty', 'middlex', 'ref1.x']:
+                    fig, ax = plt.subplots()
+                    ax.scatter(x=data[xvar], y=data['dx'], c=data['ref1.x'], alpha=0.5)
+                    ax.hlines([mediandx], 0, 1, transform=ax.get_yaxis_transform(), colors='r')
+                    ax.set_title('dx as a function of {}'.format(xvar))
+                    plt.show()
+            for xvar in ['dx', 'distx', 'disty', 'middlex', 'ref1.x']:
+                fig, ax = plt.subplots()
+                ax.scatter(x=data[xvar], y=data['dy'], c=data['ref1.x'], alpha=0.5)
+                ax.hlines([mediandy], 0, 1, transform=ax.get_yaxis_transform(), colors='r')
+                ax.set_title('dy as a function of {}, for {} projection'.format(xvar, proj_name))
+                plt.show()

+ 3 - 4
panorama/models.py

@@ -233,10 +233,9 @@ class Panorama(ReferencePoint):
         panorama."""
         panorama."""
         return [{"id": r.pk,
         return [{"id": r.pk,
                  "name": r.reference_point.name,
                  "name": r.reference_point.name,
-                 # Adapt to js-based coordinates (x between 0 and 1, y
-                 # between -0.5 and 0.5)
-                 "x": r.x / r.panorama.image_width,
-                 "y": (r.y / r.panorama.image_height) - 0.5,
+                 "kind": r.reference_point.kind,
+                 "x": r.x,
+                 "y": r.y,
                  "cap": self.bearing(r.reference_point),
                  "cap": self.bearing(r.reference_point),
                  "elevation": self.elevation(r.reference_point)}
                  "elevation": self.elevation(r.reference_point)}
                 for r in self.panorama_references.all()]
                 for r in self.panorama_references.all()]

+ 11 - 4
panorama/static/panorama/css/celutz.css

@@ -105,10 +105,16 @@ body {
     overflow:hidden;
     overflow:hidden;
 }
 }
 
 
-#mon-canvas {
-    background-color:#000;
-    margin:auto;
-    display:block;
+#app {
+    height: 100%;
+}
+
+#pano {
+    background-color: #000;
+    margin: auto;
+    display: block;
+    height: 600px;
+    cursor: crosshair;
 }
 }
 
 
 #info {
 #info {
@@ -268,6 +274,7 @@ fieldset#adding {
     color:#FFF;
     color:#FFF;
     background-color:rgba(100,0,0,0.5);
     background-color:rgba(100,0,0,0.5);
 }
 }
+
 #map {
 #map {
     height: 100%;
     height: 100%;
     padding: -10px;
     padding: -10px;

BIN
panorama/static/panorama/img/leaflet/v0.7.7/images/marker-icon.png


BIN
panorama/static/panorama/img/marker-icon-2x.png


+ 2 - 350
panorama/static/panorama/js/pano.js

@@ -7,25 +7,12 @@ var debug_mode = false;
 var canvas;
 var canvas;
 var cntext;
 var cntext;
 var point_list = new Array();
 var point_list = new Array();
-var zoom = 0;
-var zooms = new Array();
-var prev_zm;
-var zm;
-var tile = {width:256, height:256};
-var ntiles = {x:228, y:9};
 var border_width = 2;
 var border_width = 2;
 var imageObj = new Array();
 var imageObj = new Array();
 
 
 // minimum and maximum azimuth
 // minimum and maximum azimuth
 var alpha_domain = {start:0, end:360};
 var alpha_domain = {start:0, end:360};
 
 
-var fingr = 0;  // mémorisation de lécart entre doigts;
-var last  = {x:0,y:0};
-var shift = {x:0,y:0};
-var mouse = {x:0,y:0};
-var speed = {x:0,y:0};
-var canvas_pos = {x:0,y:0};
-var tmt;
 var is_located = false;
 var is_located = false;
 var point_colors = {
 var point_colors = {
     'pano_point' : '255,128,128', // red
     'pano_point' : '255,128,128', // red
@@ -73,126 +60,11 @@ function fmodulo(val, div) {                // pour obtenir un modulo dans l'esp
     return (val%div+div)%div;               // il y a peut être plus simple, mais en attendant ....
     return (val%div+div)%div;               // il y a peut être plus simple, mais en attendant ....
 }
 }
 
 
-function distort_canvas(p, x, y) {
-    if (p == 0) distort = 0;
-    else {
-    cntext.save();
-    distort++;
-        cntext.clearRect(0, 0, canvas.width, 2*canvas.height);
-    var ratio = (canvas.width-2*distort)/canvas.width;
-    var shift = canvas.height/2*(1-ratio);
-    cntext.scale(1, ratio);
-    if (p == 1) cntext.translate(0, 0);
-    else if (p == -1) cntext.translate(0, 0);
-    draw_image(x, y);
-    cntext.restore();
-    }
-}
-
-function draw_image(ox, oy) {
-    var ref_vals  = {x:last.x, y:last.y, zoom:zoom};
-    ox = nmodulo(ox-canvas.width/2, zm.im.width);        // pour placer l'origine au centre du canvas
-    oy = Math.floor(oy-canvas.height/2);                 // pas de rebouclage vertical
-
-    cntext.clearRect(0, 0, canvas.width, canvas.height);
-    cntext.fillStyle = "rgba(128,128,128,0.8)";
-
-    if (canvas.height > zm.im.height) {
-        var fy = Math.floor((oy+canvas.height/2-zm.im.height/2)/(tile.height*zm.ntiles.y))*zm.ntiles.y;
-        if (fy < 0) fy = 0;
-        var ly = fy + zm.ntiles.y;
-    } else {
-        var fy = Math.floor(oy/tile.height);
-        var ly = Math.floor((oy+canvas.height+tile.height-1)/tile.height+1);
-        if (fy < 0) fy = 0;
-        if (ly > zm.ntiles.y) ly = zm.ntiles.y;
-    }
-
-    for (var j=fy; j<ly; j++) {
-        var delta_y = (Math.floor(j/zm.ntiles.y) - Math.floor(fy/zm.ntiles.y)) * (tile.height - zm.last_tile.height);
-        var dy = j*tile.height - oy - delta_y;
-        var ny = j%ntiles.y;
-        var wy = zm.tile.width;
-        if (ny == zm.ntiles.y - 1) wy = zm.last_tile.height;
-
-        var cpx = 0;
-        var i = 0;
-        var Nx = zm.ntiles.x;
-        while (cpx < ox+canvas.width) {
-            var cur_width = zm.tile.width;
-            if (i%Nx == zm.ntiles.x-1) cur_width = zm.last_tile.width;
-            if (cpx >= ox-cur_width) {
-                var nx = i%Nx;
-                var idx = nx+'-'+ny+'-'+ref_vals.zoom;
-                if (imageObj[idx] && imageObj[idx].complete) {
-                    draw_tile(idx, cpx-ox, dy); // l'image est déja en mémoire, on force le dessin sans attendre.
-                } else {
-                    var fname = get_file_name(nx, ny, ref_vals.zoom);
-                    imageObj[idx] = new Image();
-                    imageObj[idx].src = fname;
-                    var ts = zm.get_tile_size(nx, ny);
-                    cntext.fillRect(cpx-ox, dy, ts.width, ts.height);
-                    imageObj[idx].addEventListener('load', (function(ref, idx, dx, dy, ox, oy, ts) {
-                        return function() {        // closure nécéssaire pour gestion assynchronisme !!!
-                            draw_tile_del(ref, idx, dx, dy, ox, oy, ts.width, ts.height);
-                            };
-                        })(ref_vals, idx, cpx-ox, dy, ox, oy, ts), false);
-                }
-        //        load_image(zoom, nx, ny, shx, shy, cpx-ox, dy, ox, oy);
-            }
-        cpx += cur_width;
-        i++;
-        }
-    }
-    drawDecorations(ox, oy);
-    var cap_ele = zm.get_cap_ele(last.x, zm.im.height/2-last.y);
-    angle_control.value = cap_ele.cap.toFixed(2);
-    elvtn_control.value = cap_ele.ele.toFixed(2);
-    update_url();
-
-    // draw minimap
-    if (Object.keys(ref_points).length>1){
-        // Draw the mijimap only if there are at least 2 reference points (so the size is known)
-        if (typeof panorama_lat !== 'undefined') {
-            if (map_never_drawn ) { load_map() }
-            update_map();
-        } else {
-            // hack: It updates well when the 2nd points is pointed, but the map
-            // failed to load due to the missing JS variables linked to the panorama
-            // (head of view.html), so reload the page first.
-            location.reload(); 
-        };
-        $('#expandmap').css({'visibility': 'visible'})
-    } else {
-        // remove the expandmap button
-        $('#expandmap').css({'visibility': 'hidden'})
-    }
-}
 
 
-function draw_tile_del(ref, idx, tx, ty, ox, oy, twidth, theight) {
-    if (ref.zoom == zoom && ref.x == last.x && ref.y == last.y) {
-        draw_tile(idx, tx, ty);
-        drawDecorations(ox, oy, tx, ty, twidth, theight);
-    }
-}
-
-function draw_tile(idx, ox, oy) {
-    var img = imageObj[idx];
-    cntext.drawImage(img, ox, oy);
-}
 
 
 /** Draws the colored circles and the central line
 /** Draws the colored circles and the central line
  */
  */
 function drawDecorations(ox, oy, tx, ty, twidth, theight) {
 function drawDecorations(ox, oy, tx, ty, twidth, theight) {
-    if (twidth) {
-        cntext.save();
-        cntext.beginPath();
-        cntext.rect(tx, ty, twidth, theight);
-        cntext.clip();
-    }
-    var wgrd = zm.im.width/360;
-    var od = ((ox+canvas.width/2)/wgrd)%360;
-    var el = (zm.im.height/2 - (oy+canvas.height/2))/wgrd;
 
 
     // draw a vertical blue line with the central dot
     // draw a vertical blue line with the central dot
     // the dot is centered on (ox, oy) = (canvas.width/2, canvas.width/2)
     // the dot is centered on (ox, oy) = (canvas.width/2, canvas.width/2)
@@ -297,29 +169,6 @@ function erase_point() {
     putImage(last.x, last.y);
     putImage(last.x, last.y);
 }
 }
 
 
-/** Returns a 3-width zero-padded version of an int
- * ex: 3 -> "003"
- */
-function zero_pad(number) {
-    var temp = number.toString(10);
-    while (temp.length < 3) {
-        temp = '0' + temp;
-    }
-    return temp;
-}
-
-function get_file_name(x, y, z) { // recherche du fichier correspondant au zoom et à la position
-    return img_prefix+'/'+zero_pad(z)+'-'+zero_pad(x)+'-'+zero_pad(y)+'.jpg';
-}
-
-function get_base_name() {
-    /** 
-     * @returns the base name, which is the name (not path) of the folder where
-     * the tiles are.
-     */
-    return img_prefix.split('/').reverse()[0];
-}
-
 
 
 function keys(key) {
 function keys(key) {
     hide_links();
     hide_links();
@@ -403,93 +252,6 @@ function onImageClick(e) {
 }
 }
 
 
 
 
-function stickImage(e) {
-    var index = {};
-    if (e.changedTouches && e.changedTouches.length == 2) {
-        e.preventDefault();
-        // cas du zoom à 2 doigts
-        var nfingr = Math.sqrt((e.changedTouches[0].clientX - e.changedTouches[1].clientX)^2 +
-                       (e.changedTouches[0].clientY - e.changedTouches[1].clientY)^2);
-        var evt = {}
-        evt.pageX = (e.changedTouches[0].clientX + e.changedTouches[1].clientX)/2;
-        evt.pageY = (e.changedTouches[0].clientY + e.changedTouches[1].clientY)/2;
-        if (fingr > nfingr*2 || fingr < nfingr/2) {
-            evt.wheelDelta = fingr - nfingr;
-            fingr = nfingr;
-            return wheel_zoom(evt);
-        } else {
-            return;
-        }
-    }
-    if (e.touches) {
-        e.preventDefault();
-        index.x = e.changedTouches[0].clientX;
-        index.y = e.changedTouches[0].clientY;
-    } else {
-        index.x = e.pageX;
-        index.y = e.pageY;
-    }
-
-    var xs = mouse.x - index.x + shift.x;
-    var ys = mouse.y - index.y + shift.y;
-    speed.x = xs - last.x;  //mémorisation des vitesses horizontales
-    speed.y = ys - last.y;  //et verticales lors de ce déplacement
-    putImage(xs, ys);
-}
-
-function launchImage(e) {
-    var index = {};
-    if (e.touches) {
-        e.preventDefault();
-        index.x = e.changedTouches[0].clientX;
-        index.y = e.changedTouches[0].clientY;
-    } else {
-        index.x = e.pageX;
-        index.y = e.pageY;
-    }
-    distort_canvas(0);
-    canvas.removeEventListener('mousemove', stickImage, false);
-    canvas.removeEventListener('touchmove', stickImage, false);
-    //document.onmousemove = null;
-    shift.x = index.x - mouse.x + shift.x;
-    shift.y = index.y - mouse.y + shift.y;
-    tmt = setTimeout(inertialImage, 100);
-}
-
-function putImage(x, y) { // est destiné à permettre l'effet d'amortissement par la mémorisation de la position courante.
-    if (!zm.is_updated) return;
-    if (x >= zm.im.width) {   // rebouclage horizontal
-        shift.x -= zm.im.width;
-        x -= zm.im.width;
-    } else if (x < 0) {
-        shift.x += zm.im.width;
-        x += zm.im.width;
-    }
-    if (y >= zm.im.height) {   // pas de rebouclage vertical mais blocage
-        //distort_canvas(1, x, y);
-        shift.y = zm.im.height-1;
-        y = zm.im.height-1;
-    } else if (y < 0) {
-        //distort_canvas(-1, x, y);
-        shift.y = 0;
-        y = 0;
-    }
-
-    last.x = x;
-    last.y = y;
-    draw_image(x, y);
-}
-
-function inertialImage() {
-    speed.x *= 0.9;
-    speed.y *= 0.9;
-    if (Math.abs(speed.x) > 2 || Math.abs(speed.y) > 2) {
-        putImage(last.x+speed.x, last.y+speed.y);
-        tmt = setTimeout(inertialImage, 100);
-    } else {
-        show_links();
-    }
-}
 
 
 function tri_ref_points(v1, v2) {
 function tri_ref_points(v1, v2) {
     return v1['x'] - v2['x'];
     return v1['x'] - v2['x'];
@@ -505,31 +267,8 @@ function sort_points_by_rev_distance(p1, p2) {
 
 
 
 
 function tzoom(zv) {
 function tzoom(zv) {
-    this.value = zv;
-    this.ntiles = {x:0,y:0};
-    this.tile = {width:0,height:0};
-    this.last_tile = {width:0,height:0};
-    this.max_tile = {width:0,height:0};
-    this.im = {width:0,height:0};
-    this.is_updated = false;
 
 
     this.refresh = function() {
     this.refresh = function() {
-        this.im.visible_width = this.tile.width*(this.ntiles.x-1)+this.last_tile.width;
-        this.is_updated = true;
-
-        this.im.width = this.im.visible_width;
-        this.im.height = this.tile.height*(this.ntiles.y-1)+this.last_tile.height;
-        if (this.last_tile.width > this.tile.width) {
-            this.max_tile.width = this.im.last_tile.width;
-        } else {
-            this.max_tile.width = this.tile.width;
-        }
-        if (this.last_tile.height > this.tile.height) {
-            this.max_tile.height = this.im.last_tile.height;
-        } else {
-            this.max_tile.height = this.tile.height;
-        }
-
         var ord_pts = new Array();
         var ord_pts = new Array();
         for(var label in ref_points) {
         for(var label in ref_points) {
             ord_pts.push(ref_points[label]);
             ord_pts.push(ref_points[label]);
@@ -725,61 +464,6 @@ function get_circle_size(point) {
     return Math.max(Math.min(size, 50), 7);
     return Math.max(Math.min(size, 50), 7);
 }
 }
 
 
-function reset_zooms () {
-    for(i=0; i<zooms.length; i++) zooms[i].is_updated = false;
-    zm.refresh();
-}
-
-function wheel_zoom (event) {
-    var zshift = {x:0, y:0};
-    if (event.pageX != undefined && event.pageX != undefined) {
-        zshift.x = event.pageX-canvas.width/2-canvas_pos.x;
-        zshift.y = event.pageY-canvas.height/2-canvas_pos.y;
-    }
-    //event.preventDefault();
-
-    var delta = (event.wheelDelta || -event.detail);
-    if (delta < 0 && zoom_control.value < zoom_control.max) {
-        zoom_control.value++;
-        change_zoom(zshift.x, zshift.y);
-    } else if (delta > 0 && zoom_control.value > zoom_control.min) {
-        zoom_control.value--;
-        change_zoom(zshift.x, zshift.y);
-    }
-}
-
-function change_zoom(shx, shy) {
-    var zoom_control = document.getElementById("zoom_ctrl");
-    var v = zoom_control.value;
-
-    prev_zm = zm;
-
-    if (zooms[v]) {
-        if (!zooms[v].is_updated) zooms[v].refresh();
-    } else {
-        zooms[v] = new tzoom(v);
-    }
-
-    if (zooms[v].is_updated) {
-        if (shx == undefined || shy == undefined) {
-            shx=0;
-            shy=0;
-        }
-        zm = zooms[v];
-        var px = (last.x+shx)*zm.im.width/prev_zm.im.width - shx;
-        var py = (last.y+shy)*zm.im.height/prev_zm.im.height - shy;
-        if (py < zm.im.height && py >= 0) {
-            zoom = zm.value;
-            tile = zm.tile;
-            ntiles = zm.ntiles;
-            update_url();
-            putImage(px, py);
-        } else {
-            zm = prev_zm;
-            zoom_control.value = zm.value;
-        }
-    }
-}
 
 
 function change_angle() {
 function change_angle() {
     var elvtn_control = document.getElementById('elvtn_ctrl');
     var elvtn_control = document.getElementById('elvtn_ctrl');
@@ -946,10 +630,11 @@ function insert_ref_point(el, x, y) {
     xhr.open("POST", "/api/v1/references/", true);
     xhr.open("POST", "/api/v1/references/", true);
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         xhr.setRequestHeader("X-CSRFToken", csrf_token);
         xhr.setRequestHeader("X-CSRFToken", csrf_token);
+    /* TODO: get correct x and y */
     xhr.send("reference_point=" + refpoint_url
     xhr.send("reference_point=" + refpoint_url
              + "&panorama=" + panorama_url
              + "&panorama=" + panorama_url
              + "&x=" + Math.floor(posx * image_width)
              + "&x=" + Math.floor(posx * image_width)
-                 + "&y=" + Math.floor((posy + 0.5) * image_height));
+             + "&y=" + Math.floor((posy + 0.5) * image_height));
 
 
     // update the course of the panorama boundaries
     // update the course of the panorama boundaries
     // (update cap_min/cap_max of the panorama object)
     // (update cap_min/cap_max of the panorama object)
@@ -974,27 +659,6 @@ function delete_ref_point(el) {
     xhr.send();
     xhr.send();
 }
 }
 
 
-function clean_canvas_events(e) {
-    canvas.removeEventListener('mousemove', stickImage, false);
-    canvas.removeEventListener('touchmove', stickImage, false);
-    document.getElementById('info').style.display = 'none';
-    speed.x = 0;
-    speed.y = 0;
-}
-
-canvas_set_size = function() {
-    canvas.style.border = border_width+"px solid black";
-    canvas.width = window.innerWidth-2*border_width;
-    canvas.height = window.innerHeight-2*border_width;
-    canvas_pos.x = canvas.offsetLeft+border_width;
-    canvas_pos.y = canvas.offsetTop+border_width;
-}
-
-canvas_resize = function() {
-    canvas_set_size();
-    putImage(last.x, last.y);
-}
-
 function paramIn(e) {
 function paramIn(e) {
     e = e || window.event;
     e = e || window.event;
     var relatedTarget = e.relatedTarget || e.fromElement;
     var relatedTarget = e.relatedTarget || e.fromElement;
@@ -1068,26 +732,14 @@ function update_url() {
 function load_pano() {
 function load_pano() {
     localisation = document.getElementById("locadraw");
     localisation = document.getElementById("locadraw");
     adding = document.getElementById("adding");
     adding = document.getElementById("adding");
-    canvas = document.getElementById("mon-canvas");
-    cntext = canvas.getContext("2d");
     canvas_set_size();
     canvas_set_size();
     canvas.addEventListener("click", check_links, false);
     canvas.addEventListener("click", check_links, false);
-    //canvas.addEventListener("oncontextmenu", manage_ref_points, false);
     canvas.oncontextmenu = manage_ref_points;
     canvas.oncontextmenu = manage_ref_points;
-    canvas.addEventListener("mouseout" , clean_canvas_events, false);
     show_links();
     show_links();
 
 
     var initial_orientation = get_orientation_from_url();
     var initial_orientation = get_orientation_from_url();
     var to_zoom = initial_orientation.zoom;
     var to_zoom = initial_orientation.zoom;
 
 
-    var max_zoom = zooms.length - 1;
-    zoom_control = document.getElementById("zoom_ctrl");
-    zoom_control.onchange = change_zoom;
-    zoom_control.max = max_zoom;
-    if (to_zoom > max_zoom) to_zoom = Math.floor(max_zoom/2);
-    zm = zooms[to_zoom];
-    zoom_control.value = to_zoom;
-    zm.refresh();
 
 
     zoom = zm.value;
     zoom = zm.value;
     tile = zm.tile;
     tile = zm.tile;

+ 88 - 0
panorama/static/panorama/js/panovue.js

@@ -0,0 +1,88 @@
+var { LMap, LTileLayer, LMarker } = Vue2Leaflet;
+
+/* Wrapping CRS for 360° panorama */
+/*
+SimpleWrapCRS = L.extend({}, L.CRS.Simple, {
+    wrapLng: [0, this.image_width],
+});
+*/
+
+new Vue({
+    el: '#app',
+    components: { LMap, LTileLayer, LMarker },
+    data: {
+        markers: [],
+
+        image_height: 0,
+        image_width: 0,
+        pano_id: null,
+        panoTileURL: '/{z}-{x}-{y}.jpg',
+        pano: null,                        /* Leaflet map */
+        panoTiles: null,                   /* Tiles of the panorama */
+        panoMinZoom: -8,
+        panoMaxZoom: 3,
+        panoZoom: 0,
+        panoCenter: [0, 0],
+        panoMaxBounds: null,
+        panoCRS: L.CRS.Simple,
+
+        panoOptions: {
+            zoomControl: true,
+        },
+
+        panoTilesURL: '/media/tiles/243/{z}-{x}-{y}.jpg',
+        panoTilesOpacity: 1.0,
+        panoTilesOptions: {
+            minZoom: -8,
+            maxZoom: 3,
+            maxNativeZoom: 0,
+            noWrap: true,
+            bounds: null,
+        }
+    },
+    mounted() {
+        this.image_width = 12972;
+        this.image_height = 3008;
+        this.panoZoom = -3;
+        this.panoCenter = [-this.image_height/2, this.image_width/2];
+        // Set bounds to avoid panning to infinity, but wide enough so that it's not too annoying
+        // TODO: change the bounds dynamically depending on the zoom level
+        this.panoMaxBounds = [[this.image_height, -0.3*this.image_width], [-2*this.image_height, 1.3*this.image_width]];
+        /* Avoid loading inexistant tiles (generating lots of 404) */
+        this.panoTilesOptions.bounds = [[0, 0], [-this.image_height, this.image_width]];
+        
+      //this.loadData();
+      //this.initPano();
+      //this.initMinimap();
+    },
+    methods: {
+      initPano() {
+
+          this.pano = L.map('pano', {
+              zoomControl: true,
+              crs: SimpleWrapCRS,
+              center: [-this.image_height/2, this.image_width/2],
+              // Set bounds to avoid panning to infinity, but wide enough so that it's not too annoying
+              // TODO: change the bounds dynamically depending on the zoom level
+              maxBounds: [[this.image_height, -0.3*this.image_width], [-2*this.image_height, 1.3*this.image_width]],
+              //maxBounds: [[this.image_height, Number.NEGATIVE_INFINITY], [-2*this.image_height, Number.POSITIVE_INFINITY]],
+              zoom: this.defaultZoomPano,
+              minZoom: this.minZoomPano,
+              maxZoom: this.maxZoomPano,
+          });
+          this.panoTiles = L.TileLayer(this.PanoTileURL, {
+          //this.panoTiles = L.TileLayer('/debug/tile/{z}/{x}/{y}.jpg', {
+              minZoom: this.minZoomPano,
+              maxZoom: this.maxZoomPano,
+              maxNativeZoom: 0,
+              opacity: 1.0,
+              noWrap: true,
+              //noWrap: false, // For 360° panorama, but does not work as expected: https://github.com/Leaflet/Leaflet/issues/6292
+              bounds: [[0, 0], [-this.image_height, this.image_width]], // Avoid loading inexistant tiles (generating lots of 404)
+          });
+          this.pano.addLayer(this.panoTiles);
+      },
+      initMinimap() {
+      },
+    },
+});

File diff suppressed because it is too large
+ 2 - 0
panorama/static/panorama/js/vue2-leaflet.min.js


File diff suppressed because it is too large
+ 1 - 0
panorama/static/panorama/js/vue2-leaflet.min.js.map


File diff suppressed because it is too large
+ 6 - 0
panorama/static/panorama/vue/v2.5.17/vue.min.js


File diff suppressed because it is too large
+ 6 - 0
panorama/static/panorama/vue/v2.5.17/vue.runtime.min.js


+ 10 - 10
panorama/templates/panorama/main.html

@@ -86,32 +86,29 @@
         var crosshairIcon = L.icon({
         var crosshairIcon = L.icon({
             iconUrl: '{% static "panorama/img/marker-blue.png" %}',
             iconUrl: '{% static "panorama/img/marker-blue.png" %}',
             iconSize:     [22, 35],
             iconSize:     [22, 35],
-            iconAnchor:   [11, 35]
+            iconAnchor:   [11, 35],
         });
         });
         var panoIcon = L.icon({
         var panoIcon = L.icon({
             iconUrl: '{% static "panorama/img/marker-red.png" %}',
             iconUrl: '{% static "panorama/img/marker-red.png" %}',
             iconSize: [22, 35],
             iconSize: [22, 35],
             iconAnchor: [11, 35],
             iconAnchor: [11, 35],
-            popupAnchor: [0,-50]
+            popupAnchor: [0, -25],
         });
         });
         var poiIcons = {
         var poiIcons = {
           subscriber: L.icon({
           subscriber: L.icon({
               iconUrl: '{% static "panorama/img/marker-circle-green.png" %}',
               iconUrl: '{% static "panorama/img/marker-circle-green.png" %}',
               iconSize: [20, 20],
               iconSize: [20, 20],
               iconAnchor: [10, 10],
               iconAnchor: [10, 10],
-              popupAnchor: [0,-20]
           }),
           }),
           waiting: L.icon({
           waiting: L.icon({
               iconUrl: '{% static "panorama/img/marker-circle-orange.png" %}',
               iconUrl: '{% static "panorama/img/marker-circle-orange.png" %}',
               iconSize: [20, 20],
               iconSize: [20, 20],
               iconAnchor: [10, 10],
               iconAnchor: [10, 10],
-              popupAnchor: [0,-20]
           }),
           }),
           other: L.icon({
           other: L.icon({
               iconUrl: '{% static "panorama/img/marker-circle-purple.png" %}',
               iconUrl: '{% static "panorama/img/marker-circle-purple.png" %}',
               iconSize: [20, 20],
               iconSize: [20, 20],
               iconAnchor: [10, 10],
               iconAnchor: [10, 10],
-              popupAnchor: [0,-20]
           }),
           }),
         };
         };
 
 
@@ -250,13 +247,16 @@
             // Add searching form
             // Add searching form
             SearchPlace();
             SearchPlace();
     
     
+            openPopup = function (e) { this.openPopup(); };
+            closePopup = function (e) { this.closePopup(); };
+
             // Create markers for panoramas
             // Create markers for panoramas
             {% for pano in panoramas %}
             {% for pano in panoramas %}
                 var marker = L.marker([{{ pano.latitude }}, {{ pano.longitude }}], {icon: panoIcon, riseOnHover: true});
                 var marker = L.marker([{{ pano.latitude }}, {{ pano.longitude }}], {icon: panoIcon, riseOnHover: true});
                 marker.on("click",function(){document.location.href="{% url 'panorama:view_pano' pano.id %}"});
                 marker.on("click",function(){document.location.href="{% url 'panorama:view_pano' pano.id %}"});
-                var popup = marker.bindPopup('{{ pano.name }}',{className : 'markerpopup', closeButton: false,});
-                popup.on('mouseover', marker.openPopup);
-                popup.on('mouseout', marker.closePopup);
+                var popup = marker.bindPopup('{{ pano.name }}',{className : 'markerpopup', closeButton: false});
+                marker.on('mouseover', openPopup);
+                marker.on('mouseout', closePopup);
                 markerClusters.addLayer( marker );
                 markerClusters.addLayer( marker );
                 allMarkers.push([{{ pano.latitude }}, {{ pano.longitude }}]);
                 allMarkers.push([{{ pano.latitude }}, {{ pano.longitude }}]);
             {% endfor %}
             {% endfor %}
@@ -268,8 +268,8 @@
             {% for poi in poi_list %}
             {% for poi in poi_list %}
                 var poiMarker = L.marker([{{ poi.latitude }}, {{ poi.longitude }}], {icon: poiIcons['{{ poi.kind }}'], riseOnHover: true});
                 var poiMarker = L.marker([{{ poi.latitude }}, {{ poi.longitude }}], {icon: poiIcons['{{ poi.kind }}'], riseOnHover: true});
                 var poiPopup = poiMarker.bindPopup('{{ poi.name }}', {className : 'markerpopup', closeButton: false});
                 var poiPopup = poiMarker.bindPopup('{{ poi.name }}', {className : 'markerpopup', closeButton: false});
-                poiPopup.on('mouseover', poiMarker.openPopup);
-                poiPopup.on('mouseout', poiMarker.closePopup);
+                poiMarker.on('mouseover', openPopup);
+                poiMarker.on('mouseout', closePopup);
                 pointsOfInterest.addLayer(poiMarker);
                 pointsOfInterest.addLayer(poiMarker);
             {% endfor %}
             {% endfor %}
             // Add a legend to the map
             // Add a legend to the map

+ 68 - 33
panorama/templates/panorama/view.html

@@ -37,15 +37,6 @@
     <script src="{% static "panorama/js/js.cookie.js" %}"></script>
     <script src="{% static "panorama/js/js.cookie.js" %}"></script>
     <script src="{% static "panorama/js/pano.js" %}"></script>
     <script src="{% static "panorama/js/pano.js" %}"></script>
     <script>
     <script>
-      {% for zoom_level, data in panorama.tiles_data.items %}
-      zooms[{{ zoom_level }}] = new tzoom({{ zoom_level }});
-      zooms[{{ zoom_level }}].ntiles.x = {{ data.ntiles_x }};
-      zooms[{{ zoom_level }}].ntiles.y = {{ data.ntiles_y }};
-      zooms[{{ zoom_level }}].tile.width = {{ data.tile_width }};
-      zooms[{{ zoom_level }}].tile.height = {{ data.tile_height }};
-      zooms[{{ zoom_level }}].last_tile.width = {{ data.last_tile_width }};
-      zooms[{{ zoom_level }}].last_tile.height = {{ data.last_tile_height }};
-      {% endfor %}
 
 
       {% for id, refpoint in panorama.refpoints_data %}
       {% for id, refpoint in panorama.refpoints_data %}
       point_list[{{ id }}] = new Array("{{ refpoint.name|escapejs }}", {{ refpoint.distance }}, "{{ refpoint.distance|distance|escapejs }}", {{ refpoint.cap }}, {{ refpoint.elevation }}, {{ refpoint.elevation_ground }}, "{{ refpoint.url }}", "/api/v1/refpoints/{{ refpoint.id }}/");
       point_list[{{ id }}] = new Array("{{ refpoint.name|escapejs }}", {{ refpoint.distance }}, "{{ refpoint.distance|distance|escapejs }}", {{ refpoint.cap }}, {{ refpoint.elevation }}, {{ refpoint.elevation_ground }}, "{{ refpoint.url }}", "/api/v1/refpoints/{{ refpoint.id }}/");
@@ -61,46 +52,89 @@
     <script type='text/javascript' src="{% static "panorama/js/jquery-3.0.0.min.js" %}"></script>
     <script type='text/javascript' src="{% static "panorama/js/jquery-3.0.0.min.js" %}"></script>
     <script type='text/javascript' src="{% static "panorama/js/leaflet.markercluster/1.3.0/leaflet.markercluster.js" %}"></script>
     <script type='text/javascript' src="{% static "panorama/js/leaflet.markercluster/1.3.0/leaflet.markercluster.js" %}"></script>
     <script>
     <script>
-      var markerClusters = L.markerClusterGroup({
-          spiderfyOnMaxZoom: false,
-          showCoverageOnHover: false,
-          maxClusterRadius: 20,
-          disableClusteringAtZoom: 19
-      });
-      var panoIcon = L.icon({
-          iconUrl: '{% static "panorama/img/marker-red.png" %}',
-          iconSize: [22, 35],
-          iconAnchor: [11, 35],
-          popupAnchor: [0,-50]
-      });
+      /* Used both on the mini-map and on the panorama view */
+      openPopup = function (e) { this.openPopup(); };
+      closePopup = function (e) { this.closePopup(); };
       var poiIcons = {
       var poiIcons = {
         subscriber: L.icon({
         subscriber: L.icon({
             iconUrl: '{% static "panorama/img/marker-circle-green.png" %}',
             iconUrl: '{% static "panorama/img/marker-circle-green.png" %}',
             iconSize: [20, 20],
             iconSize: [20, 20],
             iconAnchor: [10, 10],
             iconAnchor: [10, 10],
-            popupAnchor: [0,-20]
         }),
         }),
         waiting: L.icon({
         waiting: L.icon({
             iconUrl: '{% static "panorama/img/marker-circle-orange.png" %}',
             iconUrl: '{% static "panorama/img/marker-circle-orange.png" %}',
             iconSize: [20, 20],
             iconSize: [20, 20],
             iconAnchor: [10, 10],
             iconAnchor: [10, 10],
-            popupAnchor: [0,-20]
         }),
         }),
         other: L.icon({
         other: L.icon({
             iconUrl: '{% static "panorama/img/marker-circle-purple.png" %}',
             iconUrl: '{% static "panorama/img/marker-circle-purple.png" %}',
             iconSize: [20, 20],
             iconSize: [20, 20],
             iconAnchor: [10, 10],
             iconAnchor: [10, 10],
-            popupAnchor: [0,-20]
         }),
         }),
       };
       };
+    </script>
+    <script>
+      /* New leaflet-based panorama view */
+      var SimpleWrapCRS = L.extend({}, L.CRS.Simple, {
+          wrapLng: [0, image_width],
+      });
+
+      panoLeaflet = L.map('pano', {
+          zoomControl: true,
+          crs: SimpleWrapCRS,
+          center: [-image_height/2, image_width/2],
+          // Set bounds to avoid panning to infinity, but wide enough so that it's not too annoying
+          // TODO: change the bounds dynamically depending on the zoom level
+          maxBounds: [[image_height, -0.3*image_width], [-2*image_height, 1.3*image_width]],
+          //maxBounds: [[image_height, Number.NEGATIVE_INFINITY], [-2*image_height, Number.POSITIVE_INFINITY]],
+          zoom: -4,
+          minZoom: -8,
+          maxZoom: 3,
+      });
+      var tileLayer = new L.TileLayer(img_prefix + '/{z}-{x}-{y}.jpg', {
+      //var tileLayer = new L.TileLayer('/debug/tile/{z}/{x}/{y}.jpg', {
+          minZoom: -8,
+          maxZoom: 3,
+          maxNativeZoom: 0,
+          opacity: 1.0,
+          noWrap: true,
+          //noWrap: false, // For 360° panorama, but does not work as expected: https://github.com/Leaflet/Leaflet/issues/6292
+          bounds: [[0, 0], [-image_height, image_width]], // Avoid loading inexistant tiles (generating lots of 404)
+      });
+      panoLeaflet.addLayer(tileLayer);
+
+      var references = L.layerGroup();
+      {% for ref in panorama.references_data %}
+          var marker = L.marker([-{{ ref.y }}, {{ ref.x }}], {icon: poiIcons['{{ ref.kind }}'], riseOnHover: true});
+          var poiPopup = marker.bindPopup('{{ ref.name }}', {className : 'markerpopup', closeButton: false});
+          marker.on('mouseover', openPopup);
+          marker.on('mouseout', closePopup);
+          references.addLayer(marker);
+      {% endfor %}
+      panoLeaflet.addLayer(references);
+    </script>
+    <script>
+      /* Mini-map */
+      var markerClusters = L.markerClusterGroup({
+          spiderfyOnMaxZoom: false,
+          showCoverageOnHover: false,
+          maxClusterRadius: 20,
+          disableClusteringAtZoom: 19
+      });
+      var panoIcon = L.icon({
+          iconUrl: '{% static "panorama/img/marker-red.png" %}',
+          iconSize: [22, 35],
+          iconAnchor: [11, 35],
+          popupAnchor: [0, -25]
+      });
 
 
       {% for pano in panoramas %}
       {% for pano in panoramas %}
           {% if panorama.name != pano.name  %}
           {% if panorama.name != pano.name  %}
               var marker = L.marker([{{ pano.latitude }}, {{ pano.longitude }}], {icon: panoIcon, riseOnHover: true});
               var marker = L.marker([{{ pano.latitude }}, {{ pano.longitude }}], {icon: panoIcon, riseOnHover: true});
               marker.on("click",function(){document.location.href="{% url 'panorama:view_pano' pano.id %}"});
               marker.on("click",function(){document.location.href="{% url 'panorama:view_pano' pano.id %}"});
-              var popup = marker.bindPopup('{{ pano.name }}',{className : 'markerpopup', closeButton: false,});
-              popup.on('mouseover', marker.openPopup);
-              popup.on('mouseout', marker.closePopup);
+              var popup = marker.bindPopup('{{ pano.name }}',{className : 'markerpopup', closeButton: false});
+              marker.on('mouseover', openPopup);
+              marker.on('mouseout', closePopup);
               markerClusters.addLayer( marker );
               markerClusters.addLayer( marker );
           {% endif %}
           {% endif %}
       {% endfor %}
       {% endfor %}
@@ -109,14 +143,16 @@
       {% for poi in poi_list %}
       {% for poi in poi_list %}
           var marker = L.marker([{{ poi.latitude }}, {{ poi.longitude }}], {icon: poiIcons['{{ poi.kind }}'], riseOnHover: true});
           var marker = L.marker([{{ poi.latitude }}, {{ poi.longitude }}], {icon: poiIcons['{{ poi.kind }}'], riseOnHover: true});
           var poiPopup = marker.bindPopup('{{ poi.name }}', {className : 'markerpopup', closeButton: false});
           var poiPopup = marker.bindPopup('{{ poi.name }}', {className : 'markerpopup', closeButton: false});
-          poiPopup.on('mouseover', marker.openPopup);
-          poiPopup.on('mouseout', marker.closePopup);
+          marker.on('mouseover', openPopup);
+          marker.on('mouseout', closePopup);
           pointsOfInterest.addLayer(marker);
           pointsOfInterest.addLayer(marker);
       {% endfor %}
       {% endfor %}
+
+      load_map();
     </script>
     </script>
     <script>
     <script>
         // need to be after the initialization of the leaflet variables.
         // need to be after the initialization of the leaflet variables.
-        window.onload = load_pano
+        //window.onload = load_pano
     </script>
     </script>
 {% endlocalize %}
 {% endlocalize %}
 {% endblock js %}
 {% endblock js %}
@@ -185,9 +221,8 @@ style="padding-left:0px"
 
 
 
 
 {% block pano %}
 {% block pano %}
-    <canvas id="mon-canvas">
-      Ce message indique que ce navigateur est vétuste car il ne supporte pas <samp>canvas</samp> (IE6, IE7, IE8, ...)
-    </canvas>
+    <div id="pano">
+    </div>
     <p id="info"></p>
     <p id="info"></p>
     <p id="insert"><select id="sel_point" name="known_points">
     <p id="insert"><select id="sel_point" name="known_points">
         {% for id, refpoint in panorama.refpoints_data %}
         {% for id, refpoint in panorama.refpoints_data %}

+ 105 - 0
panorama/templates/panorama/vue.html

@@ -0,0 +1,105 @@
+{% extends "panorama/base.html" %}
+{% load staticfiles %}
+{% load i18n %}
+{% load l10n %}
+
+{% block title %}{{ panorama.name }}{% endblock title %}
+
+{% block css %}
+    <link rel="stylesheet" type="text/css" href="{% static "panorama/leaflet/v1.3.3/leaflet.css" %}">
+    <link rel="stylesheet" type="text/css" href="{% static "panorama/css/leaflet.markercluster/1.3.0/MarkerCluster.css" %}">
+    <link rel="stylesheet" type="text/css" href="{% static "panorama/css/leaflet.markercluster/1.3.0/MarkerCluster.Default.css" %}">
+    <link rel="stylesheet" type="text/css" href="{% static "panorama/css/markercluster.override.css" %}" />
+{% endblock css %}
+
+{% block js %}
+{% localize off %}
+    <script src="{% static "panorama/js/hide_n_showForm.js" %}"></script>
+    <script type='text/javascript' src="{% static "panorama/vue/v2.5.17/vue.min.js" %}"></script>
+    <script type='text/javascript' src="{% static "panorama/leaflet/v1.3.3/leaflet.js" %}"></script>
+    <script type='text/javascript' src="{% static "panorama/js/leaflet.markercluster/1.3.0/leaflet.markercluster.js" %}"></script>
+    <script type='text/javascript' src="{% static "panorama/js/vue2-leaflet.min.js" %}"></script>
+    <script type='text/javascript' src="{% static "panorama/js/panovue.js" %}"></script>
+    <script>
+      
+    </script>
+{% endlocalize %}
+{% endblock js %}
+
+{% block top-menu-title %}
+    <a class="navbar-brand" href="{% url 'panorama:main' %}"><i class="fa fa-fw fa-home"></i></a>
+    <a class="navbar-brand" href="">{{panorama.name}}</a>
+{% endblock %}
+
+{% block top-menu-pano-items %}
+{% localize off %}
+    <li class="dropdown">
+        <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-question-circle"></i>  {% trans "Parameters" %}<b class="caret"></b></a>
+        <ul class="dropdown-menu">
+            <li>
+                <div>
+                  <p>{% trans "latitude:" %} <em><span id="pos_lat">{{ panorama.latitude }}</span>°</em></p>
+                  <p>{% trans "longitude:" %} <em><span id="pos_lon">{{ panorama.longitude }}</span>°</em></p>
+                  <p>{% trans "ground altitude:" %} <em><span id="pos_ground_alt">{{ panorama.ground_altitude|floatformat:-2 }}</span> m</em></p>
+                  <p>{% trans "height above ground:" %} <em><span id="pos_height">{{ panorama.height_above_ground|floatformat:-2 }}</span> m</em></p>
+                  <p>{% trans "altitude:" %} <em><span id="pos_alt">{{ panorama.altitude|floatformat:-2 }}</span> m</em></p>
+                </div>
+            </li>
+        </ul>
+    </li>
+    <li class="dropdown">
+        <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-gears"></i>  {% trans "Controls" %}<b class="caret"></b></a>
+        <ul class="dropdown-menu">
+            <li>
+                  <label>{% trans "Zoom:" %} <input type="range" min="0" max="2" value="2" id="zoom_ctrl"/></label>
+                  <label>{% trans "Bearing:" %} <input type="number" min="0" max="360" step="10" value="0" autofocus="" id="angle_ctrl"/></label>
+                  <label>{% trans "Elevation:" %} <input type="number" min="-90" max="90" step="1" value="0" autofocus="" id="elvtn_ctrl"/></label>
+            </li>
+        </ul>
+    </li>
+    <li class="dropdown">
+        <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-search"></i>  {% trans "Locate" %}<b class="caret"></b></a>
+        <ul class="dropdown-menu">
+            <li>
+                  <label class="form_col" title="La latitude ϵ [-90°, 90°]. Ex: 12.55257">{% trans "Latitude:" %}
+                    <input  name="loca_latitude" type="number" min="-90" max="90"  id="loca_latitude"/></label>
+                  <label class="form_col" title="La longitude ϵ [-180°, 180°]. Ex: 144.14723">{% trans "Longitude:" %}
+                    <input name="loca_longitude" type="number" min="-180" max="180" id="loca_longitude"/></label>
+                  <label class="form_col" title="L'altitude positive Ex: 170">{% trans "Altitude:" %}
+                    <input  name="loca_altitude" type="number" min="-400" id="loca_altitude"/></label>
+                  <div class="loca_buttons">
+                    <input type="button" class="btn btn-info btn-sm" value="{% trans "Locate" %}" id="loca_button"/>
+                    <input type="button" class="btn btn-danger btn-sm" value="{% trans "Delete" %}" id="loca_erase"/>
+                  </div>
+            </li>
+        </ul>
+    </li>
+{% endlocalize %}
+{% endblock %}
+
+{% block sidebar %}
+{% endblock %}
+
+{% block wrapper-style %}
+style="padding-left:0px"
+{% endblock %}
+
+{% block content %}
+{% endblock content %}
+
+
+
+{% block pano %}
+    <div id="app" class="container">
+      <div id="pano">
+        <l-map ref="pano" :options="panoOptions" :crs="panoCRS" :center="panoCenter" :maxBounds="panoMaxBounds" :zoom="panoZoom" :minZoom="panoMinZoom" :maxZoom="panoMaxZoom">
+          <l-tile-layer :url="panoTilesURL" :options="panoTilesOptions" :opacity="panoTilesOpacity"></l-tile-layer>
+          <l-marker v-for="marker in markers" :lat-lng="marker.coord"></l-marker>
+        </l-map>
+      </div>
+    </div>
+      <div id="minimap"></div>
+      <div id="info"></div>
+      <div id="hideshowminimap"><a href="#" title="Hide/show map"><i id="expandmap" class="fa fa-compress" aria-hidden="true"></i></a></div>
+{% endblock pano %}
+

+ 1 - 1
panorama/views.py

@@ -44,7 +44,7 @@ class PanoramaUpload(CelutzLoginMixin, CreateView):
 @method_decorator(ensure_csrf_cookie, name='dispatch')
 @method_decorator(ensure_csrf_cookie, name='dispatch')
 class PanoramaView(CelutzLoginMixin, DetailView):
 class PanoramaView(CelutzLoginMixin, DetailView):
     model = Panorama
     model = Panorama
-    template_name = "panorama/view.html"
+    template_name = "panorama/vue.html"
     context_object_name = "panorama"
     context_object_name = "panorama"
 
 
     def get_context_data(self, **kwargs):
     def get_context_data(self, **kwargs):