legendContinuous.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 { parseColor } from '@antv/g';
  13. import { Continuous } from '@antv/gui';
  14. import { Quantile, Quantize, Threshold } from '@antv/scale';
  15. import { format } from 'd3-format';
  16. import { lastOf } from '../utils/array';
  17. import { G2Layout, adaptor, inferComponentLayout, inferComponentShape, isHorizontal, scaleOf, titleContent, } from './utils';
  18. function calculateFinalSize(size, defaultSize) {
  19. return Math.min(size, defaultSize);
  20. }
  21. function updateShapeDimensions(shape, finalSize, orientation) {
  22. shape.size = finalSize;
  23. if (isHorizontal(orientation)) {
  24. shape.height = finalSize;
  25. }
  26. else {
  27. shape.width = finalSize;
  28. }
  29. return shape;
  30. }
  31. function inferContinuousShape(value, options, component) {
  32. const { size } = options;
  33. const shape = inferComponentShape(value, options, component);
  34. const finalSize = calculateFinalSize(size, LegendContinuous.props.defaultLegendSize);
  35. return updateShapeDimensions(shape, finalSize, shape.orientation);
  36. }
  37. function getFormatter(max) {
  38. return (value) => ({
  39. value: value / max,
  40. label: String(value),
  41. });
  42. }
  43. function getQuantizeOrQuantileConfig(shape, colorScale, min, max, range) {
  44. const thresholds = colorScale.thresholds;
  45. const formatter = getFormatter(max);
  46. return Object.assign(Object.assign({}, shape), { color: range, data: [min, ...thresholds, max].map(formatter) });
  47. }
  48. function getThresholdConfig(shape, colorScale, range) {
  49. const thresholds = colorScale.thresholds;
  50. const data = [-Infinity, ...thresholds, Infinity].map((value, index) => ({
  51. value: index,
  52. label: value,
  53. }));
  54. return Object.assign(Object.assign({}, shape), { data, color: range, labelFilter: (datum, index) => {
  55. return index > 0 && index < data.length - 1;
  56. } });
  57. }
  58. function rangeOf(scale) {
  59. const { domain } = scale.getOptions();
  60. const [min, max] = [domain[0], lastOf(domain)];
  61. return [min, max];
  62. }
  63. /**
  64. * if color scale is not defined, create a constant color scale based on default color
  65. * @param scale
  66. * @param theme
  67. */
  68. function createColorScale(scale, theme) {
  69. const { defaultColor } = theme;
  70. const options = scale.getOptions();
  71. const newScale = scale.clone();
  72. newScale.update(Object.assign(Object.assign({}, options), { range: [parseColor(defaultColor).toString()] }));
  73. return newScale;
  74. }
  75. function getLinearConfig(shape, colorScale, sizeScale, opacityScale, theme) {
  76. const { length } = shape;
  77. const scale = colorScale || createColorScale(sizeScale || opacityScale, theme);
  78. const [min, max] = rangeOf(scale);
  79. return Object.assign(Object.assign({}, shape), { data: scale.getTicks().map((value) => ({ value })), color: new Array(length).fill(0).map((d, i) => {
  80. const value = ((max - min) / (length - 1)) * i + min;
  81. const color = scale.map(value);
  82. const opacity = opacityScale ? opacityScale.map(value) : 1;
  83. return color.replace(/rgb[a]*\(([\d]{1,3}) *, *([\d]{1,3}) *, *([\d]{1,3})[\S\s]*\)/, (match, p1, p2, p3) => `rgba(${p1}, ${p2}, ${p3}, ${opacity})`);
  84. }) });
  85. }
  86. function inferContinuousConfig(scales, value, options, component, theme) {
  87. const colorScale = scaleOf(scales, 'color');
  88. const shape = inferContinuousShape(value, options, component);
  89. if (colorScale instanceof Threshold) {
  90. const { range } = colorScale.getOptions();
  91. const [min, max] = rangeOf(colorScale);
  92. // for quantize, quantile scale
  93. if (colorScale instanceof Quantize || colorScale instanceof Quantile) {
  94. return getQuantizeOrQuantileConfig(shape, colorScale, min, max, range);
  95. }
  96. // for threshold
  97. return getThresholdConfig(shape, colorScale, range);
  98. }
  99. // for linear, pow, sqrt, log, time, utc scale
  100. const sizeScale = scaleOf(scales, 'size');
  101. const opacityScale = scaleOf(scales, 'opacity');
  102. return getLinearConfig(shape, colorScale, sizeScale, opacityScale, theme);
  103. }
  104. /**
  105. * Guide Component for continuous color scale.
  106. * @todo Custom style.
  107. */
  108. export const LegendContinuous = (options) => {
  109. const { labelFormatter, layout, order, orientation, position, size, title, style } = options, rest = __rest(options, ["labelFormatter", "layout", "order", "orientation", "position", "size", "title", "style"]);
  110. return ({ scales, value, theme }) => {
  111. const { bbox } = value;
  112. const { x, y, width, height } = bbox;
  113. const finalLayout = inferComponentLayout(position, layout);
  114. const { continuousLegend: legendTheme = {} } = theme;
  115. const finalStyle = adaptor(Object.assign({}, legendTheme, Object.assign(Object.assign({ titleText: titleContent(title), titleFontSize: 12, handle: false, indicator: false, labelAlign: 'value', labelFormatter: typeof labelFormatter === 'string'
  116. ? (d) => format(labelFormatter)(d.label)
  117. : labelFormatter }, inferContinuousConfig(scales, value, options, LegendContinuous, theme)), style), rest));
  118. const layoutWrapper = new G2Layout({
  119. style: Object.assign(Object.assign({ x,
  120. y,
  121. width,
  122. height }, finalLayout), {
  123. // @ts-ignore
  124. subOptions: finalStyle }),
  125. });
  126. layoutWrapper.appendChild(new Continuous({
  127. style: finalStyle,
  128. }));
  129. return layoutWrapper;
  130. };
  131. };
  132. LegendContinuous.props = {
  133. defaultPosition: 'top',
  134. defaultOrientation: 'vertical',
  135. defaultOrder: 1,
  136. defaultSize: 60,
  137. defaultLength: 300,
  138. defaultLegendSize: 60,
  139. };
  140. //# sourceMappingURL=legendContinuous.js.map