UNPKG

@gooddata/react-components

Version:

GoodData.UI - A powerful JavaScript library for building analytical applications

581 lines (510 loc) • 18.9 kB
// (C) 2007-2020 GoodData Corporation import get = require("lodash/get"); import { AFM, VisualizationObject } from "@gooddata/typings"; import { VisualizationTypes, VisType } from "../constants/visualizationTypes"; import { MEASUREGROUP } from "../constants/dimensions"; import { VIEW, STACK, SEGMENT, TREND, ATTRIBUTE, COLUMNS, MEASURES } from "../constants/bucketNames"; import { convertBucketsToAFM } from "../helpers/conversion"; import { VIEW_BY_ATTRIBUTES_LIMIT } from "../components/visualizations/chart/constants"; import { findBucketByLocalIdentifier } from "./mdObjBucketHelper"; import { getGeoBucketsFromMdObject } from "./geoChart/data"; export function getDimensionTotals(bucket: VisualizationObject.IBucket): AFM.ITotalItem[] { const bucketTotals: VisualizationObject.IVisualizationTotal[] = get< VisualizationObject.IBucket, "totals", VisualizationObject.IVisualizationTotal[] >(bucket, "totals", []); return bucketTotals.map( (total: VisualizationObject.IVisualizationTotal): AFM.ITotalItem => { return { measureIdentifier: total.measureIdentifier, type: total.type, attributeIdentifier: total.attributeIdentifier, }; }, ); } export function getPivotTableDimensions(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const rowAttributes: VisualizationObject.IBucket = buckets.find( // ATTRIBUTE for backwards compatibility with Table component. Actually ROWS bucket => bucket.localIdentifier === ATTRIBUTE, ); const columnAttributes: VisualizationObject.IBucket = buckets.find( bucket => bucket.localIdentifier === COLUMNS, ); const measures: VisualizationObject.IBucket = buckets.find(bucket => bucket.localIdentifier === MEASURES); const rowAttributesItemIdentifiers: string[] = get< VisualizationObject.IBucket, "items", VisualizationObject.BucketItem[] >(rowAttributes, "items", []).map( (a: VisualizationObject.IVisualizationAttribute): string => a.visualizationAttribute.localIdentifier, ); const columnAttributesItemIdentifiers: string[] = get< VisualizationObject.IBucket, "items", VisualizationObject.BucketItem[] >(columnAttributes, "items", []).map( (a: VisualizationObject.IVisualizationAttribute) => a.visualizationAttribute.localIdentifier, ); const measuresItemIdentifiers = get(measures, "items.length") ? [MEASUREGROUP] : []; const totals = getDimensionTotals(rowAttributes); const totalsProp = totals.length ? { totals } : {}; return [ { itemIdentifiers: rowAttributesItemIdentifiers, ...totalsProp, }, { itemIdentifiers: [...columnAttributesItemIdentifiers, ...measuresItemIdentifiers], }, ]; } export function getTableDimensions(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const attributes: VisualizationObject.IBucket = buckets.find( bucket => bucket.localIdentifier === ATTRIBUTE, ); const measures: VisualizationObject.IBucket = buckets.find(bucket => bucket.localIdentifier === MEASURES); const attributesItemIdentifiers: string[] = get< VisualizationObject.IBucket, "items", VisualizationObject.BucketItem[] >(attributes, "items", []).map( (a: VisualizationObject.IVisualizationAttribute): string => a.visualizationAttribute.localIdentifier, ); const measuresItemIdentifiers = measures && measures.items && measures.items.length ? [MEASUREGROUP] : []; const totals = getDimensionTotals(attributes); const totalsProp = totals.length ? { totals } : {}; return [ { itemIdentifiers: attributesItemIdentifiers, ...totalsProp, }, { itemIdentifiers: measuresItemIdentifiers, }, ]; } function getLocalIdentifierFromAttribute(attribute: VisualizationObject.IVisualizationAttribute): string { return attribute.visualizationAttribute.localIdentifier; } function getPieOrDonutDimensions( mdObject: VisualizationObject.IVisualizationObjectContent, ): AFM.IDimension[] { const view = mdObject.buckets.find(bucket => bucket.localIdentifier === VIEW); if (view && view.items.length) { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: view.items.map(getLocalIdentifierFromAttribute), }, ]; } return [ { itemIdentifiers: [], }, { itemIdentifiers: [MEASUREGROUP], }, ]; } function getBarDimensions(mdObject: VisualizationObject.IVisualizationObjectContent): AFM.IDimension[] { const view: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === VIEW, ); const stack: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === STACK, ); const hasNoStacks = !stack || !stack.items || stack.items.length === 0; if (hasNoStacks) { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: ((view && view.items) || []).map(getLocalIdentifierFromAttribute), }, ]; } return [ { itemIdentifiers: ((stack && stack.items) || []).map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: ((view && view.items) || []) .map(getLocalIdentifierFromAttribute) .concat([MEASUREGROUP]), }, ]; } function getAreaDimensions(mdObject: VisualizationObject.IVisualizationObjectContent): AFM.IDimension[] { const view: VisualizationObject.IBucket = findBucketByLocalIdentifier(mdObject.buckets, VIEW); const stack: VisualizationObject.IBucket = findBucketByLocalIdentifier(mdObject.buckets, STACK); const hasNoStacks = !stack || !stack.items || stack.items.length === 0; const haveManyViewItems = view && view.items && view.items.length > 1; if (haveManyViewItems) { // only take first two view items const [viewItemIdentifier, stackItemIdentifier] = view.items .slice(0, VIEW_BY_ATTRIBUTES_LIMIT) .map(getLocalIdentifierFromAttribute); return [ { itemIdentifiers: [stackItemIdentifier], }, { itemIdentifiers: [viewItemIdentifier, MEASUREGROUP], }, ]; } if (hasNoStacks) { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: ((view && view.items) || []).map(getLocalIdentifierFromAttribute), }, ]; } return [ { itemIdentifiers: ((stack && stack.items) || []).map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: ((view && view.items) || []) .map(getLocalIdentifierFromAttribute) .concat([MEASUREGROUP]), }, ]; } function getLineDimensions(mdObject: VisualizationObject.IVisualizationObjectContent): AFM.IDimension[] { const trend: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === TREND, ); const segment: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === SEGMENT, ); const hasNoSegments = !segment || !segment.items || segment.items.length === 0; if (hasNoSegments) { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: ((trend && trend.items) || []).map( (t: VisualizationObject.IVisualizationAttribute) => t.visualizationAttribute.localIdentifier, ), }, ]; } return [ { itemIdentifiers: ((segment && segment.items) || []).map( (s: VisualizationObject.IVisualizationAttribute) => s.visualizationAttribute.localIdentifier, ), }, { itemIdentifiers: ((trend && trend.items) || []) .map( (t: VisualizationObject.IVisualizationAttribute) => t.visualizationAttribute.localIdentifier, ) .concat([MEASUREGROUP]), }, ]; } export function getHeadlinesDimensions(): AFM.IDimension[] { return [{ itemIdentifiers: ["measureGroup"] }]; } export function getXirrDimensions( mdObject: VisualizationObject.IVisualizationObjectContent, ): AFM.IDimension[] { const attribute: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === ATTRIBUTE, ); if (attribute && attribute.items.length) { return [ { itemIdentifiers: [MEASUREGROUP, ...attribute.items.map(getLocalIdentifierFromAttribute)], }, ]; } return [ { itemIdentifiers: [MEASUREGROUP], }, ]; } function getScatterDimensions(mdObject: VisualizationObject.IVisualizationObjectContent): AFM.IDimension[] { const attribute: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === ATTRIBUTE, ); if (attribute && attribute.items.length) { return [ { itemIdentifiers: attribute.items.map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } return [ { itemIdentifiers: [], }, { itemIdentifiers: [MEASUREGROUP], }, ]; } export function getGeoChartDimensions(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const { attributes = [], measures = [] }: AFM.IAfm = convertBucketsToAFM(buckets); const chartDimensions: AFM.IDimension[] = []; if (measures.length > 0) { chartDimensions.push({ itemIdentifiers: [MEASUREGROUP] }); } chartDimensions.push({ itemIdentifiers: attributes.map((attr: AFM.IAttribute) => attr.localIdentifier) }); return chartDimensions; } // Heatmap export function getHeatmapDimensionsFromMdObj( mdObject: VisualizationObject.IVisualizationObjectContent, ): AFM.IDimension[] { const buckets: VisualizationObject.IBucket[] = mdObject.buckets; return getHeatmapDimensionsFromBuckets(buckets); } export function getHeatmapDimensionsFromBuckets(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const view: VisualizationObject.IBucket = buckets.find(bucket => bucket.localIdentifier === VIEW); const stack: VisualizationObject.IBucket = buckets.find(bucket => bucket.localIdentifier === STACK); const hasNoStacks = !stack || !stack.items || stack.items.length === 0; if (hasNoStacks) { return [ { itemIdentifiers: ((view && view.items) || []).map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } return [ { itemIdentifiers: ((view && view.items) || []).map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: ((stack && stack.items) || []) .map(getLocalIdentifierFromAttribute) .concat([MEASUREGROUP]), }, ]; } function getBubbleDimensions(mdObject: VisualizationObject.IVisualizationObjectContent): AFM.IDimension[] { const view: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === VIEW, ); const stack: VisualizationObject.IBucket = mdObject.buckets.find( bucket => bucket.localIdentifier === STACK, ); const hasNoStacks = !stack || !stack.items || stack.items.length === 0; if (hasNoStacks) { return [ { itemIdentifiers: ((view && view.items) || []).map(getLocalIdentifierFromAttribute), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } return [ { itemIdentifiers: ((view && view.items) || []) .map(getLocalIdentifierFromAttribute) .concat(((stack && stack.items) || []).map(getLocalIdentifierFromAttribute)), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } /** * generateDimensions * is a function that generates dimensions based on buckets and visualization objects. * WARNING: It duplicates logic from pluggable visualizations. * Remove once react components support pluggable visualizations. * @param mdObject:VisualizationObject.IVisualizationObjectContent - metadata object with buckets * @param type:VisType - visualization type string * @internal */ export function generateDimensions( mdObject: VisualizationObject.IVisualizationObjectContent, type: VisType, ): AFM.IDimension[] { switch (type) { case VisualizationTypes.TABLE: { return getPivotTableDimensions(mdObject.buckets); } case VisualizationTypes.PIE: case VisualizationTypes.DONUT: case VisualizationTypes.FUNNEL: { return getPieOrDonutDimensions(mdObject); } case VisualizationTypes.TREEMAP: { return getTreemapDimensionsFromMdObj(mdObject); } case VisualizationTypes.LINE: { return getLineDimensions(mdObject); } case VisualizationTypes.AREA: { return getAreaDimensions(mdObject); } case VisualizationTypes.BAR: case VisualizationTypes.COMBO: case VisualizationTypes.COMBO2: case VisualizationTypes.COLUMN: case VisualizationTypes.BULLET: { return getBarDimensions(mdObject); } case VisualizationTypes.HEADLINE: { return getHeadlinesDimensions(); } case VisualizationTypes.SCATTER: { return getScatterDimensions(mdObject); } case VisualizationTypes.HEATMAP: { return getHeatmapDimensionsFromMdObj(mdObject); } case VisualizationTypes.BUBBLE: { return getBubbleDimensions(mdObject); } case VisualizationTypes.XIRR: { return getXirrDimensions(mdObject); } case VisualizationTypes.PUSHPIN: { const buckets = getGeoBucketsFromMdObject(mdObject); return getGeoChartDimensions(buckets); } } return []; } export function generateStackedDimensions(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const viewBucket = buckets.find(bucket => bucket.localIdentifier === ATTRIBUTE); const stackBucket = buckets.find(bucket => bucket.localIdentifier === STACK); const viewByAttributes = viewBucket && (viewBucket.items as VisualizationObject.IVisualizationAttribute[]); const stackByAttribute = stackBucket && (stackBucket.items[0] as VisualizationObject.IVisualizationAttribute); const stackByAttributeLocalIdentifier = stackByAttribute ? stackByAttribute.visualizationAttribute.localIdentifier : undefined; const viewByAttributeLocalIdentifiers = viewByAttributes && viewByAttributes.map(getLocalIdentifierFromAttribute); return [ { itemIdentifiers: stackByAttributeLocalIdentifier ? [stackByAttributeLocalIdentifier] : [], }, { itemIdentifiers: viewByAttributeLocalIdentifiers ? [...viewByAttributeLocalIdentifiers, MEASUREGROUP] : [MEASUREGROUP], }, ]; } export function generateDefaultDimensions(afm: AFM.IAfm): AFM.IDimension[] { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: (afm.attributes || []).map(a => a.localIdentifier), }, ]; } export function isStackedChart(buckets: VisualizationObject.IBucket[], stackedBuckedName: string = STACK) { return buckets.some(bucket => bucket.localIdentifier === stackedBuckedName && bucket.items.length > 0); } // for ScatterPlot and BubbleChart export function generateDefaultDimensionsForPointsCharts(afm: AFM.IAfm): AFM.IDimension[] { return [ { itemIdentifiers: (afm.attributes || []).map(a => a.localIdentifier), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } // for PieChart, DonutChart export const generateDefaultDimensionsForRoundChart = (afm: AFM.IAfm): AFM.IDimension[] => { if ((afm.attributes || []).length === 0) { return [ { itemIdentifiers: [], }, { itemIdentifiers: [MEASUREGROUP], }, ]; } return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: (afm.attributes || []).map(a => a.localIdentifier), }, ]; }; // Treemap export function getTreemapDimensionsFromMdObj( mdObject: VisualizationObject.IVisualizationObjectContent, ): AFM.IDimension[] { const buckets: VisualizationObject.IBucket[] = mdObject.buckets; return getTreemapDimensionsFromBuckets(buckets); } export function getTreemapDimensionsFromBuckets(buckets: VisualizationObject.IBucket[]): AFM.IDimension[] { const afm: AFM.IAfm = convertBucketsToAFM(buckets); return getTreemapDimensionsFromAFM(afm); } export function getTreemapDimensionsFromAFM(afm: AFM.IAfm): AFM.IDimension[] { const attributes = afm.attributes || []; if (attributes.length === 1) { return [ { itemIdentifiers: [MEASUREGROUP], }, { itemIdentifiers: attributes.map(a => a.localIdentifier), }, ]; } return [ { itemIdentifiers: attributes.map(a => a.localIdentifier), }, { itemIdentifiers: [MEASUREGROUP], }, ]; } export function getGeneralDimensionsFromAFM(afm: AFM.IAfm): AFM.IDimension[] { const attributes = afm.attributes || []; const measures = afm.measures || []; const dimensions = []; if (attributes.length > 0) { dimensions.push({ itemIdentifiers: attributes.map((attribute: AFM.IAttribute) => attribute.localIdentifier), }); } if (measures.length > 0) { dimensions.push({ itemIdentifiers: [MEASUREGROUP], }); } return dimensions; }