facetRect.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. "use strict";
  2. var __rest = (this && this.__rest) || function (s, e) {
  3. var t = {};
  4. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  5. t[p] = s[p];
  6. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  7. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  8. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  9. t[p[i]] = s[p[i]];
  10. }
  11. return t;
  12. };
  13. Object.defineProperty(exports, "__esModule", { value: true });
  14. exports.FacetRect = exports.createInnerGuide = exports.setChildren = exports.setData = exports.toCell = exports.setStyle = exports.setAnimation = exports.inferColor = void 0;
  15. const util_1 = require("@antv/util");
  16. const d3_array_1 = require("d3-array");
  17. const vector_1 = require("../utils/vector");
  18. const container_1 = require("../utils/container");
  19. const array_1 = require("../utils/array");
  20. const utils_1 = require("./utils");
  21. const setScale = (0, utils_1.useDefaultAdaptor)((options) => {
  22. const { encode, data, scale, shareSize = false } = options;
  23. const { x, y } = encode;
  24. const flexDomain = (encode, channel) => {
  25. var _a;
  26. if (encode === undefined || !shareSize)
  27. return {};
  28. const groups = (0, d3_array_1.group)(data, (d) => d[encode]);
  29. const domain = ((_a = scale === null || scale === void 0 ? void 0 : scale[channel]) === null || _a === void 0 ? void 0 : _a.domain) || Array.from(groups.keys());
  30. const flex = domain.map((key) => {
  31. if (!groups.has(key))
  32. return 1;
  33. return groups.get(key).length;
  34. });
  35. return { domain, flex };
  36. };
  37. return {
  38. scale: {
  39. x: Object.assign(Object.assign({ paddingOuter: 0, paddingInner: 0.1, guide: x === undefined ? null : { position: 'top' } }, (x === undefined && { paddingInner: 0 })), flexDomain(x, 'x')),
  40. y: Object.assign(Object.assign({ range: [0, 1], paddingOuter: 0, paddingInner: 0.1, guide: y === undefined ? null : { position: 'right' } }, (y === undefined && { paddingInner: 0 })), flexDomain(y, 'y')),
  41. },
  42. };
  43. });
  44. /**
  45. * BFS view tree and using the last discovered color encode
  46. * as the top-level encode for this plot. This is useful when
  47. * color encode and color scale is specified in mark node.
  48. * It makes sense because the whole facet should shared the same
  49. * color encoding, but it also can be override with explicity
  50. * encode and scale specification.
  51. */
  52. exports.inferColor = (0, utils_1.useDefaultAdaptor)((options) => {
  53. const { data, scale } = options;
  54. const discovered = [options];
  55. let encodeColor;
  56. let scaleColor;
  57. let legendColor;
  58. while (discovered.length) {
  59. const node = discovered.shift();
  60. const { children, encode = {}, scale = {}, legend = {} } = node;
  61. const { color: c } = encode;
  62. const { color: cs } = scale;
  63. const { color: cl } = legend;
  64. if (c !== undefined)
  65. encodeColor = c;
  66. if (cs !== undefined)
  67. scaleColor = cs;
  68. if (cl !== undefined)
  69. legendColor = cl;
  70. if (Array.isArray(children)) {
  71. discovered.push(...children);
  72. }
  73. }
  74. const domainColor = () => {
  75. var _a;
  76. const domain = (_a = scale === null || scale === void 0 ? void 0 : scale.color) === null || _a === void 0 ? void 0 : _a.domain;
  77. if (domain !== undefined)
  78. return [domain];
  79. if (encodeColor === undefined)
  80. return [undefined];
  81. const color = typeof encodeColor === 'function' ? encodeColor : (d) => d[encodeColor];
  82. const values = data.map(color);
  83. if (values.some((d) => typeof d === 'number'))
  84. return [(0, d3_array_1.extent)(values)];
  85. return [Array.from(new Set(values)), 'ordinal'];
  86. };
  87. const title = typeof encodeColor === 'string' ? encodeColor : '';
  88. const [domain, type] = domainColor();
  89. return {
  90. encode: { color: encodeColor },
  91. scale: { color: (0, util_1.deepMix)({}, scaleColor, { domain, type }) },
  92. legend: { color: (0, util_1.deepMix)({ title }, legendColor) },
  93. };
  94. });
  95. exports.setAnimation = (0, utils_1.useDefaultAdaptor)(() => ({
  96. animate: {
  97. enterType: 'fadeIn',
  98. },
  99. }));
  100. exports.setStyle = (0, utils_1.useOverrideAdaptor)(() => ({
  101. frame: false,
  102. encode: {
  103. shape: 'hollow',
  104. },
  105. style: {
  106. lineWidth: 0,
  107. },
  108. }));
  109. exports.toCell = (0, utils_1.useOverrideAdaptor)(() => ({
  110. type: 'cell',
  111. }));
  112. /**
  113. * Do not set cell data directly, the children will get wrong do if do
  114. * so. Use transform to set new data.
  115. **/
  116. exports.setData = (0, utils_1.useOverrideAdaptor)((options) => {
  117. const { data } = options;
  118. const connector = {
  119. type: 'custom',
  120. callback: () => {
  121. const { data, encode } = options;
  122. const { x, y } = encode;
  123. const X = x ? Array.from(new Set(data.map((d) => d[x]))) : [];
  124. const Y = y ? Array.from(new Set(data.map((d) => d[y]))) : [];
  125. const cellData = () => {
  126. if (X.length && Y.length) {
  127. const cellData = [];
  128. for (const vx of X) {
  129. for (const vy of Y) {
  130. cellData.push({ [x]: vx, [y]: vy });
  131. }
  132. }
  133. return cellData;
  134. }
  135. if (X.length)
  136. return X.map((d) => ({ [x]: d }));
  137. if (Y.length)
  138. return Y.map((d) => ({ [y]: d }));
  139. };
  140. return cellData();
  141. },
  142. };
  143. return {
  144. data: { type: 'inline', value: data, transform: [connector] },
  145. };
  146. });
  147. /**
  148. * @todo Move some options assignment to runtime.
  149. */
  150. exports.setChildren = (0, utils_1.useOverrideAdaptor)((options, subLayout = subLayoutRect, createGuideX = createGuideXRect, createGuideY = createGuideYRect, childOptions = {}) => {
  151. const { data: dataValue, encode, children, scale: facetScale, x: originX = 0, y: originY = 0, shareData = false, key: viewKey, } = options;
  152. const { value: data } = dataValue;
  153. // Only support field encode now.
  154. const { x: encodeX, y: encodeY } = encode;
  155. const { color: facetScaleColor } = facetScale;
  156. const { domain: facetDomainColor } = facetScaleColor;
  157. const createChildren = (visualData, scale, layout) => {
  158. const { x: scaleX, y: scaleY } = scale;
  159. const { paddingLeft, paddingTop } = layout;
  160. const { domain: domainX } = scaleX.getOptions();
  161. const { domain: domainY } = scaleY.getOptions();
  162. const index = (0, array_1.indexOf)(visualData);
  163. const bboxs = visualData.map(subLayout);
  164. const values = visualData.map(({ x, y }) => [
  165. scaleX.invert(x),
  166. scaleY.invert(y),
  167. ]);
  168. const filters = values.map(([fx, fy]) => (d) => {
  169. const { [encodeX]: x, [encodeY]: y } = d;
  170. const inX = encodeX !== undefined ? x === fx : true;
  171. const inY = encodeY !== undefined ? y === fy : true;
  172. return inX && inY;
  173. });
  174. const facetData2d = filters.map((f) => data.filter(f));
  175. const maxDataDomain = shareData
  176. ? (0, d3_array_1.max)(facetData2d, (data) => data.length)
  177. : undefined;
  178. const facets = values.map(([fx, fy]) => ({
  179. columnField: encodeX,
  180. columnIndex: domainX.indexOf(fx),
  181. columnValue: fx,
  182. columnValuesLength: domainX.length,
  183. rowField: encodeY,
  184. rowIndex: domainY.indexOf(fy),
  185. rowValue: fy,
  186. rowValuesLength: domainY.length,
  187. }));
  188. const normalizedChildren = facets.map((facet) => {
  189. if (Array.isArray(children))
  190. return children;
  191. return [children(facet)].flat(1);
  192. });
  193. return index.flatMap((i) => {
  194. const [left, top, width, height] = bboxs[i];
  195. const facet = facets[i];
  196. const facetData = facetData2d[i];
  197. const children = normalizedChildren[i];
  198. return children.map((_a) => {
  199. var _b, _c;
  200. var { scale, key, facet: isFacet = true, axis = {}, legend = {} } = _a, rest = __rest(_a, ["scale", "key", "facet", "axis", "legend"]);
  201. const guideY = ((_b = scale === null || scale === void 0 ? void 0 : scale.y) === null || _b === void 0 ? void 0 : _b.guide) || axis.y;
  202. const guideX = ((_c = scale === null || scale === void 0 ? void 0 : scale.x) === null || _c === void 0 ? void 0 : _c.guide) || axis.x;
  203. const defaultScale = {
  204. x: { tickCount: encodeX ? 5 : undefined },
  205. y: { tickCount: encodeY ? 5 : undefined },
  206. };
  207. const newData = isFacet
  208. ? facetData
  209. : facetData.length === 0
  210. ? []
  211. : data;
  212. const newScale = {
  213. color: { domain: facetDomainColor },
  214. };
  215. const newAxis = {
  216. x: createGuide(guideX, createGuideX)(facet, newData),
  217. y: createGuide(guideY, createGuideY)(facet, newData),
  218. };
  219. return Object.assign(Object.assign({ key: `${key}-${i}`, data: newData, x: left + paddingLeft + originX, y: top + paddingTop + originY, parentKey: viewKey, width,
  220. height, paddingLeft: 0, paddingRight: 0, paddingTop: 0, paddingBottom: 0, frame: newData.length ? true : false, dataDomain: maxDataDomain, scale: (0, util_1.deepMix)(defaultScale, scale, newScale), axis: (0, util_1.deepMix)({}, axis, newAxis),
  221. // Hide all legends for child mark by default,
  222. // they are displayed in the top-level.
  223. legend: false }, rest), childOptions);
  224. });
  225. });
  226. };
  227. return {
  228. children: createChildren,
  229. };
  230. });
  231. function subLayoutRect(data) {
  232. const { points } = data;
  233. return (0, vector_1.calcBBox)(points);
  234. }
  235. /**
  236. * Inner guide not show title, tickLine, label and subTickLine,
  237. * if data is empty, do not show guide.
  238. */
  239. function createInnerGuide(guide, data) {
  240. return data.length
  241. ? (0, util_1.deepMix)({
  242. title: false,
  243. tick: null,
  244. label: null,
  245. }, guide)
  246. : (0, util_1.deepMix)({
  247. title: false,
  248. tick: null,
  249. label: null,
  250. grid: null,
  251. }, guide);
  252. }
  253. exports.createInnerGuide = createInnerGuide;
  254. function createGuideXRect(guide) {
  255. return (facet, data) => {
  256. const { rowIndex, rowValuesLength, columnIndex, columnValuesLength } = facet;
  257. // Only the bottom-most facet show axisX.
  258. if (rowIndex !== rowValuesLength - 1)
  259. return createInnerGuide(guide, data);
  260. // Only the bottom-left facet show title.
  261. const title = columnIndex !== columnValuesLength - 1 ? false : undefined;
  262. // If data is empty, do not show cell.
  263. const grid = data.length ? undefined : null;
  264. return (0, util_1.deepMix)({ title, grid }, guide);
  265. };
  266. }
  267. function createGuideYRect(guide) {
  268. return (facet, data) => {
  269. const { rowIndex, columnIndex } = facet;
  270. // Only the left-most facet show axisY.
  271. if (columnIndex !== 0)
  272. return createInnerGuide(guide, data);
  273. // Only the left-top facet show title.
  274. const title = rowIndex !== 0 ? false : undefined;
  275. // If data is empty, do not show cell.
  276. const grid = data.length ? undefined : null;
  277. return (0, util_1.deepMix)({ title, grid }, guide);
  278. };
  279. }
  280. function createGuide(guide, factory) {
  281. if (typeof guide === 'function')
  282. return guide;
  283. if (guide === null)
  284. return () => null;
  285. return factory(guide);
  286. }
  287. const FacetRect = () => {
  288. return (options) => {
  289. const newOptions = container_1.Container.of(options)
  290. .call(exports.toCell)
  291. .call(exports.inferColor)
  292. .call(exports.setAnimation)
  293. .call(setScale)
  294. .call(exports.setStyle)
  295. .call(exports.setData)
  296. .call(exports.setChildren)
  297. .value();
  298. return [newOptions];
  299. };
  300. };
  301. exports.FacetRect = FacetRect;
  302. exports.FacetRect.props = {};
  303. //# sourceMappingURL=facetRect.js.map