7cbb6754719058f3c7011102bd937aca2a31b752
[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         self._original_loaded = true;
43         self.spinner.stop();
44         var cb = self.original_loaded;
45         self.original_loaded = undefined;
46         if (cb)
47           cb()
48       });
49       
50       if (self.options.max <= 0) {
51         self.options.max = original.naturalWidth
52           * 100 / self.initial_size[0];
53       }
54
55       self.element.css({
56         'margin': 0,
57       });
58
59       self.element.offset(self.initial_position);
60       self.element.draggable({containment:"parent"});
61
62       if (self.options.plus_button)
63         self.options.plus_button.click(
64           function(ev) { self.zoom(1); });
65       if (self.options.minus_button)
66         self.options.minus_button.click(
67           function(ev) { self.zoom(-1); });
68
69       self.options.areas_links.hover(function() {
70         $this = $(this);
71         var coords = $this.data("coords");
72         this._picture_mark = self.createMark({
73           label: $this.text(),
74           coords: coords,
75         });
76       }, function() {
77         $(this._picture_mark).remove();
78         this._picture_mark = undefined;
79       });
80       return self;
81     },
82
83     natural_size: function() { 
84       var img = this.element.find('img').get(0);
85       return [ img.naturalWidth, img.naturalHeight ] 
86     },
87
88     currentZoom: function() { return this._zoom; },
89
90     initOriginal: function() {
91       var self = this;
92       function subst_original() {
93         self.element.find("img.initial").remove();
94         self.element.find("img.loading").removeClass("loading");
95         self._original = true;
96       }
97       if (!this._original) {
98         if (this._original_loaded) {
99           return subst_original();
100         } else {
101           self.original_loaded = subst_original;
102           self.spinner.start();
103         }
104       }
105
106     },
107
108     zoom: function(steps) {
109       this.initOriginal();
110       var t = this._zoom + steps;
111       return this.zoomTo(t);
112     },
113
114     zoomForStep: function(step) {
115       // 0 => initial
116       // max_step-1 => max %
117       return 100 + (this.options.max - 100) / this.options.steps * step
118     },
119
120     zoomTo: function(level) {
121       if (level < 0 || level > this.options.steps)
122         return;
123       var ratio = this.zoomForStep(level) / 100;
124       var new_width  = ratio * this.initial_size[0];
125       var new_height = ratio * this.initial_size[1];
126       var target = {
127         'width': new_width,
128         'left': Math.max(0, 
129                          this.initial_position.left 
130                          - (new_width - this.initial_size[0])/2),
131         'top': Math.max(0, 
132                         this.initial_position.top 
133                         - (new_height - this.initial_size[1])/2),
134       };
135
136       this._zoom = level;
137       this.element.animate(target, 200); // default duration=400
138     },
139
140     allowedPosition: function(off) {
141       var x = undefined, fix_x = undefined;
142       var y = undefined, fix_y = undefined;
143       var w = this.element.width();
144       var h = this.element.height();
145       var cw = $(window).width();
146       var ch = $(window).height();
147       var off = off || this.element.offset();
148
149       if (w <= cw) {
150         var x = off.left;
151         if (x < 0) 
152           fix_x = 0;
153         if (x + w > cw)
154           fix_x = cw - w;
155       } else {
156         if (x > 0)
157           fix_x = 0;
158         if (x + w < cw)
159           fix_x = cw - w;
160       }
161
162       if (h <= ch) {
163         var y = off.top;
164         if (y < 0)
165           fix_y = 0;
166         if (y + h > ch)
167           fix_y = ch - h;
168       } else {
169         if (y > 0)
170           fix_y = 0;
171         if (y + h < ch)
172           fix_y = ch - h;
173       }
174       if (fix_x !== undefined || fix_y !== undefined)
175         return { top: fix_y, left: fix_x };
176       return undefined;
177
178     },
179
180     // mark
181     // {
182     //  label: "...",
183     //  coords: [x, y, w, h]
184     // }
185     createMark: function(mark) {
186       var $mark = $('<div class="mark"><div class="label">' + 
187                     mark.label + '</div></div>');
188       var ratio = this.zoomForStep(this.currentZoom()) *
189         this.initial_size[0] / (100 * this.natural_size()[0]);
190       var scale = function (v) { 
191         return v * ratio; 
192       }
193       if (mark.coords[1][0] < 0 || mark.coords[1][1] < 0) { // whole
194         var s = self.natural_size();
195         if (mark.coords[1][0] < 0) mark.coords[1][0] = s[0];
196         if (mark.coords[1][1] < 0) mark.coords[1][1] = s[1];
197       }
198
199       var coords = [[scale(mark.coords[0][0]), scale(mark.coords[0][1])],
200                     [scale(mark.coords[1][0]), scale(mark.coords[1][1])]];
201       this.element.append($mark);
202       $mark.width(coords[1][0] - coords[0][0]);
203       $mark.height(coords[1][1] - coords[0][1]);
204       $mark.css({left: coords[0][0], top: coords[0][1]});
205       return $mark.get(0);
206     },
207   });
208 }(jQuery));
209
210
211 $(document).ready(function(){
212   $(".picture-wrap").pictureviewer({
213     plus_button: $(".toolbar .button.plus"),
214     minus_button: $(".toolbar .button.minus"),
215     areas_links: $("#picture-objects a, #picture-themes a"),
216   });
217
218   $.highlightFade.defaults.speed = 3000;
219
220   $('.toolbar a.dropdown').each(function() {
221     $t = $(this);
222     $($t.attr('href')).hide().insertAfter(this);
223   });
224
225   $('.toolbar a.dropdown').toggle(function() {
226     $(this).addClass('selected');
227     $($(this).attr('href')).slideDown('fast');
228   }, function() {
229     $(this).removeClass('selected');
230     $($(this).attr('href')).slideUp('fast');
231   });
232
233
234 });
235