source: Dev/trunk/src/client/dojox/gfx/gradient.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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