comparison client/digitallibrary/jquery/ui/jquery.digilib.SLIDER.js @ 756:ccf67eaf97ee jquery

added jQuery ui and svg javascripts
author hertzhaft
date Sun, 06 Feb 2011 22:17:41 +0100
parents
children
comparison
equal deleted inserted replaced
755:4c0cc97a6399 756:ccf67eaf97ee
1 /* Copyright (c) 2011 Martin Raspe, Robert Casties
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU Lesser General Public License as published by
5 the Free Software Foundation, either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 Authors:
17 Martin Raspe, Robert Casties, 11.1.2011
18 */
19
20 /**
21 * digilib jQuery plugin
22 **/
23
24
25 /* jslint browser: true, debug: true, forin: true
26 */
27
28 // fallback for console.log calls
29 if (typeof(console) === 'undefined') {
30 var console = {
31 log : function(){},
32 debug : function(){},
33 error : function(){}
34 };
35 var customConsole = true;
36 }
37
38 (function($) {
39 var buttons = {
40 reference : {
41 onclick : "reference",
42 tooltip : "get a reference URL",
43 img : "reference.png"
44 },
45 zoomin : {
46 onclick : ["zoomBy", 1.4],
47 tooltip : "zoom in",
48 img : "zoom-in.png"
49 },
50 zoomout : {
51 onclick : ["zoomBy", 0.7],
52 tooltip : "zoom out",
53 img : "zoom-out.png"
54 },
55 zoomarea : {
56 onclick : "zoomArea",
57 tooltip : "zoom area",
58 img : "zoom-area.png"
59 },
60 zoomfull : {
61 onclick : "zoomFull",
62 tooltip : "view the whole image",
63 img : "zoom-full.png"
64 },
65 pagewidth : {
66 onclick : ["zoomFull", "width"],
67 tooltip : "page width",
68 img : "pagewidth.png"
69 },
70 back : {
71 onclick : ["gotoPage", "-1"],
72 tooltip : "goto previous image",
73 img : "back.png"
74 },
75 fwd : {
76 onclick : ["gotoPage", "+1"],
77 tooltip : "goto next image",
78 img : "fwd.png"
79 },
80 page : {
81 onclick : "gotoPage",
82 tooltip : "goto image number",
83 img : "page.png"
84 },
85 bird : {
86 onclick : "showBirdDiv",
87 tooltip : "show bird's eye view",
88 img : "birds-eye.png"
89 },
90 help : {
91 onclick : "showAboutDiv",
92 tooltip : "about Digilib",
93 img : "help.png"
94 },
95 reset : {
96 onclick : "reset",
97 tooltip : "reset image",
98 img : "reset.png"
99 },
100 mark : {
101 onclick : "setMark",
102 tooltip : "set a mark",
103 img : "mark.png"
104 },
105 delmark : {
106 onclick : "removeMark",
107 tooltip : "delete the last mark",
108 img : "delmark.png"
109 },
110 hmir : {
111 onclick : ["mirror", "h"],
112 tooltip : "mirror horizontally",
113 img : "mirror-horizontal.png"
114 },
115 vmir : {
116 onclick : ["mirror", "v"],
117 tooltip : "mirror vertically",
118 img : "mirror-vertical.png"
119 },
120 rot : {
121 onclick : "rotate",
122 tooltip : "rotate image",
123 img : "rotate.png"
124 },
125 brgt : {
126 onclick : "brightness",
127 tooltip : "set brightness",
128 img : "brightness.png"
129 },
130 cont : {
131 onclick : "contrast",
132 tooltip : "set contrast",
133 img : "contrast.png"
134 },
135 rgb : {
136 onclick : "javascript:setParamWin('rgb', '...')",
137 tooltip : "set rgb values",
138 img : "rgb.png"
139 },
140 quality : {
141 onclick : "setQuality",
142 tooltip : "set image quality",
143 img : "quality.png"
144 },
145 size : {
146 onclick : "javascript:toggleSizeMenu()",
147 tooltip : "set page size",
148 img : "size.png"
149 },
150 calibrationx : {
151 onclick : "javascript:calibrate('x')",
152 tooltip : "calibrate screen x-ratio",
153 img : "calibration-x.png"
154 },
155 scale : {
156 onclick : "javascript:toggleScaleMenu()",
157 tooltip : "change image scale",
158 img : "original-size.png"
159 },
160 toggleoptions : {
161 onclick : "moreButtons",
162 tooltip : "more options",
163 img : "options.png"
164 },
165 moreoptions : {
166 onclick : ["moreButtons", "+1"],
167 tooltip : "more options",
168 img : "options.png"
169 },
170 lessoptions : {
171 onclick : ["moreButtons", "-1"],
172 tooltip : "less options",
173 img : "options.png"
174 },
175 SEP : {
176 img : "sep.png"
177 }
178 };
179
180 var defaults = {
181 // version of this script
182 'version' : 'jquery.digilib.js 0.9',
183 // logo url
184 'logoUrl' : '../img/digilib-logo-text1.png',
185 // homepage url (behind logo)
186 'homeUrl' : 'http://digilib.berlios.de',
187 // base URL to digilib viewer (for reference URLs)
188 'digilibBaseUrl' : null,
189 // base URL to Scaler servlet
190 'scalerBaseUrl' : null,
191 // list of Scaler parameters
192 'scalerParamNames' : ['fn','pn','dw','dh','ww','wh','wx','wy','ws','mo',
193 'rot','cont','brgt','rgbm','rgba','ddpi','ddpix','ddpiy'],
194 // Scaler parameter defaults
195 'pn' : 1,
196 'ww' : 1.0,
197 'wh' : 1.0,
198 'wx' : 0.0,
199 'wy' : 0.0,
200 'ws' : 1.0,
201 'mo' : '',
202 'rot' : 0,
203 'cont' : 0,
204 'brgt' : 0,
205 'rgbm' : '0/0/0',
206 'rgba' : '0/0/0',
207 'ddpi' : null,
208 'ddpix' : null,
209 'ddpiy' : null,
210 // list of digilib parameters
211 'digilibParamNames' : ['fn','pn','ww','wh','wx','wy','ws','mo','rot','cont','brgt','rgbm','rgba','mk','clop'],
212 // digilib parameter defaults
213 'mk' : '',
214 'clop' : '',
215 // mode of operation:
216 // fullscreen = take parameters from page URL, keep state in page URL
217 // embedded = take parameters from Javascript options, keep state inside object
218 'interactionMode' : 'fullscreen',
219 // buttons
220 'buttons' : buttons,
221 // defaults for digilib buttons
222 'buttonSettings' : {
223 'fullscreen' : {
224 // path to button images (must end with a slash)
225 'imagePath' : 'img/fullscreen/',
226 'standardSet' : ["reference","zoomin","zoomout","zoomarea","zoomfull","pagewidth","back","fwd","page","bird","help","reset","toggleoptions"],
227 'specialSet' : ["mark","delmark","hmir","vmir","rot","brgt","cont","rgb","quality","size","calibrationx","scale","toggleoptions"],
228 'buttonSets' : ['standardSet', 'specialSet']
229 },
230 'embedded' : {
231 'imagePath' : 'img/embedded/16/',
232 'standardSet' : ["reference","zoomin","zoomout","zoomarea","zoomfull","bird","help","reset","toggleoptions"],
233 'specialSet' : ["mark","delmark","hmir","vmir","rot","brgt","cont","rgb","quality","toggleoptions"],
234 'buttonSets' : ['standardSet', 'specialSet']
235 }
236 },
237 // number of visible button groups
238 'visibleButtonSets' : 1,
239 // is birdView shown?
240 'isBirdDivVisible' : false,
241 // dimensions of bird's eye div
242 'birdDivWidth' : 200,
243 'birdDivHeight' : 200,
244 // parameters used by bird's eye div
245 'birdDivParams' : ['fn','pn','dw','dh'],
246 // style of the zoom area indicator in the bird's eye div
247 'birdIndicatorStyle' : {'border' : '2px solid #ff0000' },
248 // style of zoom area "rubber band"
249 'zoomrectStyle' : {'border' : '2px solid #ff0000' },
250 // is the "about" window shown?
251 'isAboutDivVisible' : false,
252 // maximum width of background image for drag-scroll
253 'maxBgSize' : 10000
254
255 };
256
257 // affine geometry classes
258 var geom = dlGeometry();
259
260 var FULL_AREA = geom.rectangle(0, 0, 1, 1);
261
262 var actions = {
263 // init: digilib initialization
264 init : function(options) {
265 // settings for this digilib instance are merged from defaults and options
266 var settings = $.extend({}, defaults, options);
267 var isFullscreen = settings.interactionMode === 'fullscreen';
268 var queryParams = {};
269 if (isFullscreen) {
270 queryParams = parseQueryParams();
271 // check scalerBaseUrl
272 if (settings.scalerBaseUrl == null) {
273 // try the host this came from
274 var h = window.location.host;
275 if (window.location.host) {
276 var url = window.location.href;
277 // assume the page lives in [webapp]/jquery/
278 var pos = url.indexOf('jquery/');
279 if (pos > 0) {
280 settings.scalerBaseUrl = url.substring(0, pos) + 'servlet/Scaler';
281 }
282 }
283 }
284 }
285 return this.each(function() {
286 var $elem = $(this);
287 var data = $elem.data('digilib');
288 var params, elemSettings;
289 // if the plugin hasn't been initialized yet
290 if (!data) {
291 // merge query parameters
292 if (isFullscreen) {
293 params = queryParams;
294 } else {
295 params = parseImgParams($elem);
296 if (jQuery.cookie) {
297 // retrieve params from cookie
298 var ck = "digilib-embed:fn:" + escape(params.fn) + ":pn:" + (params.pn || '1');
299 var cs = jQuery.cookie(ck);
300 console.debug("get cookie=", ck, " value=", cs);
301 if (cs) {
302 var cp = parseQueryString(cs);
303 // ignore fn and pn from cookie TODO: should we keep pn?
304 delete cp.fn;
305 delete cp.pn;
306 jQuery.extend(params, cp);
307 }
308 }
309 }
310 // store $(this) element in the settings
311 elemSettings = jQuery.extend({}, settings, params);
312 data = {
313 $elem : $elem,
314 settings : elemSettings,
315 queryParams : params
316 };
317 // store in data element
318 $elem.data('digilib', data);
319 }
320 unpackParams(data);
321 // check if browser knows *background-size
322 for (var bs in {'':1, '-moz-':1, '-webkit-':1, '-o-':1}) {
323 if ($elem.css(bs+'background-size')) {
324 data.hasBgSize = true;
325 data.bgSizeName = bs+'background-size';
326 break;
327 }
328 }
329 // check digilib base URL
330 if (elemSettings.digilibBaseUrl == null) {
331 if (isFullscreen) {
332 // take current host
333 var url = window.location.toString();
334 var pos = url.indexOf('?');
335 elemSettings.digilibBaseUrl = url.substring(0, pos);
336 } else {
337 var url = elemSettings.scalerBaseUrl;
338 if (url) {
339 // build it from scaler URL
340 var bp = url.indexOf('/servlet/Scaler');
341 elemSettings.digilibBaseUrl = url.substring(0, bp) + '/digilib.jsp';
342 }
343 }
344 }
345 // create HTML structure for scaler
346 setupScalerDiv(data);
347 // add buttons
348 for (var i = 0; i < elemSettings.visibleButtonSets; ++i) {
349 showButtons(data, true, i);
350 }
351 // bird's eye view creation
352 if (elemSettings.isBirdDivVisible) {
353 setupBirdDiv(data);
354 data.$birdDiv.show();
355 }
356 // about window creation - TODO: could be deferred? restrict to only one item?
357 setupAboutDiv(data);
358 // drag zoom area around in scaler div
359 setupZoomDrag(data);
360 // dialog for brightness, rotate etc.
361 setupDialogDiv(data);
362 });
363 },
364
365 // destroy: clean up digilib
366 destroy : function(data) {
367 return this.each(function(){
368 var $elem = $(this);
369 $(window).unbind('.digilib'); // unbind all digilibs(?)
370 data.digilib.remove();
371 $elem.removeData('digilib');
372 });
373 },
374
375 // show or hide the 'about' window
376 showAboutDiv : function(data, show) {
377 data.settings.isAboutDivVisible = showDiv(data.settings.isAboutDivVisible, data.$aboutDiv, show);
378 },
379
380 // event handler: toggles the visibility of the bird's eye window
381 showBirdDiv : function (data, show) {
382 var settings = data.settings;
383 if (data.$birdDiv == null) {
384 // no bird div -> create
385 setupBirdDiv(data);
386 }
387 settings.isBirdDivVisible = showDiv(settings.isBirdDivVisible, data.$birdDiv, show);
388 updateBirdDiv(data);
389 storeOptions(data);
390 // data.$birdImg.triggerHandler('load'); // TODO: we shouldn't do that
391 },
392
393 // goto given page nr (+/-: relative)
394 gotoPage : function (data, pageNr) {
395 var settings = data.settings;
396 var oldpn = settings.pn;
397 if (pageNr == null) {
398 pageNr = window.prompt("Goto page number", oldpn);
399 }
400 var pn = setNumValue(settings, "pn", pageNr);
401 if (pn == null) return false; // nothing happened
402 if (pn < 1) {
403 alert("no such page (page number too low)");
404 settings.pn = oldpn;
405 return false;
406 }
407 if (settings.pt) {
408 if (pn > settings.pt) {
409 alert("no such page (page number too high)");
410 settings.pn = oldpn;
411 return false;
412 }
413 }
414 // reset mk and others(?)
415 data.marks = [];
416 data.zoomArea = FULL_AREA;
417 // then reload
418 redisplay(data);
419 },
420
421 // zoom by a given factor
422 zoomBy : function (data, factor) {
423 zoomBy(data, factor);
424 },
425
426 // zoom interactively
427 zoomArea : function (data) {
428 zoomArea(data);
429 },
430
431 // zoom out to full page
432 zoomFull : function (data, mode) {
433 data.zoomArea = FULL_AREA;
434 if (mode === 'width') {
435 data.dlOpts.fitwidth = 1;
436 delete data.dlOpts.fitheight;
437 } else if (mode === 'height') {
438 data.dlOpts.fitheight = 1;
439 delete data.dlOpts.fitwidth;
440 } else {
441 delete data.dlOpts.fitwidth;
442 delete data.dlOpts.fitheight;
443 }
444 redisplay(data);
445 },
446
447 // set a mark by clicking (or giving a position)
448 setMark : function (data, mpos) {
449 if (mpos == null) {
450 // interactive
451 setMark(data);
452 } else {
453 // use position
454 data.marks.push(pos);
455 redisplay(data);
456 }
457 },
458
459 // remove the last mark
460 removeMark : function (data) {
461 data.marks.pop();
462 redisplay(data);
463 },
464
465 // mirror the image
466 mirror : function (data, mode) {
467 var flags = data.scalerFlags;
468 if (mode === 'h') {
469 if (flags.hmir) {
470 delete flags.hmir;
471 } else {
472 flags.hmir = 1;
473 }
474 } else {
475 if (flags.vmir) {
476 delete flags.vmir;
477 } else {
478 flags.vmir = 1;
479 }
480 }
481 redisplay(data);
482 },
483
484 // rotate the image
485 rotate : function (data, angle) {
486 var rot = data.settings.rot;
487 if (angle == null) {
488 // angle = window.prompt("Rotation angle:", rot);
489 var $slider = data.$slider;
490 $slider.slider('enable');
491 var $dialog = data.$dialog;
492 $dialog.text('Set the slider');
493 $dialog.dialog('option', {
494 'title' : 'set rotation angle',
495 });
496 $dialog.dialog('open');
497 }
498 //data.settings.rot = angle;
499 //redisplay(data);
500 },
501
502 // change brightness
503 brightness : function (data, factor) {
504 var brgt = data.settings.brgt;
505 if (factor == null) {
506 factor = window.prompt("Brightness (-255..255)", brgt);
507 }
508 data.settings.brgt = factor;
509 redisplay(data);
510 },
511
512 // change contrast
513 contrast : function (data, factor) {
514 var cont = data.settings.cont;
515 if (factor == null) {
516 factor = window.prompt("Contrast (-8, 8)", cont);
517 }
518 data.settings.cont = factor;
519 redisplay(data);
520 },
521
522 // display more (or less) button sets
523 moreButtons : function (data, more) {
524 var settings = data.settings;
525 if (more == null) {
526 // toggle more or less (only works for 2 sets)
527 var maxbtns = settings.buttonSettings[settings.interactionMode].buttonSets.length;
528 if (settings.visibleButtonSets >= maxbtns) {
529 more = '-1';
530 } else {
531 more = '+1';
532 }
533 }
534 if (more === '-1') {
535 // remove set
536 var setIdx = settings.visibleButtonSets - 1;
537 if (showButtons(data, false, setIdx, true)) {
538 settings.visibleButtonSets--;
539 }
540 } else {
541 // add set
542 var setIdx = settings.visibleButtonSets;
543 if (showButtons(data, true, setIdx, true)) {
544 settings.visibleButtonSets++;
545 }
546 }
547 // persist setting
548 storeOptions(data);
549 },
550
551 // reset image parameters to defaults
552 reset : function (data) {
553 var settings = data.settings;
554 var paramNames = settings.digilibParamNames;
555 var params = data.queryParams;
556 // delete all digilib parameters
557 for (var i = 0; i < paramNames.length; i++) {
558 var paramName = paramNames[i];
559 delete settings[paramName];
560 }
561 settings.fn = params.fn || ''; // no default defined
562 settings.pn = params.pn || defaults.pn;
563 settings.dw = params.dw;
564 settings.dh = params.dh;
565 settings.isBirdDivVisible = false;
566 settings.visibleButtonSets = 1;
567 // resets zoomArea, marks, scalerflags
568 data.zoomArea = FULL_AREA;
569 data.marks = [];
570 data.scalerFlags = {};
571 delete data.dlOpts.fitwidth;
572 delete data.dlOpts.fitheight;
573 redisplay(data);
574 },
575
576 // presents a reference url (returns value if noprompt)
577 reference : function (data, noprompt) {
578 var settings = data.settings;
579 var url = getDigilibUrl(data);
580 if (noprompt == null) {
581 window.prompt("URL reference to the current view", url);
582 }
583 return url;
584 },
585
586 // set image quality
587 setQuality : function (data, qual) {
588 var oldq = getQuality(data);
589 if (qual == null) {
590 qual = window.prompt("Image quality (0..2)", oldq);
591 }
592 qual = parseInt(qual, 10);
593 if (qual >= 0 && qual <= 2) {
594 setQuality(data, qual);
595 redisplay(data);
596 }
597 }
598 };
599
600 // returns parameters from page url
601 var parseQueryParams = function() {
602 return parseQueryString(window.location.search.slice(1));
603 };
604
605 // returns parameters from embedded img-element
606 var parseImgParams = function($elem) {
607 var src = $elem.find('img').first().attr('src');
608 if (!src) return null;
609 var pos = src.indexOf('?');
610 var query = (pos < 0) ? '' : src.substring(pos + 1);
611 var scalerUrl = src.substring(0, pos);
612 var params = parseQueryString(query);
613 params.scalerBaseUrl = scalerUrl;
614 return params;
615 };
616
617 // parses query parameter string into parameter object
618 var parseQueryString = function(query) {
619 var params = {};
620 if (query == null) return params;
621 var pairs = query.split("&");
622 //var keys = [];
623 for (var i = 0; i < pairs.length; i++) {
624 var pair = pairs[i].split("=");
625 if (pair.length === 2) {
626 params[pair[0]] = pair[1];
627 //keys.push(pair[0]);
628 }
629 }
630 return params;
631 };
632
633 // returns a query string from key names from a parameter hash (ignoring if the same value is in defaults)
634 var getParamString = function (settings, keys, defaults) {
635 var paramString = '';
636 var nx = false;
637 for (i = 0; i < keys.length; ++i) {
638 var key = keys[i];
639 if ((settings[key] != null) && ((defaults == null) || (settings[key] != defaults[key]))) {
640 // first param gets no '&'
641 if (nx) {
642 paramString += '&';
643 } else {
644 nx = true;
645 }
646 // add parm=val
647 paramString += key + '=' + settings[key];
648 }
649 }
650 return paramString;
651 };
652
653 // returns URL and query string for Scaler
654 var getScalerUrl = function (data) {
655 packParams(data);
656 var settings = data.settings;
657 if (settings.scalerBaseUrl == null) {
658 alert("ERROR: URL of digilib Scaler servlet missing!");
659 }
660 var keys = settings.scalerParamNames;
661 var queryString = getParamString(settings, keys, defaults);
662 var url = settings.scalerBaseUrl + '?' + queryString;
663 return url;
664 };
665
666 // returns URL for bird's eye view image
667 var getBirdImgUrl = function (data, moreParams) {
668 var settings = data.settings;
669 var birdDivOptions = {
670 dw : settings.birdDivWidth,
671 dh : settings.birdDivHeight
672 };
673 var birdSettings = jQuery.extend({}, settings, birdDivOptions);
674 // use only the relevant parameters
675 if (moreParams == null) {
676 var params = getParamString(birdSettings, settings.birdDivParams, defaults);
677 } else {
678 var params = getParamString(birdSettings,
679 settings.birdDivParams.concat(moreParams), defaults);
680 }
681 var url = settings.scalerBaseUrl + '?' + params;
682 return url;
683 };
684
685 // returns URL and query string for current digilib
686 var getDigilibUrl = function (data) {
687 packParams(data);
688 var settings = data.settings;
689 var queryString = getParamString(settings, settings.digilibParamNames, defaults);
690 return settings.digilibBaseUrl + '?' + queryString;
691 };
692
693 // processes some parameters into objects and stuff
694 var unpackParams = function (data) {
695 var settings = data.settings;
696 // zoom area
697 var zoomArea = geom.rectangle(settings.wx, settings.wy, settings.ww, settings.wh);
698 data.zoomArea = zoomArea;
699 // marks
700 var marks = [];
701 if (settings.mk) {
702 var mk = settings.mk;
703 if (mk.indexOf(";") >= 0) {
704 var pa = mk.split(";"); // old format with ";"
705 } else {
706 var pa = mk.split(","); // new format
707 }
708 for (var i = 0; i < pa.length ; i++) {
709 var pos = pa[i].split("/");
710 if (pos.length > 1) {
711 marks.push(geom.position(pos[0], pos[1]));
712 }
713 }
714 }
715 data.marks = marks;
716 // mo (Scaler flags)
717 var flags = {};
718 if (settings.mo) {
719 var pa = settings.mo.split(",");
720 for (var i = 0; i < pa.length ; i++) {
721 flags[pa[i]] = pa[i];
722 }
723 }
724 data.scalerFlags = flags;
725 retrieveOptions(data);
726 };
727
728 // put objects back into parameters
729 var packParams = function (data) {
730 var settings = data.settings;
731 // zoom area
732 if (data.zoomArea) {
733 settings.wx = cropFloat(data.zoomArea.x);
734 settings.wy = cropFloat(data.zoomArea.y);
735 settings.ww = cropFloat(data.zoomArea.width);
736 settings.wh = cropFloat(data.zoomArea.height);
737 }
738 // marks
739 if (data.marks) {
740 settings.mk = '';
741 for (var i = 0; i < data.marks.length; i++) {
742 if (i) {
743 settings.mk += ',';
744 }
745 settings.mk += cropFloat(data.marks[i].x).toString() +
746 '/' + cropFloat(data.marks[i].y).toString();
747 }
748 }
749 // Scaler flags
750 if (data.scalerFlags) {
751 var mo = '';
752 for (var f in data.scalerFlags) {
753 if (mo) {
754 mo += ',';
755 }
756 mo += f;
757 }
758 settings.mo = mo;
759 }
760 // user interface options
761 storeOptions(data);
762 };
763
764 var storeOptions = function (data) {
765 // save digilib options in cookie
766 var settings = data.settings;
767 if (data.dlOpts) {
768 // save digilib settings in options
769 data.dlOpts.birdview = settings.isBirdDivVisible ? 1 : 0;
770 data.dlOpts.buttons = settings.visibleButtonSets;
771 var clop = '';
772 for (var o in data.dlOpts) {
773 if (clop) {
774 clop += '&';
775 }
776 clop += o + '=' + data.dlOpts[o];
777 }
778 if (jQuery.cookie) {
779 var ck = "digilib:fn:" + escape(settings.fn) + ":pn:" + settings.pn;
780 console.debug("set cookie=", ck, " value=", clop);
781 jQuery.cookie(ck, clop);
782 }
783 }
784 if (settings.interactionMode !== 'fullscreen' && jQuery.cookie) {
785 // store normal parameters in cookie for embedded mode
786 var qs = getParamString(settings, settings.digilibParamNames, defaults);
787 var ck = "digilib-embed:fn:" + escape(settings.fn) + ":pn:" + settings.pn;
788 console.debug("set cookie=", ck, " value=", qs);
789 jQuery.cookie(ck, qs);
790 }
791 };
792
793 var retrieveOptions = function (data) {
794 // clop (digilib options)
795 var opts = {};
796 var settings = data.settings;
797 if (jQuery.cookie) {
798 // read from cookie
799 var ck = "digilib:fn:" + escape(settings.fn) + ":pn:" + settings.pn;
800 var cp = jQuery.cookie(ck);
801 console.debug("get cookie=", ck, " value=", cp);
802 // in query string format
803 opts = parseQueryString(cp);
804 }
805 data.dlOpts = opts;
806 // birdview option
807 if (opts.birdview != null) {
808 settings.isBirdDivVisible = opts.birdview === '1';
809 }
810 // visible button sets
811 if (opts.buttons != null) {
812 settings.visibleButtonSets = opts.buttons;
813 }
814 };
815
816 // (re)load the img from a new scaler URL
817 var redisplay = function (data) {
818 var settings = data.settings;
819 if (settings.interactionMode === 'fullscreen') {
820 // update location.href (browser URL) in fullscreen mode
821 var url = getDigilibUrl(data);
822 var history = window.history;
823 if (typeof(history.pushState) === 'function') {
824 console.debug("we could modify history, but we don't...");
825 }
826 window.location = url;
827 } else {
828 // embedded mode -- just change img src
829 var url = getScalerUrl(data);
830 data.$img.attr('src', url);
831 // redisplay bird img
832 updateBirdDiv(data);
833 }
834 };
835
836 // returns maximum size for scaler img in fullscreen mode
837 var getFullscreenImgSize = function($elem) {
838 var $win = $(window);
839 var winH = $win.height();
840 var winW = $win.width();
841 // TODO: account for borders?
842 return geom.size(winW, winH);
843 };
844
845 // creates HTML structure for digilib in elem
846 var setupScalerDiv = function (data) {
847 var settings = data.settings;
848 var $elem = data.$elem;
849 $elem.addClass('digilib');
850 var $img;
851 var scalerUrl;
852 if (settings.interactionMode === 'fullscreen') {
853 // fullscreen
854 $elem.addClass('dl_fullscreen');
855 var imgSize = getFullscreenImgSize($elem);
856 // fitwidth/height omits destination height/width
857 if (data.dlOpts.fitheight == null) {
858 settings.dw = imgSize.width;
859 }
860 if (data.dlOpts.fitwidth == null) {
861 settings.dh = imgSize.height;
862 }
863 scalerUrl = getScalerUrl(data);
864 $img = $('<img/>');
865 } else {
866 // embedded mode -- try to keep img tag
867 $elem.addClass('dl_embedded');
868 scalerUrl = getScalerUrl(data);
869 $img = $elem.find('img');
870 if ($img.length > 0) {
871 oldUrl = $img.attr('src');
872 if (oldUrl === scalerUrl) {
873 console.debug("img detach:", $img);
874 $img.detach();
875 } else {
876 $img = $('<img/>');
877 }
878 } else {
879 $img = $('<img/>');
880 }
881 }
882 // create new html
883 $elem.empty(); // TODO: should we keep stuff for customization?
884 var $scaler = $('<div class="scaler"/>');
885 $elem.append($scaler);
886 $scaler.append($img);
887 $img.addClass('pic');
888 data.$scaler = $scaler;
889 data.$img = $img;
890 // setup image load handler before setting the src attribute (IE bug)
891 $img.load(scalerImgLoadedHandler(data));
892 $img.attr('src', scalerUrl);
893 };
894
895 // creates HTML structure for buttons in elem
896 var createButtons = function (data, buttonSetIdx) {
897 var $elem = data.$elem;
898 var settings = data.settings;
899 var mode = settings.interactionMode;
900 var buttonSettings = settings.buttonSettings[mode];
901 var buttonGroup = buttonSettings.buttonSets[buttonSetIdx];
902 if (buttonGroup == null) {
903 // no buttons here
904 return;
905 }
906 var $buttonsDiv = $('<div class="buttons"/>');
907 var buttonNames = buttonSettings[buttonGroup];
908 for (var i = 0; i < buttonNames.length; i++) {
909 var buttonName = buttonNames[i];
910 var buttonConfig = settings.buttons[buttonName];
911 // construct the button html
912 var $button = $('<div class="button"></div>');
913 var $a = $('<a/>');
914 var $img = $('<img class="button"/>');
915 $buttonsDiv.append($button);
916 $button.append($a);
917 $a.append($img);
918 // add attributes and bindings
919 $button.attr('title', buttonConfig.tooltip);
920 $button.addClass('button-' + buttonName);
921 // create handler for the buttons
922 $a.bind('click.digilib', (function () {
923 // we create a new closure to capture the value of action
924 var action = buttonConfig.onclick;
925 if ($.isArray(action)) {
926 // the handler function calls digilib with action and parameters
927 return function (evt) {
928 console.debug('click action=', action, ' evt=', evt);
929 $elem.digilib.apply($elem, action);
930 return false;
931 };
932 } else {
933 // the handler function calls digilib with action
934 return function (evt) {
935 console.debug('click action=', action, ' evt=', evt);
936 $elem.digilib(action);
937 return false;
938 };
939 }
940 })());
941 $img.attr('src', buttonSettings.imagePath + buttonConfig.img);
942 }
943 // make buttons div scroll if too large for window
944 if ($buttonsDiv.height() > $(window).height() - 10) {
945 $buttonsDiv.css('position', 'absolute');
946 }
947 // buttons hidden at first
948 $buttonsDiv.hide();
949 $elem.append($buttonsDiv);
950 if (data.$buttonSets == null) {
951 // first button set
952 data.$buttonSets = [$buttonsDiv];
953 } else {
954 $elem.append($buttonsDiv);
955 data.$buttonSets[buttonSetIdx] = $buttonsDiv;
956 }
957 return $buttonsDiv;
958 };
959
960 // creates HTML structure for the bird's eye view in elem
961 var setupBirdDiv = function (data) {
962 var $elem = data.$elem;
963 // the bird's eye div
964 var $birdDiv = $('<div class="birdview" style="display:none"/>');
965 // the detail indicator frame
966 var $birdZoom = $('<div class="birdzoom" style="display:none; background-color:transparent;"/>');
967 // the small image
968 var $birdImg = $('<img class="birdimg"/>');
969 data.$birdDiv = $birdDiv;
970 data.$birdZoom = $birdZoom;
971 data.$birdImg = $birdImg;
972 $elem.append($birdDiv);
973 $birdDiv.append($birdZoom);
974 $birdDiv.append($birdImg);
975 $birdZoom.css(data.settings.birdIndicatorStyle);
976 var birdUrl = getBirdImgUrl(data);
977 $birdImg.load(birdImgLoadedHandler(data));
978 $birdImg.attr('src', birdUrl);
979 };
980
981 // update bird's eye view
982 var updateBirdDiv = function (data) {
983 if (!data.settings.isBirdDivVisible) return;
984 var $birdImg = data.$birdImg;
985 var oldsrc = $birdImg.attr('src');
986 var newsrc = getBirdImgUrl(data);
987 if (oldsrc !== newsrc) {
988 $birdImg.attr('src', newsrc);
989 // onload handler re-renders
990 } else {
991 // re-render
992 renderBirdArea(data);
993 // enable click and drag
994 setupBirdDrag(data);
995 }
996 };
997
998 // creates HTML structure for the dialog
999 var setupDialogDiv = function (data) {
1000 var $elem = data.$elem;
1001 var settings = data.settings;
1002 var $dialogDiv = $('<div/>');
1003 var $sliderDiv = $('<div/>');
1004 $dialogDiv.append($sliderDiv);
1005 $dialogDiv.dialog({
1006 'autoOpen' : false,
1007 'buttons': {
1008 "Ok": function() {
1009 $(this).dialog("close");
1010 },
1011 "Cancel": function() {
1012 $(this).dialog("close");
1013 }
1014 }
1015 });
1016 $sliderDiv.slider({
1017 'range' : true,
1018 'min' : 0,
1019 'max' : 500,
1020 'values' : [ 75, 300 ]
1021 });
1022 data.$dialog = $dialogDiv;
1023 data.$slider = $sliderDiv;
1024 };
1025
1026 // creates HTML structure for the about view in elem
1027 var setupAboutDiv = function (data) {
1028 var $elem = data.$elem;
1029 var settings = data.settings;
1030 var $aboutDiv = $('<div class="about" style="display:none"/>');
1031 var $header = $('<p>Digilib Graphic Viewer</p>');
1032 var $link = $('<a/>');
1033 var $logo = $('<img class="logo" title="digilib"/>');
1034 var $content = $('<p/>');
1035 $elem.append($aboutDiv);
1036 $aboutDiv.append($header);
1037 $aboutDiv.append($link);
1038 $aboutDiv.append($content);
1039 $link.append($logo);
1040 $logo.attr('src', settings.logoUrl);
1041 $link.attr('href', settings.homeUrl);
1042 $content.text('Version: ' + settings.version);
1043 // click hides
1044 $aboutDiv.bind('click.digilib', function () {
1045 settings.isAboutDivVisible = showDiv(settings.isAboutDivVisible, $aboutDiv, 0);
1046 return false;
1047 });
1048 data.$aboutDiv = $aboutDiv;
1049 };
1050
1051 // shows some window e.g. 'about' (toggle visibility if show is null)
1052 var showDiv = function (isVisible, $div, show) {
1053 if (show == null) {
1054 // toggle visibility
1055 isVisible = !isVisible;
1056 } else {
1057 // set visibility
1058 isVisible = show;
1059 }
1060 if (isVisible) {
1061 $div.fadeIn();
1062 } else {
1063 $div.fadeOut();
1064 }
1065 return isVisible;
1066 };
1067
1068 // display more (or less) button sets
1069 var showButtons = function (data, more, setIdx, animated) {
1070 var atime = animated ? 'fast': 0;
1071 if (more) {
1072 // add set
1073 var $otherSets = data.$elem.find('div.buttons:visible');
1074 var $set;
1075 if (data.$buttonSets && data.$buttonSets[setIdx]) {
1076 // set exists
1077 $set = data.$buttonSets[setIdx];
1078 } else {
1079 $set = createButtons(data, setIdx);
1080 }
1081 if ($set == null) return false;
1082 var btnWidth = $set.width();
1083 // move remaining sets left and show new set
1084 if ($otherSets.length > 0) {
1085 $otherSets.animate({right : '+='+btnWidth+'px'}, atime,
1086 function () {$set.show();});
1087 } else {
1088 $set.show();
1089 }
1090 } else {
1091 // remove set
1092 var $set = data.$buttonSets[setIdx];
1093 if ($set == null) return false;
1094 var btnWidth = $set.width();
1095 // hide last set
1096 $set.hide();
1097 // take remaining sets and move right
1098 var $otherSets = data.$elem.find('div.buttons:visible');
1099 $otherSets.animate({right : '-='+btnWidth+'px'}, atime);
1100 }
1101 return true;
1102 };
1103
1104 // create Transform from area and $img
1105 var getImgTrafo = function ($img, area, rot, hmir, vmir) {
1106 var picrect = geom.rectangle($img);
1107 var trafo = geom.transform();
1108 // move zoom area offset to center
1109 trafo.concat(trafo.getTranslation(geom.position(-area.x, -area.y)));
1110 // scale zoom area size to [1,1]
1111 trafo.concat(trafo.getScale(geom.size(1/area.width, 1/area.height)));
1112 // rotate and mirror (around transformed image center i.e. [0.5,0.5])
1113 if (rot || hmir || vmir) {
1114 // move [0.5,0.5] to center
1115 trafo.concat(trafo.getTranslation(geom.position(-0.5, -0.5)));
1116 if (hmir) {
1117 // mirror about center
1118 trafo.concat(trafo.getMirror('y'));
1119 }
1120 if (vmir) {
1121 // mirror about center
1122 trafo.concat(trafo.getMirror('x'));
1123 }
1124 if (rot) {
1125 // rotate around center
1126 trafo.concat(trafo.getRotation(parseFloat(rot)));
1127 }
1128 // move back
1129 trafo.concat(trafo.getTranslation(geom.position(0.5, 0.5)));
1130 }
1131 // scale to screen position and size
1132 trafo.concat(trafo.getScale(picrect));
1133 trafo.concat(trafo.getTranslation(picrect));
1134 return trafo;
1135 };
1136
1137 // returns function for load event of scaler img
1138 var scalerImgLoadedHandler = function (data) {
1139 return function () {
1140 var $img = $(this);
1141 var $scaler = data.$scaler;
1142 // create Transform from current area and picsize
1143 data.imgTrafo = getImgTrafo($img, data.zoomArea,
1144 data.settings.rot, data.scalerFlags.hmir, data.scalerFlags.vmir);
1145 console.debug("imgTrafo=", data.imgTrafo);
1146 // adjust scaler div size
1147 var imgRect = geom.rectangle($img);
1148 console.debug("imgrect=", imgRect);
1149 imgRect.adjustDiv($scaler);
1150 // show image in case it was hidden (for example in zoomDrag)
1151 $img.css('visibility', 'visible');
1152 $scaler.css({'opacity' : '1', 'background-image' : 'none'});
1153 // display marks
1154 renderMarks(data);
1155 // enable drag-to-scroll
1156 setupZoomDrag(data);
1157 // TODO: digilib.showArrows(); // show arrow overlays for zoom navigation
1158 };
1159 };
1160
1161 // returns function for load event of bird's eye view img
1162 var birdImgLoadedHandler = function (data) {
1163 return function () {
1164 var $img = $(this);
1165 console.debug("birdimg loaded! this=", this, " data=", data);
1166 // create Transform from current area and picsize
1167 data.birdTrafo = getImgTrafo($img, FULL_AREA);
1168 // display red indicator around zoomarea
1169 renderBirdArea(data);
1170 // enable click and drag
1171 setupBirdDrag(data);
1172 };
1173 };
1174
1175 // place marks on the image
1176 var renderMarks = function (data) {
1177 var $elem = data.$elem;
1178 var marks = data.marks;
1179 // clear marks
1180 $elem.find('div.mark').remove();
1181 for (var i = 0; i < marks.length; i++) {
1182 var mark = marks[i];
1183 if (data.zoomArea.containsPosition(mark)) {
1184 var mpos = data.imgTrafo.transform(mark);
1185 console.debug("renderMarks: mpos=",mpos);
1186 // create mark
1187 var html = '<div class="mark">'+(i+1)+'</div>';
1188 var $mark = $(html);
1189 $elem.append($mark);
1190 mpos.adjustDiv($mark);
1191 }
1192 }
1193 };
1194
1195 // show zoom area indicator on bird's eye view
1196 var renderBirdArea = function (data) {
1197 var $birdZoom = data.$birdZoom;
1198 var zoomArea = data.zoomArea;
1199 var normalSize = isFullArea(zoomArea);
1200 if (normalSize) {
1201 $birdZoom.hide();
1202 return;
1203 } else {
1204 $birdZoom.show();
1205 }
1206 // position may have changed
1207 data.birdTrafo = getImgTrafo(data.$birdImg, FULL_AREA);
1208 var zoomRect = data.birdTrafo.transform(zoomArea);
1209 // acount for border width
1210 zoomRect.addPosition({x : -2, y : -2});
1211 if (data.settings.interactionMode === 'fullscreen') {
1212 // no animation for fullscreen
1213 zoomRect.adjustDiv($birdZoom);
1214 } else {
1215 // nice animation for embedded mode :-)
1216 // correct offsetParent because animate doesn't use offset
1217 var ppos = $birdZoom.offsetParent().offset();
1218 var dest = {
1219 left : (zoomRect.x - ppos.left) + 'px',
1220 top : (zoomRect.y - ppos.top) + 'px',
1221 width : zoomRect.width,
1222 height : zoomRect.height};
1223 $birdZoom.animate(dest);
1224 }
1225 };
1226
1227 // zooms by the given factor
1228 var zoomBy = function(data, factor) {
1229 var area = data.zoomArea;
1230 var newarea = area.copy();
1231 // scale
1232 newarea.width /= factor;
1233 newarea.height /= factor;
1234 // and recenter
1235 newarea.x -= 0.5 * (newarea.width - area.width);
1236 newarea.y -= 0.5 * (newarea.height - area.height);
1237 newarea = FULL_AREA.fit(newarea);
1238 data.zoomArea = newarea;
1239 redisplay(data);
1240 };
1241
1242 // add a mark where clicked
1243 var setMark = function (data) {
1244 var $scaler = data.$scaler;
1245 // unbind other handler
1246 $scaler.unbind(".dlZoomDrag");
1247 // start event capturing
1248 $scaler.one('mousedown.dlSetMark', function (evt) {
1249 // event handler adding a new mark
1250 console.log("setmark at=", evt);
1251 var mpos = geom.position(evt);
1252 var pos = data.imgTrafo.invtransform(mpos);
1253 data.marks.push(pos);
1254 redisplay(data);
1255 return false;
1256 });
1257 };
1258
1259 // zoom to the area around two clicked points
1260 var zoomArea = function(data) {
1261 $elem = data.$elem;
1262 $scaler = data.$scaler;
1263 var pt1, pt2;
1264 var $zoomDiv = $('<div class="zoomrect" style="display:none"/>');
1265 $elem.append($zoomDiv);
1266 $zoomDiv.css(data.settings.zoomrectStyle);
1267 var picRect = geom.rectangle($scaler);
1268 // FIX ME: is there a way to query the border width from CSS info?
1269 // rect.x -= 2; // account for overlay borders
1270 // rect.y -= 2;
1271
1272 var zoomStart = function (evt) {
1273 pt1 = geom.position(evt);
1274 // setup and show zoom div
1275 pt1.adjustDiv($zoomDiv);
1276 $zoomDiv.width(0).height(0);
1277 $zoomDiv.show();
1278 // register events
1279 $elem.bind("mousemove.dlZoomArea", zoomMove);
1280 $elem.bind("mouseup.dlZoomArea", zoomEnd);
1281 return false;
1282 };
1283
1284 // mouse move handler
1285 var zoomMove = function (evt) {
1286 pt2 = geom.position(evt);
1287 var rect = geom.rectangle(pt1, pt2);
1288 rect.clipTo(picRect);
1289 // update zoom div
1290 rect.adjustDiv($zoomDiv);
1291 return false;
1292 };
1293
1294 // mouseup handler: end moving
1295 var zoomEnd = function (evt) {
1296 pt2 = geom.position(evt);
1297 // assume a click and continue if the area is too small
1298 var clickRect = geom.rectangle(pt1, pt2);
1299 if (clickRect.getArea() <= 5) return false;
1300 // hide zoom div
1301 $zoomDiv.remove();
1302 // unregister events
1303 $elem.unbind("mousemove.dlZoomArea", zoomMove);
1304 $elem.unbind("mouseup.dlZoomArea", zoomEnd);
1305 // clip and transform
1306 clickRect.clipTo(picRect);
1307 var area = data.imgTrafo.invtransform(clickRect);
1308 data.zoomArea = area;
1309 // zoomed is always fit
1310 data.settings.ws = 1;
1311 delete data.dlOpts.fitwidth;
1312 delete data.dlOpts.fitheight;
1313 redisplay(data);
1314 return false;
1315 };
1316
1317 // clear old handler (also ZoomDrag)
1318 $scaler.unbind('.dlZoomArea');
1319 $scaler.unbind(".dlZoomDrag");
1320 $elem.unbind('.dlZoomArea');
1321 // bind start zoom handler
1322 $scaler.one('mousedown.dlZoomArea', zoomStart);
1323 };
1324
1325 // bird's eye view zoom area click and drag handler
1326 var setupBirdDrag = function(data) {
1327 var $birdImg = data.$birdImg;
1328 var $birdZoom = data.$birdZoom;
1329 var $document = $(document);
1330 var $scaler = data.$scaler;
1331 var startPos, newRect, birdImgRect, birdZoomRect, fullRect, scalerPos;
1332
1333 // mousedown handler: start dragging bird zoom to a new position
1334 var birdZoomStartDrag = function(evt) {
1335 startPos = geom.position(evt);
1336 // position may have changed
1337 data.birdTrafo = getImgTrafo($birdImg, FULL_AREA);
1338 birdImgRect = geom.rectangle($birdImg);
1339 birdZoomRect = geom.rectangle($birdZoom);
1340 scalerPos = geom.position($scaler);
1341 newRect = null;
1342 fullRect = setZoomBG(data); // setup zoom background image
1343 $document.bind("mousemove.dlBirdMove", birdZoomMove);
1344 $document.bind("mouseup.dlBirdMove", birdZoomEndDrag);
1345 return false;
1346 };
1347
1348 // mousemove handler: drag
1349 var birdZoomMove = function(evt) {
1350 var pos = geom.position(evt);
1351 var delta = startPos.delta(pos);
1352 // move birdZoom div, keeping size
1353 newRect = birdZoomRect.copy();
1354 newRect.addPosition(delta);
1355 newRect.stayInside(birdImgRect);
1356 // reflect birdview zoom position in scaler image
1357 var area = data.birdTrafo.invtransform(newRect);
1358 var imgArea = data.imgTrafo.transform(area);
1359 var offset = imgArea.getPosition().neg();
1360 offset.add(scalerPos);
1361 console.log('offset', offset);
1362 if (fullRect) {
1363 var bgPos = fullRect.getPosition().add(offset);
1364 } else {
1365 var bgPos = offset;
1366 }
1367 // move the background image to the new position
1368 data.$scaler.css({
1369 'background-position' : bgPos.x + "px " + bgPos.y + "px"
1370 });
1371 // acount for border width
1372 newRect.addPosition({x : -2, y : -2});
1373 newRect.adjustDiv($birdZoom);
1374 return false;
1375 };
1376
1377 // mouseup handler: reload page
1378 var birdZoomEndDrag = function(evt) {
1379 var settings = data.settings;
1380 $document.unbind("mousemove.dlBirdMove", birdZoomMove);
1381 $document.unbind("mouseup.dlBirdMove", birdZoomEndDrag);
1382 if (newRect == null) {
1383 // no movement happened - set center to click position
1384 startPos = birdZoomRect.getCenter();
1385 birdZoomMove(evt);
1386 }
1387 // ugly, but needed to prevent double border width compensation
1388 newRect.addPosition({x : +2, y : +2});
1389 var newArea = data.birdTrafo.invtransform(newRect);
1390 data.zoomArea = newArea;
1391 redisplay(data);
1392 return false;
1393 };
1394
1395 // clear old handler
1396 $document.unbind(".dlBirdMove");
1397 $birdImg.unbind(".dlBirdMove");
1398 $birdZoom.unbind(".dlBirdMove");
1399 if (! isFullArea(data.zoomArea)) {
1400 // set new handler
1401 $birdImg.bind("mousedown.dlBirdMove", birdZoomStartDrag);
1402 $birdZoom.bind("mousedown.dlBirdMove", birdZoomStartDrag);
1403 }
1404 };
1405
1406 // move bird zoom indicator to reflect zoomed detail area
1407 var setBirdZoom = function(data, rect) {
1408 var part = data.imgTrafo.invtransform(rect);
1409 // area = FULL_AREA.fit(part); // no, we want to see where we transcend the borders
1410 birdTrafo = getImgTrafo(data.$birdImg, FULL_AREA);
1411 var birdRect = birdTrafo.transform(part);
1412 // acount for border width
1413 birdRect.addPosition({x : -2, y : -2});
1414 birdRect.adjustDiv(data.$birdZoom);
1415 };
1416
1417 // set zoom background
1418 var setZoomBG = function(data) {
1419 var $scaler = data.$scaler;
1420 var $img = data.$img;
1421 var fullRect = null;
1422 // hide the scaler img, show background of div instead
1423 $img.css('visibility', 'hidden');
1424 var scalerCss = {
1425 'background-image' : 'url(' + $img.attr('src') + ')',
1426 'background-repeat' : 'no-repeat',
1427 'background-position' : 'left top',
1428 'opacity' : '0.5',
1429 'cursor' : 'move'
1430 };
1431 if (data.hasBgSize) {
1432 // full-size background using CSS3-background-size
1433 fullRect = data.imgTrafo.transform(FULL_AREA);
1434 if (fullRect.height < data.settings.maxBgSize && fullRect.width < data.settings.maxBgSize) {
1435 // correct offset because background is relative
1436 var scalerPos = geom.position($scaler);
1437 fullRect.addPosition(scalerPos.neg());
1438 var url = getBirdImgUrl(data, ['rot', 'mo']);
1439 scalerCss['background-image'] = 'url(' + url + ')';
1440 scalerCss[data.bgSizeName] = fullRect.width + 'px ' + fullRect.height + 'px';
1441 scalerCss['background-position'] = fullRect.x + 'px '+ fullRect.y + 'px';
1442 } else {
1443 // too big
1444 fullRect = null;
1445 }
1446 }
1447 $scaler.css(scalerCss);
1448 // isBgReady = true;
1449 return fullRect;
1450 };
1451
1452 // setup handlers for dragging the zoomed image
1453 var setupZoomDrag = function(data) {
1454 var startPos, delta, fullRect;
1455 var $document = $(document);
1456 var $elem = data.$elem;
1457 var $scaler = data.$scaler;
1458 var $img = data.$img;
1459
1460 // drag the image and load a new detail on mouse up
1461 var dragStart = function (evt) {
1462 console.debug("dragstart at=",evt);
1463 // don't start dragging if not zoomed
1464 if (isFullArea(data.zoomArea)) return false;
1465 startPos = geom.position(evt);
1466 delta = null;
1467 // set low res background immediately on mousedown
1468 fullRect = setZoomBG(data);
1469 $document.bind("mousemove.dlZoomDrag", dragMove);
1470 $document.bind("mouseup.dlZoomDrag", dragEnd);
1471 return false;
1472 };
1473
1474 // mousemove handler: drag zoomed image
1475 var dragMove = function (evt) {
1476 var pos = geom.position(evt);
1477 delta = startPos.delta(pos);
1478 if (fullRect) {
1479 var bgPos = fullRect.getPosition().add(delta);
1480 } else {
1481 var bgPos = delta;
1482 }
1483 // move the background image to the new position
1484 $scaler.css({
1485 'background-position' : bgPos.x + "px " + bgPos.y + "px"
1486 });
1487 // set birdview indicator to reflect new zoom position
1488 var za = geom.rectangle($img);
1489 za.addPosition(delta.neg());
1490 setBirdZoom(data, za);
1491 return false;
1492 };
1493
1494 // mouseup handler: reload zoomed image in new position
1495 var dragEnd = function (evt) {
1496 $scaler.css('cursor', 'auto');
1497 $document.unbind("mousemove.dlZoomDrag", dragMove);
1498 $document.unbind("mouseup.dlZoomDrag", dragEnd);
1499 if (delta == null || delta.distance() < 2) {
1500 // no movement
1501 $img.css('visibility', 'visible');
1502 $scaler.css({'opacity' : '1', 'background-image' : 'none'});
1503 return false;
1504 }
1505 // get old zoom area (screen coordinates)
1506 var za = geom.rectangle($img);
1507 // move
1508 za.addPosition(delta.neg());
1509 // transform back
1510 var newArea = data.imgTrafo.invtransform(za);
1511 data.zoomArea = FULL_AREA.fit(newArea);
1512 redisplay(data);
1513 return false;
1514 };
1515
1516 // clear old handler
1517 $document.unbind(".dlZoomDrag");
1518 $scaler.unbind(".dlZoomDrag");
1519 if (! isFullArea(data.zoomArea)) {
1520 // set handler
1521 $scaler.bind("mousedown.dlZoomDrag", dragStart);
1522 }
1523 };
1524
1525 // get image quality as a number (0..2)
1526 var getQuality = function (data) {
1527 var flags = data.scalerFlags;
1528 var q = flags.q2 || flags.q1 || 'q0'; // assume q0 as default
1529 return parseInt(q[1], 10);
1530 };
1531
1532 // set image quality as a number (0..2)
1533 var setQuality = function (data, qual) {
1534 var flags = data.scalerFlags;
1535 // clear flags
1536 for (var i = 0; i < 3; ++i) {
1537 delete flags['q'+i];
1538 }
1539 flags['q'+qual] = 'q'+qual;
1540 };
1541
1542 // sets a key to a value (relative values with +/- if relative=true)
1543 var setNumValue = function(settings, key, value) {
1544 if (value == null) return null;
1545 if (isNumber(value)) {
1546 settings[key] = value;
1547 return value;
1548 }
1549 var sign = value[0];
1550 if (sign === '+' || sign === '-') {
1551 if (settings[key] == null) {
1552 // this isn't perfect but still...
1553 settings[key] = 0;
1554 }
1555 settings[key] = parseFloat(settings[key]) + parseFloat(value);
1556 } else {
1557 settings[key] = value;
1558 }
1559 return settings[key];
1560 };
1561
1562 // auxiliary function (from old dllib.js)
1563 var isFullArea = function(area) {
1564 return (area.width === 1.0) && (area.height === 1.0);
1565 };
1566
1567 // auxiliary function (from Douglas Crockford, A.10)
1568 var isNumber = function isNumber(value) {
1569 return typeof value === 'number' && isFinite(value);
1570 };
1571
1572 // auxiliary function to crop senseless precision
1573 var cropFloat = function (x) {
1574 return parseInt(10000 * x, 10) / 10000;
1575 };
1576
1577 // fallback for console.log calls
1578 if (customConsole) {
1579 var logFunction = function(type) {
1580 return function(){
1581 var $debug = $('#debug'); // debug div
1582 if (!$debug) return;
1583 var args = Array.prototype.slice.call(arguments);
1584 var argtext = args.join(' ');
1585 var $logDiv = $('<div/>');
1586 $logDiv.addClass(type);
1587 $logDiv.text(argtext);
1588 $debug.append($logDiv);
1589 };
1590 };
1591 console.log = logFunction('_log');
1592 console.debug = logFunction('_debug');
1593 console.error = logFunction('_error');
1594 }
1595
1596 // hook plugin into jquery
1597 $.fn.digilib = function(action) {
1598 if (actions[action]) {
1599 // call action on this with the remaining arguments (inserting data as first argument)
1600 var $elem = $(this);
1601 var data = $elem.data('digilib');
1602 var args = Array.prototype.slice.call(arguments, 1);
1603 args.unshift(data);
1604 return actions[action].apply(this, args);
1605 } else if (typeof(action) === 'object' || !action) {
1606 // call init on this
1607 return actions.init.apply(this, arguments);
1608 } else {
1609 $.error('action ' + action + ' does not exist on jQuery.digilib');
1610 }
1611 };
1612
1613 })(jQuery);