elementSelect.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. var __rest = (this && this.__rest) || function (s, e) {
  2. var t = {};
  3. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  4. t[p] = s[p];
  5. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  6. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  7. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  8. t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { group } from 'd3-array';
  13. import { deepMix } from '@antv/util';
  14. import { subObject } from '../utils/helper';
  15. import { createValueof, createDatumof, selectG2Elements, useState, renderLink, renderBackground, selectPlotArea, offsetTransform, mergeState, selectElementByData, } from './utils';
  16. /**
  17. * Active a group of elements.
  18. */
  19. export function elementSelect(root, { elements: elementsof, // given the root of chart returns elements to be manipulated
  20. datum, // given each element returns the datum of it
  21. groupKey = (d) => d, // group elements by specified key
  22. link = false, // draw link or not
  23. single = false, // single select or not
  24. coordinate, background = false, scale, emitter, state = {}, }) {
  25. var _a;
  26. const elements = elementsof(root);
  27. const elementSet = new Set(elements);
  28. const keyGroup = group(elements, groupKey);
  29. const valueof = createValueof(elements, datum);
  30. const [appendLink, removeLink] = renderLink(Object.assign({ link,
  31. elements,
  32. valueof,
  33. coordinate }, subObject(state.selected, 'link')));
  34. const [appendBackground, removeBackground] = renderBackground(Object.assign({ background,
  35. coordinate,
  36. scale,
  37. valueof }, subObject(state.selected, 'background')));
  38. const elementStyle = deepMix(state, {
  39. selected: Object.assign({}, (((_a = state.selected) === null || _a === void 0 ? void 0 : _a.offset) && {
  40. //Apply translate to mock slice out.
  41. transform: (...params) => {
  42. const value = state.selected.offset(...params);
  43. const [, i] = params;
  44. return offsetTransform(elements[i], value, coordinate);
  45. },
  46. })),
  47. });
  48. const { setState, removeState, hasState } = useState(elementStyle, valueof);
  49. const clear = (nativeEvent = true) => {
  50. for (const e of elements) {
  51. removeState(e, 'selected', 'unselected');
  52. removeLink(e);
  53. removeBackground(e);
  54. }
  55. if (nativeEvent)
  56. emitter.emit('element:unselect', { nativeEvent: true });
  57. return;
  58. };
  59. const singleSelect = (event, element, nativeEvent = true) => {
  60. // Clear states if clicked selected element.
  61. if (hasState(element, 'selected'))
  62. clear();
  63. else {
  64. const k = groupKey(element);
  65. const group = keyGroup.get(k);
  66. const groupSet = new Set(group);
  67. for (const e of elements) {
  68. if (groupSet.has(e))
  69. setState(e, 'selected');
  70. else {
  71. setState(e, 'unselected');
  72. removeLink(e);
  73. }
  74. if (e !== element)
  75. removeBackground(e);
  76. }
  77. appendLink(group);
  78. appendBackground(element);
  79. if (!nativeEvent)
  80. return;
  81. emitter.emit('element:select', Object.assign(Object.assign({}, event), { nativeEvent, data: {
  82. data: [datum(element), ...group.map(datum)],
  83. } }));
  84. }
  85. };
  86. const multipleSelect = (event, element, nativeEvent = true) => {
  87. const k = groupKey(element);
  88. const group = keyGroup.get(k);
  89. const groupSet = new Set(group);
  90. if (!hasState(element, 'selected')) {
  91. const hasSelectedGroup = group.some((e) => hasState(e, 'selected'));
  92. for (const e of elements) {
  93. if (groupSet.has(e))
  94. setState(e, 'selected');
  95. else if (!hasState(e, 'selected'))
  96. setState(e, 'unselected');
  97. }
  98. // Append link for each group only once.
  99. if (!hasSelectedGroup && link)
  100. appendLink(group);
  101. appendBackground(element);
  102. }
  103. else {
  104. // If there is no selected elements after resetting this group,
  105. // clear the states.
  106. const hasSelected = elements.some((e) => !groupSet.has(e) && hasState(e, 'selected'));
  107. if (!hasSelected)
  108. return clear();
  109. // If there are still some selected elements after resetting this group,
  110. // only remove the link.
  111. for (const e of group) {
  112. setState(e, 'unselected');
  113. removeLink(e);
  114. removeBackground(e);
  115. }
  116. }
  117. if (!nativeEvent)
  118. return;
  119. emitter.emit('element:select', Object.assign(Object.assign({}, event), { nativeEvent, data: {
  120. data: elements.filter((e) => hasState(e, 'selected')).map(datum),
  121. } }));
  122. };
  123. const click = (event) => {
  124. const { target: element, nativeEvent = true } = event;
  125. // Click non-element shape, reset.
  126. // Such as the rest of content area(background).
  127. if (!elementSet.has(element))
  128. return clear();
  129. if (single)
  130. return singleSelect(event, element, nativeEvent);
  131. return multipleSelect(event, element, nativeEvent);
  132. };
  133. root.addEventListener('click', click);
  134. const onSelect = (e) => {
  135. const { nativeEvent, data } = e;
  136. if (nativeEvent)
  137. return;
  138. const selectedData = single ? data.data.slice(0, 1) : data.data;
  139. for (const d of selectedData) {
  140. const element = selectElementByData(elements, d, datum);
  141. click({ target: element, nativeEvent: false });
  142. }
  143. };
  144. const onUnSelect = () => {
  145. clear(false);
  146. };
  147. emitter.on('element:select', onSelect);
  148. emitter.on('element:unselect', onUnSelect);
  149. return () => {
  150. for (const e of elements)
  151. removeLink(e);
  152. root.removeEventListener('click', click);
  153. emitter.off('element:select', onSelect);
  154. emitter.off('element:unselect', onUnSelect);
  155. };
  156. }
  157. export function ElementSelect(_a) {
  158. var { createGroup, background = false, link = false } = _a, rest = __rest(_a, ["createGroup", "background", "link"]);
  159. return (context, _, emitter) => {
  160. const { container, view, options } = context;
  161. const { coordinate, scale } = view;
  162. const plotArea = selectPlotArea(container);
  163. return elementSelect(plotArea, Object.assign({ elements: selectG2Elements, datum: createDatumof(view), groupKey: createGroup ? createGroup(view) : undefined, coordinate,
  164. scale, state: mergeState(options, [
  165. ['selected', background ? {} : { lineWidth: '1', stroke: '#000' }],
  166. 'unselected',
  167. ]), background,
  168. link,
  169. emitter }, rest));
  170. };
  171. }
  172. //# sourceMappingURL=elementSelect.js.map