source: Dev/branches/rest-dojo-ui/client/dojox/gfx/gradient.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 4.9 KB
Line 
1define(["dojo/_base/lang", "./matrix", "dojo/_base/Color"],
2  function(lang, m, Color){
3// Various utilities to deal with a linear gradient (mostly VML-specific)
4        var grad = lang.getObject("dojox.gfx.gradient", true);
5        var C = Color;
6        /*===== grad = dojox.gfx.gradient;  =====*/
7       
8        grad.rescale = function(stops, from, to){
9                // summary:
10                //              Recalculates a gradient from 0-1 window to
11                //              "from"-"to" window blending and replicating colors,
12                //              if necessary.
13                // stops: Array
14                //              input gradient as a list of colors with offsets
15                //              (see dojox.gfx.defaultLinearGradient and dojox.gfx.defaultRadialGradient)
16                // from: Number
17                //              the beginning of the window, should be less than "to"
18                // to: Number
19                //              the end of the window, should be more than "from"
20
21                var len = stops.length, reverseFlag = (to < from), newStops;
22
23                // do we need to reverse the color table?
24                if(reverseFlag){
25                        var tmp = from;
26                        from = to;
27                        to = tmp;
28                }
29               
30                // various edge cases
31                if(!len){
32                        // no colors
33                        return [];
34                }
35                if(to <= stops[0].offset){
36                        // all colors are before the color table
37                        newStops = [
38                                {offset: 0, color: stops[0].color},
39                                {offset: 1, color: stops[0].color}
40                        ];
41                }else if(from >= stops[len - 1].offset){
42                        // all colors are after the color table
43                        newStops = [
44                                {offset: 0, color: stops[len - 1].color},
45                                {offset: 1, color: stops[len - 1].color}
46                        ];
47                }else{
48                        // main scanning algorithm
49                        var span = to - from, stop, prev, i;
50                        newStops = [];
51                        if(from < 0){
52                                newStops.push({offset: 0, color: new C(stops[0].color)});
53                        }
54                        for(i = 0; i < len; ++i){
55                                stop = stops[i];
56                                if(stop.offset >= from){
57                                        break;
58                                }
59                                // skip this color
60                        }
61                        if(i){
62                                prev = stops[i - 1];
63                                newStops.push({
64                                        offset: 0,
65                                        color: Color.blendColors(new C(prev.color), new C(stop.color), (from - prev.offset) / (stop.offset - prev.offset))
66                                });
67                        }else{
68                                newStops.push({offset: 0, color: new C(stop.color)});
69                        }
70                        for(; i < len; ++i){
71                                stop = stops[i];
72                                if(stop.offset >= to){
73                                        break;
74                                }
75                                newStops.push({offset: (stop.offset - from) / span, color: new C(stop.color)});
76                        }
77                        if(i < len){
78                                prev = stops[i - 1];
79                                newStops.push({
80                                        offset: 1,
81                                        color: Color.blendColors(new C(prev.color), new C(stop.color), (to - prev.offset) / (stop.offset - prev.offset))
82                                });
83                        }else{
84                                newStops.push({offset: 1, color: new C(stops[len - 1].color)});
85                        }
86                }
87               
88                // reverse the color table, if needed
89                if(reverseFlag){
90                        newStops.reverse();
91                        for(i = 0, len = newStops.length; i < len; ++i){
92                                stop = newStops[i];
93                                stop.offset = 1 - stop.offset;
94                        }
95                }
96               
97                return newStops;
98        };
99       
100        function getPoint(x, y, matrix, project, shiftAndRotate, scale){
101                var r = m.multiplyPoint(matrix, x, y),
102                        p = m.multiplyPoint(project, r);
103                return {r: r, p: p, o: m.multiplyPoint(shiftAndRotate, p).x / scale};
104        }
105       
106        function sortPoints(a, b){
107                return a.o - b.o;
108        }
109       
110        grad.project = function(matrix, gradient, tl, rb, ttl, trb){
111                // summary:
112                //              Returns a new gradient using the "VML algorithm" and suitable for VML.
113                // matrix: dojox.gfx.Matrix2D|Null:
114                //              matrix to apply to a shape and its gradient
115                // gradient: Object:
116                //              a linear gradient object to be transformed
117                // tl: dojox.gfx.Point:
118                //              top-left corner of shape's bounding box
119                // rb: dojox.gfx.Point:
120                //              right-bottom corner of shape's bounding box
121                // ttl: dojox.gfx.Point:
122                //              top-left corner of shape's transformed bounding box
123                // trb: dojox.gfx.Point:
124                //              right-bottom corner of shape's transformed bounding box
125               
126                matrix = matrix || m.identity;
127
128                var f1 = m.multiplyPoint(matrix, gradient.x1, gradient.y1),
129                        f2 = m.multiplyPoint(matrix, gradient.x2, gradient.y2),
130                        angle = Math.atan2(f2.y - f1.y, f2.x - f1.x),
131                        project = m.project(f2.x - f1.x, f2.y - f1.y),
132                        pf1 = m.multiplyPoint(project, f1),
133                        pf2 = m.multiplyPoint(project, f2),
134                        shiftAndRotate = new m.Matrix2D([m.rotate(-angle), {dx: -pf1.x, dy: -pf1.y}]),
135                        scale = m.multiplyPoint(shiftAndRotate, pf2).x,
136                        //comboMatrix = new m.Matrix2D([shiftAndRotate, project, matrix]),
137                        // bbox-specific calculations
138                        points = [
139                                        getPoint(tl.x, tl.y, matrix, project, shiftAndRotate, scale),
140                                        getPoint(rb.x, rb.y, matrix, project, shiftAndRotate, scale),
141                                        getPoint(tl.x, rb.y, matrix, project, shiftAndRotate, scale),
142                                        getPoint(rb.x, tl.y, matrix, project, shiftAndRotate, scale)
143                                ].sort(sortPoints),
144                        from = points[0].o,
145                        to   = points[3].o,
146                        stops = grad.rescale(gradient.colors, from, to),
147                        //angle2 = Math.atan2(Math.abs(points[3].r.y - points[0].r.y) * (f2.y - f1.y), Math.abs(points[3].r.x - points[0].r.x) * (f2.x - f1.x));
148                        angle2 = Math.atan2(points[3].r.y - points[0].r.y, points[3].r.x - points[0].r.x);
149
150                return {
151                        type: "linear",
152                        x1: points[0].p.x, y1: points[0].p.y, x2: points[3].p.x, y2: points[3].p.y,
153                        colors: stops,
154                        // additional helpers (for VML)
155                        angle: angle
156                };
157        };
158       
159        return grad;
160});
Note: See TracBrowser for help on using the repository browser.