123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.placeComponents = exports.computeLayout = void 0;
- const d3_array_1 = require("d3-array");
- const coordinate_1 = require("../utils/coordinate");
- const helper_1 = require("../utils/helper");
- const array_1 = require("../utils/array");
- const string_1 = require("../utils/string");
- const component_1 = require("./component");
- function computeLayout(components, options, theme, library) {
- const { width, height, x = 0, y = 0, inset = 0, insetLeft = inset, insetTop = inset, insetBottom = inset, insetRight = inset, margin = 0, marginLeft = margin, marginBottom = margin, marginTop = margin, marginRight = margin, padding, paddingBottom = padding, paddingLeft = padding, paddingRight = padding, paddingTop = padding, } = options;
- const MAX_PADDING_RATIO = 1 / 3;
- const clamp = (origin, computed, max) => origin === 'auto' ? Math.min(max, computed) : computed;
- // Compute paddingLeft and paddingRight first to get innerWidth.
- const horizontalPadding = computePadding(components, height, [0, 0], ['left', 'right'], options, theme, library);
- const { paddingLeft: pl0, paddingRight: pr0 } = horizontalPadding;
- const viewWidth = width - marginLeft - marginRight;
- const pl = clamp(paddingLeft, pl0, viewWidth * MAX_PADDING_RATIO);
- const pr = clamp(paddingRight, pr0, viewWidth * MAX_PADDING_RATIO);
- const iw = viewWidth - pl - pr;
- // Compute paddingBottom and paddingTop based on innerWidth.
- const verticalPadding = computePadding(components, iw, [pl, pr], ['bottom', 'top'], options, theme, library);
- const { paddingTop: pt0, paddingBottom: pb0 } = verticalPadding;
- const viewHeight = height - marginBottom - marginTop;
- const pb = clamp(paddingBottom, pb0, viewHeight * MAX_PADDING_RATIO);
- const pt = clamp(paddingTop, pt0, viewHeight * MAX_PADDING_RATIO);
- const ih = viewHeight - pb - pt;
- return {
- width,
- height,
- insetLeft,
- insetTop,
- insetBottom,
- insetRight,
- innerWidth: iw,
- innerHeight: ih,
- paddingLeft: pl,
- paddingRight: pr,
- paddingTop: pt,
- paddingBottom: pb,
- marginLeft,
- marginBottom,
- marginTop,
- marginRight,
- x,
- y,
- };
- }
- exports.computeLayout = computeLayout;
- /**
- * @todo Support percentage size(e.g. 50%)
- */
- function computePadding(components, crossSize, crossPadding, positions, options, theme, library) {
- const positionComponents = (0, d3_array_1.group)(components, (d) => d.position);
- const { padding, paddingLeft = padding, paddingRight = padding, paddingBottom = padding, paddingTop = padding, } = options;
- const layout = {
- paddingBottom,
- paddingLeft,
- paddingTop,
- paddingRight,
- };
- for (const position of positions) {
- const key = `padding${(0, helper_1.capitalizeFirst)((0, string_1.camelCase)(position))}`;
- const value = layout[key];
- if (value === undefined || value === 'auto') {
- if (!positionComponents.has(position)) {
- layout[key] = 30;
- }
- else {
- const components = positionComponents.get(position);
- if (value === 'auto') {
- components.forEach((component) => (0, component_1.computeComponentSize)(component, crossSize, crossPadding, position, theme, library));
- }
- const totalSize = components.reduce((sum, { size }) => sum + size, 0);
- layout[key] = totalSize;
- }
- }
- }
- return layout;
- }
- function placeComponents(components, coordinate, layout) {
- const positionComponents = (0, d3_array_1.group)(components, (d) => d.position);
- const { paddingLeft, paddingRight, paddingTop, paddingBottom, marginLeft, marginTop, marginBottom, marginRight, innerHeight, innerWidth, height, width, } = layout;
- const pl = paddingLeft + marginLeft;
- const pt = paddingTop + marginTop;
- const pr = paddingRight + marginRight;
- const pb = paddingBottom + marginBottom;
- const section = {
- top: [pl, 0, innerWidth, pt, 'vertical', true, d3_array_1.ascending],
- right: [width - pr, pt, pr, innerHeight, 'horizontal', false, d3_array_1.ascending],
- bottom: [pl, height - pb, innerWidth, pb, 'vertical', false, d3_array_1.ascending],
- left: [0, pt, pl, innerHeight, 'horizontal', true, d3_array_1.ascending],
- 'top-left': [pl, 0, innerWidth, pt, 'vertical', true, d3_array_1.ascending],
- 'top-right': [pl, 0, innerWidth, pt, 'vertical', true, d3_array_1.ascending],
- 'bottom-left': [
- pl,
- height - pb,
- innerWidth,
- pb,
- 'vertical',
- false,
- d3_array_1.ascending,
- ],
- 'bottom-right': [
- pl,
- height - pb,
- innerWidth,
- pb,
- 'vertical',
- false,
- d3_array_1.ascending,
- ],
- center: [pl, pt, innerWidth, innerHeight, 'center', null, null],
- inner: [pl, pt, innerWidth, innerHeight, 'center', null, null],
- outer: [pl, pt, innerWidth, innerHeight, 'center', null, null],
- };
- for (const [position, components] of positionComponents.entries()) {
- const area = section[position];
- /**
- * @description non-entity components: axis in the center, inner, outer, component in the center
- * @description entity components: other components
- * @description no volume components take up no extra space
- */
- const [nonEntityComponents, entityComponents] = (0, array_1.divide)(components, (component) => {
- if (typeof component.type !== 'string')
- return false;
- if (position === 'center')
- return true;
- if (component.type.startsWith('axis') &&
- ['inner', 'outer'].includes(position)) {
- return true;
- }
- return false;
- });
- if (nonEntityComponents.length) {
- placeNonEntityComponents(nonEntityComponents, coordinate, area, position);
- }
- if (entityComponents.length) {
- placePaddingArea(components, coordinate, area);
- }
- }
- }
- exports.placeComponents = placeComponents;
- function placeNonEntityComponents(components, coordinate, area, position) {
- const [axisComponents, nonAxisComponents] = (0, array_1.divide)(components, (component) => {
- if (typeof component.type === 'string' &&
- component.type.startsWith('axis')) {
- return true;
- }
- return false;
- });
- placeNonEntityAxis(axisComponents, coordinate, area, position);
- // in current stage, only legend component which located in the center can be placed
- placeCenter(nonAxisComponents, coordinate, area);
- }
- function placeNonEntityAxis(components, coordinate, area, position) {
- if (position === 'center') {
- if ((0, coordinate_1.isRadar)(coordinate)) {
- placeAxisRadar(components, coordinate, area, position);
- }
- else if ((0, coordinate_1.isPolar)(coordinate)) {
- placeArcLinear(components, coordinate, area);
- }
- else if ((0, coordinate_1.isParallel)(coordinate)) {
- placeAxisParallel(components, coordinate, area, components[0].orientation);
- }
- }
- else if (position === 'inner') {
- placeAxisArcInner(components, coordinate, area);
- }
- else if (position === 'outer') {
- placeAxisArcOuter(components, coordinate, area);
- }
- }
- function placeAxisArcInner(components, coordinate, area) {
- const [x, y, , height] = area;
- const [cx, cy] = coordinate.getCenter();
- const [innerRadius] = (0, coordinate_1.radiusOf)(coordinate);
- const r = height / 2;
- const size = innerRadius * r;
- const x0 = cx - size;
- const y0 = cy - size;
- for (let i = 0; i < components.length; i++) {
- const component = components[i];
- component.bbox = {
- x: x + x0,
- y: y + y0,
- width: size * 2,
- height: size * 2,
- };
- }
- }
- function placeAxisArcOuter(components, coordinate, area) {
- const [x, y, width, height] = area;
- for (const component of components) {
- component.bbox = { x, y, width, height };
- }
- }
- /**
- * @example arcX, arcY, axisLinear with angle
- */
- function placeArcLinear(components, coordinate, area) {
- const [x, y, width, height] = area;
- for (const component of components) {
- component.bbox = { x: x, y, width, height };
- }
- }
- function placeAxisParallel(components, coordinate, area, orientation) {
- if (orientation === 'horizontal') {
- placeAxisParallelHorizontal(components, coordinate, area);
- }
- else if (orientation === 'vertical') {
- placeAxisParallelVertical(components, coordinate, area);
- }
- }
- function placeAxisParallelVertical(components, coordinate, area) {
- const [x, y, , height] = area;
- // Create a high dimension vector and map to a list of two-dimension points.
- // [0, 0, 0] -> [x0, 0, x1, 0, x2, 0]
- const vector = new Array(components.length + 1).fill(0);
- const points = coordinate.map(vector);
- // Extract x of each points.
- // [x0, 0, x1, 0, x2, 0] -> [x0, x1, x2]
- const X = points.filter((_, i) => i % 2 === 0).map((d) => d + x);
- // Place each axis by coordinate in parallel coordinate.
- for (let i = 0; i < components.length; i++) {
- const component = components[i];
- const x = X[i];
- const width = X[i + 1] - x;
- component.bbox = { x, y, width, height };
- }
- }
- function placeAxisParallelHorizontal(components, coordinate, area) {
- const [x, y, width] = area;
- // Create a high dimension vector and map to a list of two-dimension points.
- // [0, 0, 0] -> [height, y0, height, y1, height, y2]
- const vector = new Array(components.length + 1).fill(0);
- const points = coordinate.map(vector);
- // Extract y of each points.
- // [x0, 0, x1, 0, x2, 0] -> [x0, x1, x2]
- const Y = points.filter((_, i) => i % 2 === 1).map((d) => d + y);
- // Place each axis by coordinate in parallel coordinate.
- for (let i = 0; i < components.length; i++) {
- const component = components[i];
- const y = Y[i];
- const height = Y[i + 1] - y;
- component.bbox = { x, y, width, height };
- }
- // override style
- }
- function placeAxisRadar(components, coordinate, area, position) {
- const [x, y, width, height] = area;
- for (const component of components) {
- component.bbox = { x, y, width, height };
- component.radar = {
- index: components.indexOf(component),
- count: components.length,
- };
- }
- }
- function placePaddingArea(components, coordinate, area) {
- const [x, y, width, height, direction, reverse, comparator] = area;
- const [mainStartKey, mainStartValue, crossStartKey, crossStartValue, mainSizeKey, mainSizeValue, crossSizeKey, crossSizeValue,] = direction === 'vertical'
- ? ['y', y, 'x', x, 'height', height, 'width', width]
- : ['x', x, 'y', y, 'width', width, 'height', height];
- // Sort components by order.
- // The smaller the order, the closer to center.
- components.sort((a, b) => comparator === null || comparator === void 0 ? void 0 : comparator(a.order, b.order));
- const startValue = reverse ? mainStartValue + mainSizeValue : mainStartValue;
- for (let i = 0, start = startValue; i < components.length; i++) {
- const component = components[i];
- const { size } = component;
- component.bbox = {
- [mainStartKey]: reverse ? start - size : start,
- [crossStartKey]: crossStartValue,
- [mainSizeKey]: size,
- [crossSizeKey]: crossSizeValue,
- };
- start += size * (reverse ? -1 : 1);
- }
- }
- /**
- * @example legend in the center of radial or polar system
- */
- function placeCenter(components, coordinate, area) {
- if (components.length === 0)
- return;
- const [x, y, width, height] = area;
- const [innerRadius] = (0, coordinate_1.radiusOf)(coordinate);
- const r = ((height / 2) * innerRadius) / Math.sqrt(2);
- const cx = x + width / 2;
- const cy = y + height / 2;
- for (let i = 0; i < components.length; i++) {
- const component = components[i];
- component.bbox = { x: cx - r, y: cy - r, width: r * 2, height: r * 2 };
- }
- }
- //# sourceMappingURL=layout.js.map
|