liquid.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.addWaterWave = void 0;
  4. var tslib_1 = require("tslib");
  5. var g2_1 = require("@antv/g2");
  6. var util_1 = require("@antv/util");
  7. var matrix_1 = require("../../../utils/matrix");
  8. var DURATION = 5000;
  9. /**
  10. * 一个线性映射的函数
  11. * @param min
  12. * @param max
  13. * @param factor
  14. */
  15. function lerp(min, max, factor) {
  16. return min + (max - min) * factor;
  17. }
  18. /**
  19. * 波浪的 attrs
  20. * @param cfg
  21. */
  22. function getFillAttrs(cfg) {
  23. var attrs = tslib_1.__assign({ opacity: 1 }, cfg.style);
  24. if (cfg.color && !attrs.fill) {
  25. attrs.fill = cfg.color;
  26. }
  27. return attrs;
  28. }
  29. /**
  30. * shape 的 attrs
  31. * @param cfg
  32. */
  33. function getLineAttrs(cfg) {
  34. var defaultAttrs = {
  35. fill: '#fff',
  36. fillOpacity: 0,
  37. lineWidth: 4,
  38. };
  39. var attrs = (0, util_1.mix)({}, defaultAttrs, cfg.style);
  40. if (cfg.color && !attrs.stroke) {
  41. attrs.stroke = cfg.color;
  42. }
  43. if ((0, util_1.isNumber)(cfg.opacity)) {
  44. attrs.opacity = attrs.strokeOpacity = cfg.opacity;
  45. }
  46. return attrs;
  47. }
  48. /**
  49. * 用贝塞尔曲线模拟正弦波
  50. * Using Bezier curves to fit sine wave.
  51. * There is 4 control points for each curve of wave,
  52. * which is at 1/4 wave length of the sine wave.
  53. *
  54. * The control points for a wave from (a) to (d) are a-b-c-d:
  55. * c *----* d
  56. * b *
  57. * |
  58. * ... a * ..................
  59. *
  60. * whose positions are a: (0, 0), b: (0.5, 0.5), c: (1, 1), d: (PI / 2, 1)
  61. *
  62. * @param x x position of the left-most point (a)
  63. * @param stage 0-3, stating which part of the wave it is
  64. * @param waveLength wave length of the sine wave
  65. * @param amplitude wave amplitude
  66. * @return 正弦片段曲线
  67. */
  68. function getWaterWavePositions(x, stage, waveLength, amplitude) {
  69. if (stage === 0) {
  70. return [
  71. [x + ((1 / 2) * waveLength) / Math.PI / 2, amplitude / 2],
  72. [x + ((1 / 2) * waveLength) / Math.PI, amplitude],
  73. [x + waveLength / 4, amplitude],
  74. ];
  75. }
  76. if (stage === 1) {
  77. return [
  78. [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 2), amplitude],
  79. [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 1), amplitude / 2],
  80. [x + waveLength / 4, 0],
  81. ];
  82. }
  83. if (stage === 2) {
  84. return [
  85. [x + ((1 / 2) * waveLength) / Math.PI / 2, -amplitude / 2],
  86. [x + ((1 / 2) * waveLength) / Math.PI, -amplitude],
  87. [x + waveLength / 4, -amplitude],
  88. ];
  89. }
  90. return [
  91. [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 2), -amplitude],
  92. [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 1), -amplitude / 2],
  93. [x + waveLength / 4, 0],
  94. ];
  95. }
  96. /**
  97. * 获取水波路径
  98. * @param radius 半径
  99. * @param waterLevel 水位
  100. * @param waveLength 波长
  101. * @param phase 相位
  102. * @param amplitude 震幅
  103. * @param cx 圆心x
  104. * @param cy 圆心y
  105. * @return path 路径
  106. * @reference http://gitlab.alipay-inc.com/datavis/g6/blob/1.2.0/src/graph/utils/path.js#L135
  107. */
  108. function getWaterWavePath(radius, waterLevel, waveLength, phase, amplitude, cx, cy) {
  109. var curves = Math.ceil(((2 * radius) / waveLength) * 4) * 4;
  110. var path = [];
  111. var _phase = phase;
  112. // map phase to [-Math.PI * 2, 0]
  113. while (_phase < -Math.PI * 2) {
  114. _phase += Math.PI * 2;
  115. }
  116. while (_phase > 0) {
  117. _phase -= Math.PI * 2;
  118. }
  119. _phase = (_phase / Math.PI / 2) * waveLength;
  120. var left = cx - radius + _phase - radius * 2;
  121. /**
  122. * top-left corner as start point
  123. *
  124. * draws this point
  125. * |
  126. * \|/
  127. * ~~~~~~~~
  128. * | |
  129. * +------+
  130. */
  131. path.push(['M', left, waterLevel]);
  132. /**
  133. * top wave
  134. *
  135. * ~~~~~~~~ <- draws this sine wave
  136. * | |
  137. * +------+
  138. */
  139. var waveRight = 0;
  140. for (var c = 0; c < curves; ++c) {
  141. var stage = c % 4;
  142. var pos = getWaterWavePositions((c * waveLength) / 4, stage, waveLength, amplitude);
  143. path.push([
  144. 'C',
  145. pos[0][0] + left,
  146. -pos[0][1] + waterLevel,
  147. pos[1][0] + left,
  148. -pos[1][1] + waterLevel,
  149. pos[2][0] + left,
  150. -pos[2][1] + waterLevel,
  151. ]);
  152. if (c === curves - 1) {
  153. waveRight = pos[2][0];
  154. }
  155. }
  156. /**
  157. * top-right corner
  158. *
  159. * ~~~~~~~~
  160. * 3. draws this line -> | | <- 1. draws this line
  161. * +------+
  162. * ^
  163. * |
  164. * 2. draws this line
  165. */
  166. path.push(['L', waveRight + left, cy + radius]);
  167. path.push(['L', left, cy + radius]);
  168. path.push(['Z']);
  169. // path.push(['L', left, waterLevel]);
  170. return path;
  171. }
  172. /**
  173. * 添加水波
  174. * @param x 中心x
  175. * @param y 中心y
  176. * @param level 水位等级 0~1
  177. * @param waveCount 水波数
  178. * @param waveAttrs 色值
  179. * @param group 图组
  180. * @param clip 用于剪切的图形
  181. * @param radius 绘制图形的高度
  182. * @param waveLength 波的长度
  183. */
  184. function addWaterWave(x, y, level, waveCount, waveAttrs, group, clip, radius, waveLength, animation) {
  185. // 盒子属性 颜色 宽高
  186. var fill = waveAttrs.fill, opacity = waveAttrs.opacity;
  187. var bbox = clip.getBBox();
  188. var width = bbox.maxX - bbox.minX;
  189. var height = bbox.maxY - bbox.minY;
  190. // 循环 waveCount 个数
  191. for (var idx = 0; idx < waveCount; idx++) {
  192. var factor = waveCount <= 1 ? 1 : idx / (waveCount - 1);
  193. // 画波
  194. var wave = group.addShape('path', {
  195. name: "waterwave-path",
  196. attrs: {
  197. // 波形路径配置
  198. path: getWaterWavePath(radius, bbox.minY + height * level, waveLength, 0, width / 32, // 波幅高度
  199. x, y),
  200. fill: fill,
  201. opacity: lerp(0.2, 0.9, factor) * opacity,
  202. },
  203. });
  204. try {
  205. // 默认 underfind 开启动画
  206. if (animation === false)
  207. return;
  208. var matrix = (0, matrix_1.transform)([['t', waveLength, 0]]);
  209. wave.stopAnimate();
  210. wave.animate({ matrix: matrix }, {
  211. duration: lerp(0.5 * DURATION, DURATION, factor),
  212. repeat: true,
  213. });
  214. }
  215. catch (e) {
  216. // TODO off-screen canvas 中动画会找不到 canvas
  217. console.warn('off-screen group animate error!');
  218. }
  219. }
  220. }
  221. exports.addWaterWave = addWaterWave;
  222. /**
  223. *
  224. * @param x 中心 x
  225. * @param y 中心 y
  226. * @param width 外接矩形的宽
  227. * @param height 外接矩形的高
  228. */
  229. function pin(x, y, width, height) {
  230. var w = (width * 2) / 3;
  231. var h = Math.max(w, height);
  232. var r = w / 2;
  233. // attrs of the upper circle
  234. var cx = x;
  235. var cy = r + y - h / 2;
  236. var theta = Math.asin(r / ((h - r) * 0.85));
  237. var dy = Math.sin(theta) * r;
  238. var dx = Math.cos(theta) * r;
  239. // the start point of the path
  240. var x0 = cx - dx;
  241. var y0 = cy + dy;
  242. // control point
  243. var cpX = x;
  244. var cpY = cy + r / Math.sin(theta);
  245. return "\n M ".concat(x0, " ").concat(y0, "\n A ").concat(r, " ").concat(r, " 0 1 1 ").concat(x0 + dx * 2, " ").concat(y0, "\n Q ").concat(cpX, " ").concat(cpY, " ").concat(x, " ").concat(y + h / 2, "\n Q ").concat(cpX, " ").concat(cpY, " ").concat(x0, " ").concat(y0, "\n Z \n ");
  246. }
  247. /**
  248. *
  249. * @param x 中心 x
  250. * @param y 中心 y
  251. * @param width 外接矩形的宽
  252. * @param height 外接矩形的高
  253. */
  254. function circle(x, y, width, height) {
  255. var rx = width / 2;
  256. var ry = height / 2;
  257. return "\n M ".concat(x, " ").concat(y - ry, " \n a ").concat(rx, " ").concat(ry, " 0 1 0 0 ").concat(ry * 2, "\n a ").concat(rx, " ").concat(ry, " 0 1 0 0 ").concat(-ry * 2, "\n Z\n ");
  258. }
  259. /**
  260. *
  261. * @param x 中心 x
  262. * @param y 中心 y
  263. * @param width 外接矩形的宽
  264. * @param height 外接矩形的高
  265. */
  266. function diamond(x, y, width, height) {
  267. var h = height / 2;
  268. var w = width / 2;
  269. return "\n M ".concat(x, " ").concat(y - h, "\n L ").concat(x + w, " ").concat(y, "\n L ").concat(x, " ").concat(y + h, "\n L ").concat(x - w, " ").concat(y, "\n Z\n ");
  270. }
  271. /**
  272. *
  273. * @param x 中心 x
  274. * @param y 中心 y
  275. * @param width 外接矩形的宽
  276. * @param height 外接矩形的高
  277. */
  278. function triangle(x, y, width, height) {
  279. var h = height / 2;
  280. var w = width / 2;
  281. return "\n M ".concat(x, " ").concat(y - h, "\n L ").concat(x + w, " ").concat(y + h, "\n L ").concat(x - w, " ").concat(y + h, "\n Z\n ");
  282. }
  283. /**
  284. *
  285. * @param x 中心 x
  286. * @param y 中心 y
  287. * @param width 外接矩形的宽
  288. * @param height 外接矩形的高
  289. */
  290. function rect(x, y, width, height) {
  291. var GOLDEN_SECTION_RATIO = 0.618;
  292. var h = height / 2;
  293. var w = (width / 2) * GOLDEN_SECTION_RATIO;
  294. return "\n M ".concat(x - w, " ").concat(y - h, "\n L ").concat(x + w, " ").concat(y - h, "\n L ").concat(x + w, " ").concat(y + h, "\n L ").concat(x - w, " ").concat(y + h, "\n Z\n ");
  295. }
  296. var builtInShapeByName = {
  297. pin: pin,
  298. circle: circle,
  299. diamond: diamond,
  300. triangle: triangle,
  301. rect: rect,
  302. };
  303. (0, g2_1.registerShape)('interval', 'liquid-fill-gauge', {
  304. draw: function (cfg, container) {
  305. var cx = 0.5;
  306. var cy = 0.5;
  307. var customInfo = cfg.customInfo;
  308. var _a = customInfo, percent = _a.percent, radio = _a.radius, shape = _a.shape, shapeStyle = _a.shapeStyle, background = _a.background, animation = _a.animation;
  309. var outline = customInfo.outline;
  310. var wave = customInfo.wave;
  311. var border = outline.border, distance = outline.distance;
  312. var waveCount = wave.count, waveLength = wave.length;
  313. // 获取最小 minX
  314. var minX = (0, util_1.reduce)(cfg.points, function (r, p) {
  315. return Math.min(r, p.x);
  316. }, Infinity);
  317. var center = this.parsePoint({ x: cx, y: cy });
  318. var minXPoint = this.parsePoint({ x: minX, y: cy });
  319. var halfWidth = center.x - minXPoint.x;
  320. // 保证半径是 画布宽高最小值的 radius 值
  321. var radius = Math.min(halfWidth, minXPoint.y * radio);
  322. var waveAttrs = getFillAttrs(cfg);
  323. var outlineAttrs = getLineAttrs((0, util_1.mix)({}, cfg, outline));
  324. var innerRadius = radius - border / 2;
  325. var buildPath = typeof shape === 'function' ? shape : builtInShapeByName[shape] || builtInShapeByName['circle'];
  326. var shapePath = buildPath(center.x, center.y, innerRadius * 2, innerRadius * 2);
  327. // 1. 当 shapeStyle 不为空时,绘制形状样式作为背景
  328. if (shapeStyle) {
  329. container.addShape('path', {
  330. name: 'shape',
  331. attrs: tslib_1.__assign({ path: shapePath }, shapeStyle),
  332. });
  333. }
  334. // 比例大于 0 时才绘制水波
  335. if (percent > 0) {
  336. // 2. 绘制一个波
  337. var waves = container.addGroup({
  338. name: 'waves',
  339. });
  340. // 3. 波对应的 clip 裁剪形状
  341. var clipPath = waves.setClip({
  342. type: 'path',
  343. attrs: {
  344. path: shapePath,
  345. },
  346. });
  347. // 4. 绘制波形
  348. addWaterWave(center.x, center.y, 1 - cfg.points[1].y, waveCount, waveAttrs, waves, clipPath, radius * 2, waveLength, animation);
  349. }
  350. // 5. 绘制一个 distance 宽的 border
  351. container.addShape('path', {
  352. name: 'distance',
  353. attrs: {
  354. path: shapePath,
  355. fill: 'transparent',
  356. lineWidth: border + distance * 2,
  357. stroke: background === 'transparent' ? '#fff' : background,
  358. },
  359. });
  360. // 6. 绘制一个 border 宽的 border
  361. container.addShape('path', {
  362. name: 'wrap',
  363. attrs: (0, util_1.mix)(outlineAttrs, {
  364. path: shapePath,
  365. fill: 'transparent',
  366. lineWidth: border,
  367. }),
  368. });
  369. return container;
  370. },
  371. });
  372. //# sourceMappingURL=liquid.js.map