cf7e3f10f7d05b8fc37adfa04b90ea9e9a18e8583cf7444483bbe9ac834e3c02032f7716d01d5b17f8d1949fba84ca0897ae1524fbda238386473cc5556992 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { LinearGradientObject } from '../graphic/LinearGradient';
  2. import { RadialGradientObject } from '../graphic/RadialGradient';
  3. import { GradientObject } from '../graphic/Gradient';
  4. import { RectLike } from '../core/BoundingRect';
  5. import Path from '../graphic/Path';
  6. function isSafeNum(num: number) {
  7. // NaN、Infinity、undefined、'xx'
  8. return isFinite(num);
  9. }
  10. export function createLinearGradient(
  11. this: void,
  12. ctx: CanvasRenderingContext2D,
  13. obj: LinearGradientObject,
  14. rect: RectLike
  15. ) {
  16. let x = obj.x == null ? 0 : obj.x;
  17. let x2 = obj.x2 == null ? 1 : obj.x2;
  18. let y = obj.y == null ? 0 : obj.y;
  19. let y2 = obj.y2 == null ? 0 : obj.y2;
  20. if (!obj.global) {
  21. x = x * rect.width + rect.x;
  22. x2 = x2 * rect.width + rect.x;
  23. y = y * rect.height + rect.y;
  24. y2 = y2 * rect.height + rect.y;
  25. }
  26. // Fix NaN when rect is Infinity
  27. x = isSafeNum(x) ? x : 0;
  28. x2 = isSafeNum(x2) ? x2 : 1;
  29. y = isSafeNum(y) ? y : 0;
  30. y2 = isSafeNum(y2) ? y2 : 0;
  31. const canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
  32. return canvasGradient;
  33. }
  34. export function createRadialGradient(
  35. this: void,
  36. ctx: CanvasRenderingContext2D,
  37. obj: RadialGradientObject,
  38. rect: RectLike
  39. ) {
  40. const width = rect.width;
  41. const height = rect.height;
  42. const min = Math.min(width, height);
  43. let x = obj.x == null ? 0.5 : obj.x;
  44. let y = obj.y == null ? 0.5 : obj.y;
  45. let r = obj.r == null ? 0.5 : obj.r;
  46. if (!obj.global) {
  47. x = x * width + rect.x;
  48. y = y * height + rect.y;
  49. r = r * min;
  50. }
  51. x = isSafeNum(x) ? x : 0.5;
  52. y = isSafeNum(y) ? y : 0.5;
  53. r = r >= 0 && isSafeNum(r) ? r : 0.5;
  54. const canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
  55. return canvasGradient;
  56. }
  57. export function getCanvasGradient(this: void, ctx: CanvasRenderingContext2D, obj: GradientObject, rect: RectLike) {
  58. // TODO Cache?
  59. const canvasGradient = obj.type === 'radial'
  60. ? createRadialGradient(ctx, obj as RadialGradientObject, rect)
  61. : createLinearGradient(ctx, obj as LinearGradientObject, rect);
  62. const colorStops = obj.colorStops;
  63. for (let i = 0; i < colorStops.length; i++) {
  64. canvasGradient.addColorStop(
  65. colorStops[i].offset, colorStops[i].color
  66. );
  67. }
  68. return canvasGradient;
  69. }
  70. export function isClipPathChanged(clipPaths: Path[], prevClipPaths: Path[]): boolean {
  71. // displayable.__clipPaths can only be `null`/`undefined` or an non-empty array.
  72. if (clipPaths === prevClipPaths || (!clipPaths && !prevClipPaths)) {
  73. return false;
  74. }
  75. if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {
  76. return true;
  77. }
  78. for (let i = 0; i < clipPaths.length; i++) {
  79. if (clipPaths[i] !== prevClipPaths[i]) {
  80. return true;
  81. }
  82. }
  83. return false;
  84. }
  85. function parseInt10(val: string) {
  86. return parseInt(val, 10);
  87. }
  88. export function getSize(
  89. root: HTMLElement,
  90. whIdx: number,
  91. opts: { width?: number | string, height?: number | string}
  92. ) {
  93. const wh = ['width', 'height'][whIdx] as 'width' | 'height';
  94. const cwh = ['clientWidth', 'clientHeight'][whIdx] as 'clientWidth' | 'clientHeight';
  95. const plt = ['paddingLeft', 'paddingTop'][whIdx] as 'paddingLeft' | 'paddingTop';
  96. const prb = ['paddingRight', 'paddingBottom'][whIdx] as 'paddingRight' | 'paddingBottom';
  97. if (opts[wh] != null && opts[wh] !== 'auto') {
  98. return parseFloat(opts[wh] as string);
  99. }
  100. // IE8 does not support getComputedStyle, but it use VML.
  101. const stl = document.defaultView.getComputedStyle(root);
  102. return (
  103. (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))
  104. - (parseInt10(stl[plt]) || 0)
  105. - (parseInt10(stl[prb]) || 0)
  106. ) | 0;
  107. }