gradient.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* eslint-disable */
  2. // 当ctx传入当前文件,const grd = ctx.createCircularGradient() 和
  3. // const grd = this.ctx.createLinearGradient() 无效,因此只能分开处理
  4. // 先分析,在外部创建grd,再传入使用就可以
  5. /**
  6. * 分析渐变字符串,提取颜色和百分比
  7. * @param {string} string - 渐变字符串
  8. * @returns {object} 包含colors和percents的对象
  9. */
  10. function analizeGrad(string) {
  11. const colorPercents = string.substring(0, string.length - 1).split('%,');
  12. const colors = [];
  13. const percents = [];
  14. for (let colorPercent of colorPercents) {
  15. colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(' ')).trim());
  16. percents.push(colorPercent.substring(colorPercent.lastIndexOf(' '), colorPercent.length) / 100);
  17. }
  18. return {
  19. colors: colors,
  20. percents: percents
  21. };
  22. }
  23. /**
  24. * 分析线性渐变的方向参数
  25. * @param {string} bg - 渐变背景字符串
  26. * @param {number} width - 宽度
  27. * @param {number} height - 高度
  28. * @returns {Array} 坐标数组
  29. */
  30. function analizeLinear(bg, width, height) {
  31. const direction = bg.match(/([-]?\d{1,3})deg/);
  32. const dir = direction && direction[1] ? parseFloat(direction[1]) : 0;
  33. let coordinate;
  34. switch (dir) {
  35. case 0:
  36. coordinate = [0, -height / 2, 0, height / 2];
  37. break;
  38. case 90:
  39. coordinate = [width / 2, 0, -width / 2, 0];
  40. break;
  41. case -90:
  42. coordinate = [-width / 2, 0, width / 2, 0];
  43. break;
  44. case 180:
  45. coordinate = [0, height / 2, 0, -height / 2];
  46. break;
  47. case -180:
  48. coordinate = [0, -height / 2, 0, height / 2];
  49. break;
  50. default:
  51. let x1 = 0;
  52. let y1 = 0;
  53. let x2 = 0;
  54. let y2 = 0;
  55. if (direction[1] > 0 && direction[1] < 90) {
  56. x1 =
  57. width / 2 -
  58. (((width / 2) * Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) - height / 2) * Math.sin((2 * (90 - direction[1]) * Math.PI * 2) / 360)) / 2;
  59. y2 = Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) * x1;
  60. x2 = -x1;
  61. y1 = -y2;
  62. } else if (direction[1] > -180 && direction[1] < -90) {
  63. x1 =
  64. -(width / 2) +
  65. (((width / 2) * Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) - height / 2) * Math.sin((2 * (90 - direction[1]) * Math.PI * 2) / 360)) / 2;
  66. y2 = Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) * x1;
  67. x2 = -x1;
  68. y1 = -y2;
  69. } else if (direction[1] > 90 && direction[1] < 180) {
  70. x1 =
  71. width / 2 +
  72. ((-(width / 2) * Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) - height / 2) * Math.sin((2 * (90 - direction[1]) * Math.PI * 2) / 360)) / 2;
  73. y2 = Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) * x1;
  74. x2 = -x1;
  75. y1 = -y2;
  76. } else {
  77. x1 =
  78. -(width / 2) -
  79. ((-(width / 2) * Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) - height / 2) * Math.sin((2 * (90 - direction[1]) * Math.PI * 2) / 360)) / 2;
  80. y2 = Math.tan(((90 - direction[1]) * Math.PI * 2) / 360) * x1;
  81. x2 = -x1;
  82. y1 = -y2;
  83. }
  84. coordinate = [x1, y1, x2, y2];
  85. break;
  86. }
  87. return coordinate;
  88. }
  89. /**
  90. * 创建径向渐变效果
  91. * @param {number} width - 宽度
  92. * @param {number} height - 高度
  93. * @param {string} bg - 渐变背景字符串
  94. * @param {CanvasRenderingContext2D} ctx - Canvas上下文
  95. */
  96. function radialEffect(width, height, bg, ctx) {
  97. const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]);
  98. const grd = ctx.createRadialGradient(0, 0, 0, 0, 0, width < height ? height / 2 : width / 2);
  99. for (let i = 0; i < colorPer.colors.length; i++) {
  100. grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
  101. }
  102. ctx.fillStyle = grd;
  103. //ctx.fillRect(-(width / 2), -(height / 2), width, height);
  104. }
  105. /**
  106. * 创建线性渐变效果
  107. * @param {number} width - 宽度
  108. * @param {number} height - 高度
  109. * @param {string} bg - 渐变背景字符串
  110. * @param {CanvasRenderingContext2D} ctx - Canvas上下文
  111. */
  112. function linearEffect(width, height, bg, ctx) {
  113. const param = analizeLinear(bg, width, height);
  114. const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]);
  115. const content = bg.match(/linear-gradient\((.+)\)/)[1];
  116. const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1));
  117. for (let i = 0; i < colorPer.colors.length; i++) {
  118. grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
  119. }
  120. ctx.fillStyle = grd;
  121. //ctx.fillRect(-(width / 2), -(height / 2), width, height);
  122. }
  123. /**
  124. * 判断是否为渐变背景
  125. * @param {string} bg - 背景字符串
  126. * @returns {boolean} 是否为渐变
  127. */
  128. export function isGradient(bg) {
  129. if (bg && (bg.startsWith('linear') || bg.startsWith('radial'))) {
  130. return true;
  131. }
  132. return false;
  133. }
  134. /**
  135. * 执行渐变效果
  136. * @param {string} bg - 渐变背景字符串
  137. * @param {number} width - 宽度
  138. * @param {number} height - 高度
  139. * @param {CanvasRenderingContext2D} ctx - Canvas上下文
  140. */
  141. export function doGradient(bg, width, height, ctx) {
  142. if (bg.startsWith('linear')) {
  143. linearEffect(width, height, bg, ctx);
  144. } else if (bg.startsWith('radial')) {
  145. radialEffect(width, height, bg, ctx);
  146. }
  147. }