~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to lib/SunViewer/overlays.js

  • Committer: Michael Lynch
  • Date: 2008-02-01 06:21:07 UTC
  • Revision ID: mike@mike-desktop-20080201062107-uhqip0rcpsfc91mq
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @author Patrick Schmiedel patrick.schmiedel@gmx.net
 
3
 */
 
4
 
 
5
/**
 
6
 * @classDescription General overlay class. Enables to display
 
7
 * any HTML element at a position on the image.
 
8
 * Coordinate system is normalized to the interval [0,1]
 
9
 * (0,0) being the top right and (1,1) the bottom left
 
10
 * corner of the complete image.
 
11
 * @see OverlayLayerProvider
 
12
 * @see OverlayCollection
 
13
 */
 
14
var Overlay = Class.create();
 
15
 
 
16
Overlay.prototype = Object.extend(new SunViewerWidget(), {
 
17
        defaultOptions: $H({
 
18
                scaleWhenZooming: false,
 
19
                scaleFactor: 1,
 
20
                className: 'overlay'
 
21
        }),
 
22
 
 
23
        /**
 
24
         * @constructor
 
25
         * @param {String} html                 The HTML code that makes up the overlay.
 
26
         * @param {SunImage} sunImage   The sunImage the overlay belongs to. Set date to null to indicate it belongs to all images.
 
27
         * @param {Hash} options                Available options: position, offset, scaleWhenZooming, scaleFactor, dimensions
 
28
         */
 
29
        initialize: function(html, sunImage, options) {
 
30
                this.html = html;
 
31
                this.sunImage = sunImage;
 
32
                this.position = { x: 0.5, y: 0.5 };
 
33
                this.offset = { x: 0, y: 0 };
 
34
                this.domNode = null;
 
35
                this.dimensions = { width: 0, height: 0 };
 
36
                
 
37
                Object.extend(this, this.defaultOptions);
 
38
                Object.extend(this, options);
 
39
                
 
40
                this.dimensions = { width: this.dimensions.width * this.scaleFactor, height: this.dimensions.height * this.scaleFactor };
 
41
                if (this.scaleWhenZooming)
 
42
                        this.offset = { x: this.offset.x * this.scaleFactor, y: this.offset.y * this.scaleFactor };
 
43
        },
 
44
 
 
45
        /**
 
46
         * @method scaleTo                              Scales the overlay.
 
47
         * @param {Number} scaleFactor  The factor by which to scale.
 
48
         */     
 
49
        scaleTo : function(scaleFactor) {
 
50
                if (!this.dimensions) return;
 
51
                // e.g. DIV element
 
52
                if (this.domNode && this.domNode.style) {
 
53
                        this.domNode.style.width = Math.round(this.dimensions.width * scaleFactor) + 'px';
 
54
                        this.domNode.style.height = Math.round(this.dimensions.height * scaleFactor) + 'px';
 
55
                }
 
56
                // e.g. IMG element
 
57
                if (this.domNode && this.domNode.width && this.domNode.height) {
 
58
                        this.domNode.width = Math.round(this.dimensions.width * scaleFactor);
 
59
                        this.domNode.height = Math.round(this.dimensions.height * scaleFactor);
 
60
                }
 
61
        },
 
62
        
 
63
        /**
 
64
         * @method getQuadrant  Gets the quadrant number in which the overlay is located.
 
65
         * (left, top)
 
66
         *  \
 
67
         *   +--+--+ -
 
68
         *   | 0| 1|  |
 
69
         *   +--+--+  | size
 
70
         *   | 2| 3|  |
 
71
         *   +--+--+ -
 
72
         * 
 
73
         *   |_____|
 
74
         *    size
 
75
         *  
 
76
         * @param {Number} left The x coordinate of the top left corner.
 
77
         * @param {Number} top  The y coordinate of the top left corner.
 
78
         * @param {Number} size The size of the sides.
 
79
         * @return {Number}             The number of the quadrant.
 
80
         */
 
81
        getQuadrant: function(left, top, size) {
 
82
                return (this.position.x < left + size/2 ? 0 : 1) + (this.position.y < top + size/2 ? 0 : 2);
 
83
        },
 
84
        
 
85
        /**
 
86
         * @method appendTo                             Appends the overlay HTML element(s) to a layer at the given position.
 
87
         * @param {HTML Element} layer  The HTML element on which to append.
 
88
         * @param {Object} x                    The x coordinate in the HTML element in pixels.
 
89
         * @param {Object} y                    The y coordinate in the HTML element in pixels.
 
90
         */
 
91
        appendTo: function(layer, x, y) {
 
92
                // The overlay HTML element
 
93
                var htmlElement = document.createElement('div');
 
94
                htmlElement.className = this.className;
 
95
                htmlElement.innerHTML = this.html;
 
96
                
 
97
                // The black background
 
98
                bgElement = document.createElement('div');
 
99
                bgElement.className = 'blackBg';
 
100
                htmlElement.appendChild(bgElement);
 
101
 
 
102
                // NOTE: This is rather crude, but I haven't found a better way
 
103
                // to center the label on the position yet...
 
104
                htmlElement.setStyle({
 
105
                        position: 'absolute',
 
106
                        cursor: 'pointer',
 
107
                        left: Math.round(x + this.offset.x) + 'px',
 
108
                        top: Math.round(y + this.offset.y) + 'px'
 
109
                });
 
110
 
 
111
                // Append the overlay HTML element
 
112
                this.domNode = layer.appendChild(htmlElement);
 
113
 
 
114
                // If this overlay has info HTML
 
115
                if (this.infoHtml) {
 
116
                        // Show it when clicked on
 
117
                        var handler = this.showInfo.bindAsEventListener(this, layer);
 
118
                        Event.observe(htmlElement, 'mousedown', handler);
 
119
                        $(htmlElement).setStyle({ cursor: 'pointer' });
 
120
                }
 
121
        },
 
122
        
 
123
        /**
 
124
         * @method showInfo                                     Shows HTML information associated with an overlay.
 
125
         * @param {DOM MouseEvent} e            The DOM MouseEvent.
 
126
         * @param {HTML element} tileLayer      The parent node of the overlay HTML element.
 
127
         */
 
128
        showInfo: function(e, tileLayer) {
 
129
                Event.stop(e);
 
130
                var localPos = {
 
131
                        x: Math.round(parseFloat(this.domNode.style.left)) - this.offset.x,
 
132
                        y: Math.round(parseFloat(this.domNode.style.top)) - this.offset.y
 
133
                };
 
134
                this.notifyListeners('ShowInfo', { html: this.infoHtml, layer: this.domNode.parentNode, position: this.position } );
 
135
        }
 
136
});
 
