gradient.js 5.2 KB

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