So many things get better/are improved, but only things that are to be done or broken...
[wolnelektury.git] / apps / wolnelektury_core / static / js / picture.js
1
2 (function($) {
3     $.widget('wl.pictureviewer', {
4
5         options: {
6             steps: 6, // steps of zoom
7             max: -1, // max zoom in percent
8             plus_button: undefined,
9             minus_button: undefined,
10             height: 500, // height to scale to initially
11         },
12
13
14         _create: function() {
15             var self = this;
16             /* Calibrate */
17             self._zoom = 0;
18
19             // the initial thumbnailed picture
20
21
22             var img = self.element.find('img.initial').get(0);
23
24             self.initial_size = [ 
25                 img.naturalWidth,
26                 img.naturalHeight
27             ];
28
29             self.element.width(self.initial_size[0]);
30             self.element.height(self.initial_size[1]);
31             
32             self.initial_position = self.element.offset();
33
34             var original = self.element.find('img.original').get(0);
35             self._original = false;
36             self.original_loeaded = undefined; // callback
37             self._original_loaded = false;
38
39             self.spinner = $("#spinner").progressSpin();
40
41             $(original).load(function() {
42                 console.log("loaded original");
43                 self._original_loaded = true;
44                 self.spinner.stop();
45                 var cb = self.original_loaded;
46                 self.original_loaded = undefined;
47                 if (cb)
48                     cb()
49             });
50             
51             if (self.options.max <= 0) {
52                 self.options.max = original.naturalWidth
53                     * 100 / self.initial_size[0];
54             }
55
56             self.element.css({
57                 'margin': 0,
58             });
59
60             self.element.offset(self.initial_position);
61             //      self.element.draggable({containment:"parent"});
62
63             if (self.options.plus_button)
64                 self.options.plus_button.click(
65                     function(ev) { self.zoom(1); });
66             if (self.options.minus_button)
67                 self.options.minus_button.click(
68                     function(ev) { self.zoom(-1); });
69
70             self.options.areas_links.hover(function() {
71                 $this = $(this);
72                 var coords = $this.data("coords");
73                 this._picture_mark = self.createMark({
74                     label: $this.text(),
75                     coords: coords,
76                 });
77             }, function() {
78                 $(this._picture_mark).remove();
79                 this._picture_mark = undefined;
80             });
81             return self;
82         },
83
84         natural_size: function() {
85             var img = this.element.find('img.original').get(0);
86             return [ img.naturalWidth, img.naturalHeight ] 
87         },
88
89         currentZoom: function() { return this._zoom; },
90
91         initOriginal: function() {
92             var self = this;
93             function subst_original() {
94                 self.element.find("img.initial").remove();
95                 self.element.find("img.loading").removeClass("loading");
96                 self._original = true;
97             }
98             if (!this._original) {
99                 if (this._original_loaded) {
100                     return subst_original();
101                 } else {
102                     self.original_loaded = subst_original;
103                     self.spinner.start();
104                 }
105             }
106
107         },
108
109         zoom: function(steps) {
110             this.initOriginal();
111             var t = this._zoom + steps;
112             return this.zoomTo(t);
113         },
114
115         zoomForStep: function(step) {
116             // 0 => initial
117             // max_step-1 => max %
118             return 100 + (this.options.max - 100) / this.options.steps * step
119         },
120
121         zoomTo: function(level) {
122             if (level < 0 || level > this.options.steps)
123                 return;
124             var ratio = this.zoomForStep(level) / 100;
125             var new_width  = ratio * this.initial_size[0];
126             var new_height = ratio * this.initial_size[1];
127             var target = {
128                 'width': new_width,
129                 'left': Math.max(0, 
130                                  this.initial_position.left 
131                                  - (new_width - this.initial_size[0])/2),
132                 'top': Math.max(0, 
133                                 this.initial_position.top 
134                                 - (new_height - this.initial_size[1])/2),
135             };
136
137             this._zoom = level;
138
139             this.element.css(target);
140            
141
142 //          this.element.animate(target, 1200); // default duration=400
143         },
144
145         allowedPosition: function(off) {
146             var x = undefined, fix_x = undefined;
147             var y = undefined, fix_y = undefined;
148             var w = this.element.width();
149             var h = this.element.height();
150             var cw = $(window).width();
151             var ch = $(window).height();
152             var off = off || this.element.offset();
153
154             if (w <= cw) {
155                 var x = off.left;
156                 if (x < 0) 
157                     fix_x = 0;
158                 if (x + w > cw)
159                     fix_x = cw - w;
160             } else {
161                 if (x > 0)
162                     fix_x = 0;
163                 if (x + w < cw)
164                     fix_x = cw - w;
165             }
166
167             if (h <= ch) {
168                 var y = off.top;
169                 if (y < 0)
170                     fix_y = 0;
171                 if (y + h > ch)
172                     fix_y = ch - h;
173             } else {
174                 if (y > 0)
175                     fix_y = 0;
176                 if (y + h < ch)
177                     fix_y = ch - h;
178             }
179             if (fix_x !== undefined || fix_y !== undefined)
180                 return { top: fix_y, left: fix_x };
181             return undefined;
182
183         },
184
185         // mark
186         // {
187         //  label: "...",
188         //  coords: [x, y, w, h]
189         // }
190         createMark: function(mark) {
191             var $mark = $('<div class="mark"><div class="label">' + 
192                           mark.label + '</div></div>');
193             var ratio = this.zoomForStep(this.currentZoom()) *
194                 this.initial_size[0] / (100 * this.natural_size()[0]);
195             var scale = function (v) { 
196                 return v * ratio; 
197             }
198             if (mark.coords[1][0] < 0 || mark.coords[1][1] < 0) { // whole
199                 var s = self.natural_size();
200                 if (mark.coords[1][0] < 0) mark.coords[1][0] = s[0];
201                 if (mark.coords[1][1] < 0) mark.coords[1][1] = s[1];
202             }
203
204             var coords = [[scale(mark.coords[0][0]), scale(mark.coords[0][1])],
205                           [scale(mark.coords[1][0]), scale(mark.coords[1][1])]];
206             this.element.append($mark);
207             $mark.width(coords[1][0] - coords[0][0]);
208             $mark.height(coords[1][1] - coords[0][1]);
209             $mark.css({left: coords[0][0], top: coords[0][1]});
210             return $mark.get(0);
211         },
212     });
213 }(jQuery));
214
215
216 $(document).ready(function(){
217     $(".picture-wrap").pictureviewer({
218         plus_button: $(".toolbar .button.plus"),
219         minus_button: $(".toolbar .button.minus"),
220         areas_links: $("#picture-objects a, #picture-themes a"),
221     });
222
223     $.highlightFade.defaults.speed = 3000;
224
225     $('.toolbar a.dropdown').each(function() {
226         $t = $(this);
227         $($t.attr('href')).hide().insertAfter(this);
228     });
229
230     function closeDD() {
231         $(this).removeClass('selected');
232         $($(this).attr('href')).slideUp('fast');
233         
234     }
235     $('.toolbar a.dropdown').click(function() {
236         if ($(this).hasClass('selected')) {
237             closeDD.call(this);
238         } else {
239             $(this).addClass('selected');
240             $($(this).attr('href')).slideDown('fast');
241             $(this).parent().siblings(".button:has(.dropdown)").children(".dropdown").each(closeDD);
242         }
243     });
244
245
246 });
247