137
 
 
138
/**
 
139
 * @classDescription Helper class for the quadTree.
 
140
 * Specifies a branch. Defaults to a tree leaf (endsHere=true).
 
141
 */
 
142
var branchEnd = Class.create();
 
143
 
 
144
branchEnd.prototype = Object.extend([], {
 
145
        initialize: function() { this.endsHere=true; } 
 
146
});
 
147
 
 
148
 
 
149
/**
 
150
 * @classDescription    Overlay Collection class.
 
151
 * @see                                 Overlay
 
152
 */
 
153
var OverlayCollection = Class.create();
 
154
 
 
155
OverlayCollection.prototype = Object.extend(
 
156
  Object.extend($A([]), new SunViewerWidget()), {
 
157
        
 
158
        /**
 
159
         * @constructor
 
160
         */
 
161
        initialize: function() {
 
162
                this.quadTree = [];
 
163
                this.quadTree.endsHere = true;
 
164
        },
 
165
        
 
166
        /**
 
167
         * @method createOverlay                Creates a new Overlay and adds it to the collection.
 
168
         * @param {String} html                 The HTML code that makes up the overlay.
 
169
         * @param {SunImage} sunImage   The sunImage the overlay belongs to. Set date to null to indicate it belongs to all images.
 
170
         * @param {Hash} options                Available options: position, offset, scaleWhenZooming, scaleFactor, dimensions
 
171
         * @see Overlay
 
172
         */
 
173
        createOverlay: function(html, sunImage, options) {
 
174
                var overlay = new Overlay(html, sunImage, options);
 
175
                this.addOverlay(overlay);
 
176
 
 
177
                // Notify listeners
 
178
                this.notifyListeners('NewOverlay', overlay);
 
179
        },
 
180
        
 
181
        /**
 
182
         * @method getOverlays          Returns the overlays for a tile at the given x and y index and zoom level.
 
183
         *                                                      Utilizes a Quad Tree for storing them in sub-quadrants, so that they can be
 
184
         *                                                      easily retrieved.
 
185
         * @param {Number} xIndex       The x index of the tile.
 
186
         * @param {Number} yIndex       The y index of the tile.
 
187
         * @param {Number} level        The zoom level.
 
188
         * @return {Overlay[]}          An Array of overlays on this tile.
 
189
         */
 
190
        getOverlays: function(xIndex, yIndex, level) {
 
191
                if (level < 0                   // Do not display overlays for zoom levels < 0
 
192
                 || xIndex < 0
 
193
                 || (xIndex > 0 && xIndex >= Math.max(0, 1 << level))
 
194
                 || yIndex < 0
 
195
                 || (yIndex > 0 && yIndex >= Math.max(0, 1 << level)))
 
196
                        return [];
 
197
                
 
198
                var branch = this.quadTree;
 
199
 
 
200
                for(var l = 0; l < level; l++) {
 
201
                        if (branch.endsHere) {
 
202
                                if (branch.length == 0) return [];
 
203
                                // Put all the overlays for this quadrant into their corresponding sub-quadrants
 
204
                                // divide this quadrant into 4 sub-quadrants
 
205
                                var subQuads = [new branchEnd(),new branchEnd(),new branchEnd(),new branchEnd()];
 
206
                                // the position and size of the quadrant
 
207
                                var size = 1 / (1 << l);
 
208
                                var x = (xIndex >> (level - l)) / (1 << l);
 
209
                                var y = (yIndex >> (level - l)) / (1 << l);
 
210
                                // each overlay is put into the corresponding sub-quadrant
 
211
                                branch.each(function(overlay) {
 
212
                                        var q = overlay.getQuadrant(x,y,size);
 
213
                                        subQuads[q].push(overlay);
 
214
                                });
 
215
                                branch.length = 4;
 
216
                                branch[0] = subQuads[0];
 
217
                                branch[1] = subQuads[1];
 
218
                                branch[2] = subQuads[2];
 
219
                                branch[3] = subQuads[3];
 
220
                                // now we have sub-quadrants
 
221
                                branch.endsHere = false;
 
222
                        }
 
223
 
 
224
                        // Determine next quadrant
 
225
                        var quadrant = ((xIndex >> (level - l - 1)) & 1) | ((yIndex >> (level - l - 1) << 1) & 2);
 
226
 
 
227
                        // Step down the Quad-Tree
 
228
                        branch = branch[quadrant];
 
229
                }
 
230
 
 
231
                // Return all the overlays in this quadrant (or its sub-quadrants)
 
232
                return branch.flatten();
 
233
        },
 
234
        
 
235
        /**
 
236
         * @method addOverlay           Adds a new overlay to the collection.
 
237
         *                                                      Also adds it in the correct place in the Quad Tree.
 
238
         * @param {Overlay} overlay     The overlay to add.
 
239
         */
 
240
        addOverlay: function(overlay) {
 
241
                this.push(overlay);
 
242
                var branch = this.quadTree;
 
243
                // Until we reach the end
 
244
                for(l = 0; !branch.endsHere; l++) {
 
245
                        // Determine next quadrant
 
246
                        var quadrant = (overlay.x * (1 << (l + 1)) & 1) | ((overlay.y * (1 << (l + 1)) << 1) & 2);
 
247
                        // Step down the Quad-Tree
 
248
                        branch = branch[quadrant];
 
249
                }
 
250
                // Add the overlay to this branch
 
251
                branch.push(overlay);
 
252
        },
 
253
        
 
254
        /**
 
255
         * @method addOverlays                  Adds a number of overlays to the collection.
 
256
         * @param {Overlay[]} overlays  The overlays to add.
 
257
         * @see OverlayCollection.addOverlays()
 
258
         */
 
259
        addOverlays: function(overlays) {
 
260
                overlays.each(this.addOverlay.bind(this));
 
261
        },
 
262
        
 
263
        /**
 
264
         * @method clear        Removes all overlays from the collection.
 
265
         */
 
266
        clear: function() {
 
267
                this.quadTree = new branchEnd();
 
268
        }
 
269
});
 
 
b'\\ No newline at end of file'