scale initial mark with the image
[wolnelektury.git] / apps / wolnelektury_core / static / js / picture.js
1
2 (function($) {
3   $.widget('wl.pictureviewer', {
4     
5     options: {
6       step: 20, // step in % of initial image
7       plus_button: undefined,
8       minus_button: undefined,
9     },
10     ORIGINAL_LOADING: 0, 
11     ORIGINAL_AVAILABLE: 1, 
12     ORIGINAL_SHOWN: 2,
13
14     _create: function() {
15       var self = this;
16       self.initial_size = [ 
17         self.element.data('width'),
18         self.element.data('height') 
19       ];
20       self.original_size = [
21         self.element.data('original-width'),
22         self.element.data('original-height')
23       ];
24       self._zoom = 0;
25       self._ratio = 1.0;
26
27       self.original = self.element.find('img.original').eq(0);
28       
29       self._original_avaialble = self.ORIGINAL_LOADING;
30       function original_loaded() {
31         self._original_avaialble = self.ORIGINAL_AVAILABLE;
32         self.options.plus_button.removeClass('inactive');
33         self.options.minus_button.removeClass('inactive');
34         console.log("Original image available, sizes initial: " + self.initial_size + ", original: " + self.original_size);
35       };
36       self.original.load(original_loaded);
37
38       self.element.width(self.initial_size[0]);
39       self.element.height(self.initial_size[1]);
40
41       if (self.options.plus_button)
42         self.options.plus_button.click(
43           function(ev) { self.zoom(1); });
44       if (self.options.minus_button)
45         self.options.minus_button.click(
46           function(ev) { self.zoom(-1); });
47
48       self._initial_mark = null;
49       function clean_initial_mark() {
50         if (self._initial_mark) {
51           self._initial_mark.remove();
52           self._initial_mark = null;
53         }
54       }
55       var initial_hash = window.location.hash;
56       if (initial_hash) {
57         var mk = null;
58         if (initial_hash.startsWith('#object-')) {
59           $("[href=#picture-objects]").trigger('click');
60         } else if (initial_hash.startsWith('#theme-')) {
61           $("[href=#picutre-themes]").trigger('click');
62         }
63         mk = $("[href=" + initial_hash + "]").eq(0);
64         self._initial_mark = self.createMark({
65           label: mk.text(),
66           coords: mk.data('coords')
67         });
68       }      
69
70
71       self.options.areas_links.hover(function() {
72         clean_initial_mark();
73         $this = $(this);
74         var coords = $this.data("coords");
75         this._picture_mark = self.createMark({
76 //        label: $this.text(),
77           coords: coords,
78         });
79       }, function() {
80         $(this._picture_mark).remove();
81         this._picture_mark = undefined;
82       }).click(function(ev) {
83         ev.preventDefault();
84         var $mark = self.element.find('.mark').eq(0);
85         var markPos = $mark.offset();
86         markPos = [markPos.left, markPos.top];
87         var markSize = [ $mark.width(), $mark.height() ]
88         var wSize = [ window.innerWidth, window.innerHeight ];
89         window.scrollTo(
90           markPos[0] + markSize[0]/2 - wSize[0]/2,
91           markPos[1] + markSize[1]/2 - wSize[1]/2       
92         );
93         
94       });
95
96       
97
98       return self;
99     },
100
101     currentSize: function() {
102       return [this.element.width(), this.element.height() ];
103     },
104
105     currentZoom: function() { return this._zoom; },
106
107     initOriginal: function() {
108       if (this._original_avaialble > this.ORIGINAL_LOADING && 
109           this._original_avaialble < this.ORIGINAL_SHOWN) {
110         this.element.css({'background-image': 'url('+ this.original.attr('src')+')', 'background-size':  this.initial_size[0]+'px'});
111         this._original_avaialble = this.ORIGINAL_SHOWN;
112       };
113     },
114
115     zoom: function(steps) {
116       this.initOriginal();
117       var t = this._zoom + steps;
118       return this.zoomTo(t);
119     },
120
121     zoomForStep: function(step) {
122       // 0 => initial
123       // max_step-1 => max %
124       if (step < 0) step = 0;
125       var zoomperc = 100 + step * this.options.step;
126       if (zoomperc * this.initial_size[0] > this.original_size[0] * 100) {
127         zoomperc = this.original_size[0] * 100 / this.initial_size[0];
128       };
129       return zoomperc;
130     },
131
132     zoomTo: function(level) {
133       var ratio = this.zoomForStep(level) / 100;
134       var new_width  = ratio * this.initial_size[0];
135       var new_height = ratio * this.initial_size[1];
136       var cs = this.currentSize();
137       if (new_width == cs[0]) 
138         return;
139
140       var target = {
141         'width': new_width + 'px',
142         'height': new_height + 'px',
143         'background-size': new_width + 'px',
144       };
145
146       this._zoom = level;
147       this._ratio = ratio;
148
149       this.element.css(target);
150       if (this._initial_mark) {
151         this._initial_mark = this.redrawMark(this._initial_mark);
152       }
153
154     },
155
156     allowedPosition: function(off) {
157       var x = undefined, fix_x = undefined;
158       var y = undefined, fix_y = undefined;
159       var w = this.element.width();
160       var h = this.element.height();
161       var cw = $(window).width();
162       var ch = $(window).height();
163       var off = off || this.element.offset();
164
165       if (w <= cw) {
166         var x = off.left;
167         if (x < 0) 
168           fix_x = 0;
169         if (x + w > cw)
170           fix_x = cw - w;
171       } else {
172         if (x > 0)
173           fix_x = 0;
174         if (x + w < cw)
175           fix_x = cw - w;
176       }
177
178       if (h <= ch) {
179         var y = off.top;
180         if (y < 0)
181           fix_y = 0;
182         if (y + h > ch)
183           fix_y = ch - h;
184       } else {
185         if (y > 0)
186           fix_y = 0;
187         if (y + h < ch)
188           fix_y = ch - h;
189       }
190       if (fix_x !== undefined || fix_y !== undefined)
191         return { top: fix_y, left: fix_x };
192       return undefined;
193
194     },
195     redrawMark: function(mark) {
196       var $mark = $(mark);
197       var $newmark = this.createMark($mark.data('mark'));
198       $mark.remove();
199       return $newmark;
200     },
201     // mark
202     // {
203     //  label: "...",
204     //  coords: [x, y, w, h]
205     // }
206     createMark: function(mark) {
207       if (mark.label === undefined)
208         mark.label = '';
209       var $mark = $('<div class="mark"><div class="label">' + 
210                     mark.label + '</div></div>');
211       var cs = this.currentSize()
212       var ratio = cs[0] / this.original_size[0];
213       var scale = function (v) { 
214         return v * ratio; 
215       }
216       if (mark.coords[1][0] < 0 || mark.coords[1][1] < 0) { // whole
217         var s = this.original_size;
218         if (mark.coords[1][0] < 0) mark.coords[1][0] = s[0];
219         if (mark.coords[1][1] < 0) mark.coords[1][1] = s[1];
220       }
221
222       var coords = [[scale(mark.coords[0][0]), scale(mark.coords[0][1])],
223                     [scale(mark.coords[1][0]), scale(mark.coords[1][1])]];
224       this.element.append($mark);
225       $mark.width(coords[1][0] - coords[0][0]);
226       $mark.height(coords[1][1] - coords[0][1]);
227       $mark.css({left: coords[0][0], top: coords[0][1]});
228
229       $mark.data('mark', mark);
230       return $mark.get(0);
231     },
232   });
233 }(jQuery));
234
235
236 $(document).ready(function() {
237   $.highlightFade.defaults.speed = 3000;
238
239   $('.toolbar a.dropdown').each(function() {
240     $t = $(this);
241     $($t.attr('href')).hide().insertAfter(this);
242   });
243
244   function closeDD() {
245     $(this).removeClass('selected');
246     $($(this).attr('href')).slideUp('fast');
247     
248   }
249   $('.toolbar a.dropdown').click(function(ev) {
250     $("#sponsors:not(:hidden)").fadeOut();
251     ev.preventDefault();
252     if ($(this).hasClass('selected')) {
253       closeDD.call(this);
254     } else {
255       $(this).addClass('selected');
256       $($(this).attr('href')).slideDown('fast');
257       $(this).parent().siblings(".button:has(.dropdown)").children(".dropdown").each(closeDD);
258     }
259   });
260
261   $(".picture-wrap").pictureviewer({
262     plus_button: $(".toolbar .button.plus"),
263     minus_button: $(".toolbar .button.minus"),
264     areas_links: $("#picture-objects a, #picture-themes a"),
265   });
266
267 });
268