Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
/* Flot plugin for plotting images.
2
 
3
Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
Licensed under the MIT license.
5
 
6
The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and
7
(x2, y2) are where you intend the two opposite corners of the image to end up
8
in the plot. Image must be a fully loaded Javascript image (you can make one
9
with new Image()). If the image is not complete, it's skipped when plotting.
10
 
11
There are two helpers included for retrieving images. The easiest work the way
12
that you put in URLs instead of images in the data, like this:
13
 
14
        [ "myimage.png", 0, 0, 10, 10 ]
15
 
16
Then call $.plot.image.loadData( data, options, callback ) where data and
17
options are the same as you pass in to $.plot. This loads the images, replaces
18
the URLs in the data with the corresponding images and calls "callback" when
19
all images are loaded (or failed loading). In the callback, you can then call
20
$.plot with the data set. See the included example.
21
 
22
A more low-level helper, $.plot.image.load(urls, callback) is also included.
23
Given a list of URLs, it calls callback with an object mapping from URL to
24
Image object when all images are loaded or have failed loading.
25
 
26
The plugin supports these options:
27
 
28
        series: {
29
                images: {
30
                        show: boolean
31
                        anchor: "corner" or "center"
32
                        alpha: [ 0, 1 ]
33
                }
34
        }
35
 
36
They can be specified for a specific series:
37
 
38
        $.plot( $("#placeholder"), [{
39
                data: [ ... ],
40
                images: { ... }
41
        ])
42
 
43
Note that because the data format is different from usual data points, you
44
can't use images with anything else in a specific data series.
45
 
46
Setting "anchor" to "center" causes the pixels in the image to be anchored at
47
the corner pixel centers inside of at the pixel corners, effectively letting
48
half a pixel stick out to each side in the plot.
49
 
50
A possible future direction could be support for tiling for large images (like
51
Google Maps).
52
 
53
*/
54
 
55
(function ($) {
56
    var options = {
57
        series: {
58
            images: {
59
                show: false,
60
                alpha: 1,
61
                anchor: "corner" // or "center"
62
            }
63
        }
64
    };
65
 
66
    $.plot.image = {};
67
 
68
    $.plot.image.loadDataImages = function (series, options, callback) {
69
        var urls = [], points = [];
70
 
71
        var defaultShow = options.series.images.show;
72
 
73
        $.each(series, function (i, s) {
74
            if (!(defaultShow || s.images.show))
75
                return;
76
 
77
            if (s.data)
78
                s = s.data;
79
 
80
            $.each(s, function (i, p) {
81
                if (typeof p[0] == "string") {
82
                    urls.push(p[0]);
83
                    points.push(p);
84
                }
85
            });
86
        });
87
 
88
        $.plot.image.load(urls, function (loadedImages) {
89
            $.each(points, function (i, p) {
90
                var url = p[0];
91
                if (loadedImages[url])
92
                    p[0] = loadedImages[url];
93
            });
94
 
95
            callback();
96
        });
97
    }
98
 
99
    $.plot.image.load = function (urls, callback) {
100
        var missing = urls.length, loaded = {};
101
        if (missing == 0)
102
            callback({});
103
 
104
        $.each(urls, function (i, url) {
105
            var handler = function () {
106
                --missing;
107
 
108
                loaded[url] = this;
109
 
110
                if (missing == 0)
111
                    callback(loaded);
112
            };
113
 
114
            $('<img />').load(handler).error(handler).attr('src', url);
115
        });
116
    };
117
 
118
    function drawSeries(plot, ctx, series) {
119
        var plotOffset = plot.getPlotOffset();
120
 
121
        if (!series.images || !series.images.show)
122
            return;
123
 
124
        var points = series.datapoints.points,
125
            ps = series.datapoints.pointsize;
126
 
127
        for (var i = 0; i < points.length; i += ps) {
128
            var img = points[i],
129
                x1 = points[i + 1], y1 = points[i + 2],
130
                x2 = points[i + 3], y2 = points[i + 4],
131
                xaxis = series.xaxis, yaxis = series.yaxis,
132
                tmp;
133
 
134
            // actually we should check img.complete, but it
135
            // appears to be a somewhat unreliable indicator in
136
            // IE6 (false even after load event)
137
            if (!img || img.width <= 0 || img.height <= 0)
138
                continue;
139
 
140
            if (x1 > x2) {
141
                tmp = x2;
142
                x2 = x1;
143
                x1 = tmp;
144
            }
145
            if (y1 > y2) {
146
                tmp = y2;
147
                y2 = y1;
148
                y1 = tmp;
149
            }
150
 
151
            // if the anchor is at the center of the pixel, expand the 
152
            // image by 1/2 pixel in each direction
153
            if (series.images.anchor == "center") {
154
                tmp = 0.5 * (x2-x1) / (img.width - 1);
155
                x1 -= tmp;
156
                x2 += tmp;
157
                tmp = 0.5 * (y2-y1) / (img.height - 1);
158
                y1 -= tmp;
159
                y2 += tmp;
160
            }
161
 
162
            // clip
163
            if (x1 == x2 || y1 == y2 ||
164
                x1 >= xaxis.max || x2 <= xaxis.min ||
165
                y1 >= yaxis.max || y2 <= yaxis.min)
166
                continue;
167
 
168
            var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
169
            if (x1 < xaxis.min) {
170
                sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
171
                x1 = xaxis.min;
172
            }
173
 
174
            if (x2 > xaxis.max) {
175
                sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
176
                x2 = xaxis.max;
177
            }
178
 
179
            if (y1 < yaxis.min) {
180
                sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
181
                y1 = yaxis.min;
182
            }
183
 
184
            if (y2 > yaxis.max) {
185
                sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
186
                y2 = yaxis.max;
187
            }
188
 
189
            x1 = xaxis.p2c(x1);
190
            x2 = xaxis.p2c(x2);
191
            y1 = yaxis.p2c(y1);
192
            y2 = yaxis.p2c(y2);
193
 
194
            // the transformation may have swapped us
195
            if (x1 > x2) {
196
                tmp = x2;
197
                x2 = x1;
198
                x1 = tmp;
199
            }
200
            if (y1 > y2) {
201
                tmp = y2;
202
                y2 = y1;
203
                y1 = tmp;
204
            }
205
 
206
            tmp = ctx.globalAlpha;
207
            ctx.globalAlpha *= series.images.alpha;
208
            ctx.drawImage(img,
209
                          sx1, sy1, sx2 - sx1, sy2 - sy1,
210
                          x1 + plotOffset.left, y1 + plotOffset.top,
211
                          x2 - x1, y2 - y1);
212
            ctx.globalAlpha = tmp;
213
        }
214
    }
215
 
216
    function processRawData(plot, series, data, datapoints) {
217
        if (!series.images.show)
218
            return;
219
 
220
        // format is Image, x1, y1, x2, y2 (opposite corners)
221
        datapoints.format = [
222
            { required: true },
223
            { x: true, number: true, required: true },
224
            { y: true, number: true, required: true },
225
            { x: true, number: true, required: true },
226
            { y: true, number: true, required: true }
227
        ];
228
    }
229
 
230
    function init(plot) {
231
        plot.hooks.processRawData.push(processRawData);
232
        plot.hooks.drawSeries.push(drawSeries);
233
    }
234
 
235
    $.plot.plugins.push({
236
        init: init,
237
        options: options,
238
        name: 'image',
239
        version: '1.1'
240
    });
241
})(jQuery);