transform.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. "use strict";
  2. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  3. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  4. return new (P || (P = Promise))(function (resolve, reject) {
  5. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  6. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  7. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  8. step((generator = generator.apply(thisArg, _arguments || [])).next());
  9. });
  10. };
  11. var __rest = (this && this.__rest) || function (s, e) {
  12. var t = {};
  13. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  14. t[p] = s[p];
  15. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  16. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  17. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  18. t[p[i]] = s[p[i]];
  19. }
  20. return t;
  21. };
  22. Object.defineProperty(exports, "__esModule", { value: true });
  23. exports.maybeNonAnimate = exports.addGuideToScale = exports.maybeArrayField = exports.extractTooltip = exports.normalizeTooltip = exports.extractColumns = exports.maybeVisualChannel = exports.inferChannelsType = exports.flatEncode = exports.applyDataTransform = exports.applyDefaults = void 0;
  24. const util_1 = require("@antv/util");
  25. const d3_format_1 = require("d3-format");
  26. const array_1 = require("../utils/array");
  27. const helper_1 = require("../utils/helper");
  28. const mark_1 = require("../utils/mark");
  29. const library_1 = require("./library");
  30. const mark_2 = require("./mark");
  31. const scale_1 = require("./scale");
  32. // @todo Add more defaults.
  33. function applyDefaults(I, mark, context) {
  34. const { encode = {}, scale = {}, transform = [] } = mark, rest = __rest(mark, ["encode", "scale", "transform"]);
  35. return [I, Object.assign(Object.assign({}, rest), { encode, scale, transform })];
  36. }
  37. exports.applyDefaults = applyDefaults;
  38. function applyDataTransform(I, mark, context) {
  39. return __awaiter(this, void 0, void 0, function* () {
  40. const { library } = context;
  41. const { data } = mark;
  42. const [useData] = (0, library_1.useLibrary)('data', library);
  43. const descriptor = normalizedDataSource(data);
  44. const { transform: T = [] } = descriptor, connector = __rest(descriptor, ["transform"]);
  45. const transform = [connector, ...T];
  46. const transformFunctions = transform.map(useData);
  47. const transformedData = yield (0, helper_1.composeAsync)(transformFunctions)(data);
  48. return [
  49. Array.isArray(transformedData) ? (0, array_1.indexOf)(transformedData) : [],
  50. Object.assign(Object.assign({}, mark), { data: transformedData }),
  51. ];
  52. });
  53. }
  54. exports.applyDataTransform = applyDataTransform;
  55. function flatEncode(I, mark, context) {
  56. const { encode } = mark;
  57. if (!encode)
  58. return [I, mark];
  59. const flattenEncode = {};
  60. for (const [key, value] of Object.entries(encode)) {
  61. if (Array.isArray(value)) {
  62. for (let i = 0; i < value.length; i++) {
  63. const name = `${key}${i === 0 ? '' : i}`;
  64. flattenEncode[name] = value[i];
  65. }
  66. }
  67. else {
  68. flattenEncode[key] = value;
  69. }
  70. }
  71. return [I, Object.assign(Object.assign({}, mark), { encode: flattenEncode })];
  72. }
  73. exports.flatEncode = flatEncode;
  74. function inferChannelsType(I, mark, context) {
  75. const { encode, data } = mark;
  76. if (!encode)
  77. return [I, mark];
  78. const typedEncode = (0, array_1.mapObject)(encode, (channel) => {
  79. if (isTypedChannel(channel))
  80. return channel;
  81. const type = inferChannelType(data, channel);
  82. return { type, value: channel };
  83. });
  84. return [I, Object.assign(Object.assign({}, mark), { encode: typedEncode })];
  85. }
  86. exports.inferChannelsType = inferChannelsType;
  87. function maybeVisualChannel(I, mark, context) {
  88. const { encode } = mark;
  89. if (!encode)
  90. return [I, mark];
  91. const newEncode = (0, array_1.mapObject)(encode, (channel, name) => {
  92. const { type } = channel;
  93. if (type !== 'constant' || (0, scale_1.isPosition)(name))
  94. return channel;
  95. return Object.assign(Object.assign({}, channel), { constant: true });
  96. });
  97. return [I, Object.assign(Object.assign({}, mark), { encode: newEncode })];
  98. }
  99. exports.maybeVisualChannel = maybeVisualChannel;
  100. function extractColumns(I, mark, context) {
  101. const { encode, data } = mark;
  102. if (!encode)
  103. return [I, mark];
  104. const { library } = context;
  105. const columnOf = (0, mark_2.createColumnOf)(library);
  106. const valuedEncode = (0, array_1.mapObject)(encode, (channel) => columnOf(data, channel));
  107. return [I, Object.assign(Object.assign({}, mark), { encode: valuedEncode })];
  108. }
  109. exports.extractColumns = extractColumns;
  110. /**
  111. * Normalize mark.tooltip to {title, items}.
  112. */
  113. function normalizeTooltip(I, mark, context) {
  114. const { tooltip = {} } = mark;
  115. if ((0, helper_1.isUnset)(tooltip))
  116. return [I, mark];
  117. if (Array.isArray(tooltip)) {
  118. return [I, Object.assign(Object.assign({}, mark), { tooltip: { items: tooltip } })];
  119. }
  120. if ((0, helper_1.isStrictObject)(tooltip) && (0, mark_1.isFullTooltip)(tooltip)) {
  121. return [I, Object.assign(Object.assign({}, mark), { tooltip })];
  122. }
  123. return [I, Object.assign(Object.assign({}, mark), { tooltip: { items: [tooltip] } })];
  124. }
  125. exports.normalizeTooltip = normalizeTooltip;
  126. function extractTooltip(I, mark, context) {
  127. const { data, encode, tooltip = {} } = mark;
  128. if ((0, helper_1.isUnset)(tooltip))
  129. return [I, mark];
  130. const valueOf = (item) => {
  131. if (!item)
  132. return item;
  133. if (typeof item === 'string') {
  134. return I.map((i) => ({ name: item, value: data[i][item] }));
  135. }
  136. if ((0, helper_1.isStrictObject)(item)) {
  137. const { field, channel, color, name = field, valueFormatter = (d) => d, } = item;
  138. // Support d3-format.
  139. const normalizedValueFormatter = typeof valueFormatter === 'string'
  140. ? (0, d3_format_1.format)(valueFormatter)
  141. : valueFormatter;
  142. // Field name.
  143. const definedChannel = channel && encode[channel];
  144. const channelField = definedChannel && encode[channel].field;
  145. const name1 = name || channelField || channel;
  146. const values = [];
  147. for (const i of I) {
  148. const value1 = field
  149. ? data[i][field]
  150. : definedChannel
  151. ? encode[channel].value[i]
  152. : null;
  153. values[i] = {
  154. name: name1,
  155. color,
  156. value: normalizedValueFormatter(value1),
  157. };
  158. }
  159. return values;
  160. }
  161. if (typeof item === 'function') {
  162. const values = [];
  163. for (const i of I) {
  164. const v = item(data[i], i, data, encode);
  165. if ((0, helper_1.isStrictObject)(v))
  166. values[i] = v;
  167. else
  168. values[i] = { value: v };
  169. }
  170. return values;
  171. }
  172. return item;
  173. };
  174. const { title, items = [] } = tooltip, rest = __rest(tooltip, ["title", "items"]);
  175. const newTooltip = Object.assign({ title: valueOf(title), items: Array.isArray(items) ? items.map(valueOf) : [] }, rest);
  176. return [I, Object.assign(Object.assign({}, mark), { tooltip: newTooltip })];
  177. }
  178. exports.extractTooltip = extractTooltip;
  179. function maybeArrayField(I, mark, context) {
  180. const { encode } = mark, rest = __rest(mark, ["encode"]);
  181. if (!encode)
  182. return [I, mark];
  183. const columns = Object.entries(encode);
  184. const arrayColumns = columns
  185. .filter(([, channel]) => {
  186. const { value: V } = channel;
  187. return Array.isArray(V[0]);
  188. })
  189. .flatMap(([key, V]) => {
  190. const columns = [[key, new Array(I.length).fill(undefined)]];
  191. const { value: rows } = V, rest = __rest(V, ["value"]);
  192. for (let i = 0; i < rows.length; i++) {
  193. const row = rows[i];
  194. if (Array.isArray(row)) {
  195. for (let j = 0; j < row.length; j++) {
  196. const column = columns[j] || [
  197. `${key}${j}`,
  198. new Array(I).fill(undefined),
  199. ];
  200. column[1][i] = row[j];
  201. columns[j] = column;
  202. }
  203. }
  204. }
  205. return columns.map(([key, value]) => [
  206. key,
  207. Object.assign({ type: 'column', value }, rest),
  208. ]);
  209. });
  210. const newEncode = Object.fromEntries([...columns, ...arrayColumns]);
  211. return [I, Object.assign(Object.assign({}, rest), { encode: newEncode })];
  212. }
  213. exports.maybeArrayField = maybeArrayField;
  214. function addGuideToScale(I, mark, context) {
  215. const { axis = {}, legend = {}, slider = {}, scrollbar = {} } = mark;
  216. const normalize = (guide, channel) => {
  217. if (typeof guide === 'boolean')
  218. return guide ? {} : null;
  219. const eachGuide = guide[channel];
  220. return eachGuide === undefined || eachGuide ? eachGuide : null;
  221. };
  222. const axisChannels = typeof axis === 'object'
  223. ? Array.from(new Set(['x', 'y', ...Object.keys(axis)]))
  224. : ['x', 'y'];
  225. (0, util_1.deepMix)(mark, {
  226. scale: Object.assign(Object.assign({}, Object.fromEntries(axisChannels.map((channel) => {
  227. const scrollbarOptions = normalize(scrollbar, channel);
  228. return [
  229. channel,
  230. Object.assign({ guide: normalize(axis, channel), slider: normalize(slider, channel), scrollbar: scrollbarOptions }, (scrollbarOptions && {
  231. ratio: scrollbarOptions.ratio === undefined
  232. ? 0.5
  233. : scrollbarOptions.ratio,
  234. })),
  235. ];
  236. }))), { color: { guide: normalize(legend, 'color') }, size: { guide: normalize(legend, 'size') }, shape: { guide: normalize(legend, 'shape') },
  237. // fixme: opacity is conflict with DisplayObject.opacity
  238. // to be confirm.
  239. opacity: { guide: normalize(legend, 'opacity') } }),
  240. });
  241. return [I, mark];
  242. }
  243. exports.addGuideToScale = addGuideToScale;
  244. function maybeNonAnimate(I, mark, context) {
  245. const { animate } = mark;
  246. if (animate || animate === undefined)
  247. return [I, mark];
  248. (0, util_1.deepMix)(mark, {
  249. animate: {
  250. enter: { type: null },
  251. exit: { type: null },
  252. update: { type: null },
  253. },
  254. });
  255. return [I, mark];
  256. }
  257. exports.maybeNonAnimate = maybeNonAnimate;
  258. function isTypedChannel(channel) {
  259. if (typeof channel !== 'object' ||
  260. channel instanceof Date ||
  261. channel === null) {
  262. return false;
  263. }
  264. const { type } = channel;
  265. return (0, helper_1.defined)(type);
  266. }
  267. function inferChannelType(data, channel) {
  268. if (typeof channel === 'function')
  269. return 'transform';
  270. if (typeof channel === 'string' && isField(data, channel))
  271. return 'field';
  272. return 'constant';
  273. }
  274. function isField(data, value) {
  275. if (!Array.isArray(data))
  276. return false;
  277. return data.some((d) => d[value] !== undefined);
  278. }
  279. function normalizedDataSource(data) {
  280. // Return null as a placeholder.
  281. if (!data)
  282. return { type: 'inline', value: null };
  283. if (Array.isArray(data))
  284. return { type: 'inline', value: data };
  285. const { type = 'inline' } = data, rest = __rest(data, ["type"]);
  286. return Object.assign(Object.assign({}, rest), { type });
  287. }
  288. //# sourceMappingURL=transform.js.map