From 5839778fc6ef71f871902f0b122a0872e2f5d537 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 09:39:02 -0800 Subject: [PATCH 1/8] Include yAttributeIDs and yAttributeNames in get graph API requests. --- v3/src/components/graph/graph-component-handler.ts | 10 ++++++++-- .../data-interactive-component-types.ts | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index 8e2ffc90b..67cec55ba 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -9,7 +9,7 @@ import { IDataSet } from "../../models/data/data-set" import { ISharedCaseMetadata } from "../../models/shared/shared-case-metadata" import { getSharedCaseMetadataFromDataset, getSharedDataSets } from "../../models/shared/shared-data-utils" import { ITileContentModel, ITileContentSnapshotWithType } from "../../models/tiles/tile-content" -import { toV3AttrId, toV3DataSetId } from "../../utilities/codap-utils" +import { toV2Id, toV3AttrId, toV3DataSetId } from "../../utilities/codap-utils" import { t } from "../../utilities/translation/translate" import { AxisPlace } from "../axis/axis-types" import { isNumericAxisModel } from "../axis/models/axis-model" @@ -230,13 +230,19 @@ export const graphComponentHandler: DIComponentHandler = { const y2LowerBound = y2NumericAxis?.min const y2UpperBound = y2NumericAxis?.max + const yAttributeIDs = dataConfiguration._yAttributeDescriptions + .map(description => toV2Id(description.attributeID)) + const yAttributeNames = dataConfiguration._yAttributeDescriptions + .map(description => dataset?.getAttribute(description.attributeID)?.name).filter(name => name != null) + return { dataContext, enableNumberToggle, numberToggleLastMode, captionAttributeID, captionAttributeName, legendAttributeID, legendAttributeName, rightSplitAttributeID, rightSplitAttributeName, topSplitAttributeID, topSplitAttributeName, xAttributeID, xAttributeName, xLowerBound, xUpperBound, yAttributeID, yAttributeName, yLowerBound, yUpperBound, - y2AttributeID, y2AttributeName, y2LowerBound, y2UpperBound + y2AttributeID, y2AttributeName, y2LowerBound, y2UpperBound, + yAttributeIDs, yAttributeNames } } }, diff --git a/v3/src/data-interactive/data-interactive-component-types.ts b/v3/src/data-interactive/data-interactive-component-types.ts index 7174271e9..7c4c9ce78 100644 --- a/v3/src/data-interactive/data-interactive-component-types.ts +++ b/v3/src/data-interactive/data-interactive-component-types.ts @@ -81,7 +81,9 @@ export interface V2Graph extends V2Component { xAttributeID?: string | null xAttributeName?: string | null yAttributeID?: string | null + yAttributeIDs?: string[] yAttributeName?: string | null + yAttributeNames?: string[] y2AttributeID?: string | null y2AttributeName?: string | null } From 438e0221d32db19ad10ad2c7ce3ef8be4b563cd9 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 09:51:30 -0800 Subject: [PATCH 2/8] Return v2 ids in response to get graph API requests. --- .../graph/graph-component-handler.ts | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index 67cec55ba..4a9b75472 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -9,7 +9,7 @@ import { IDataSet } from "../../models/data/data-set" import { ISharedCaseMetadata } from "../../models/shared/shared-case-metadata" import { getSharedCaseMetadataFromDataset, getSharedDataSets } from "../../models/shared/shared-data-utils" import { ITileContentModel, ITileContentSnapshotWithType } from "../../models/tiles/tile-content" -import { toV2Id, toV3AttrId, toV3DataSetId } from "../../utilities/codap-utils" +import { maybeToV2Id, toV2Id, toV3AttrId, toV3DataSetId } from "../../utilities/codap-utils" import { t } from "../../utilities/translation/translate" import { AxisPlace } from "../axis/axis-types" import { isNumericAxisModel } from "../axis/models/axis-model" @@ -195,36 +195,43 @@ export const graphComponentHandler: DIComponentHandler = { const { dataConfiguration } = content.graphPointLayerModel const { showParentToggles: enableNumberToggle, showOnlyLastCase: numberToggleLastMode } = content - const captionAttributeID = dataConfiguration.attributeDescriptionForRole("caption")?.attributeID - const captionAttributeName = captionAttributeID ? dataset?.getAttribute(captionAttributeID)?.name : undefined + const _captionAttributeID = dataConfiguration.attributeDescriptionForRole("caption")?.attributeID + const captionAttributeID = maybeToV2Id(_captionAttributeID) + const captionAttributeName = _captionAttributeID ? dataset?.getAttribute(_captionAttributeID)?.name : undefined - const legendAttributeID = dataConfiguration.attributeDescriptionForRole("legend")?.attributeID - const legendAttributeName = legendAttributeID ? dataset?.getAttribute(legendAttributeID)?.name : undefined + const _legendAttributeID = dataConfiguration.attributeDescriptionForRole("legend")?.attributeID + const legendAttributeID = maybeToV2Id(_legendAttributeID) + const legendAttributeName = _legendAttributeID ? dataset?.getAttribute(_legendAttributeID)?.name : undefined - const rightSplitAttributeID = dataConfiguration.attributeDescriptionForRole("rightSplit")?.attributeID - const rightSplitAttributeName = rightSplitAttributeID - ? dataset?.getAttribute(rightSplitAttributeID)?.name + const _rightSplitAttributeID = dataConfiguration.attributeDescriptionForRole("rightSplit")?.attributeID + const rightSplitAttributeID = maybeToV2Id(_rightSplitAttributeID) + const rightSplitAttributeName = _rightSplitAttributeID + ? dataset?.getAttribute(_rightSplitAttributeID)?.name : undefined - const topSplitAttributeID = dataConfiguration.attributeDescriptionForRole("topSplit")?.attributeID - const topSplitAttributeName = topSplitAttributeID ? dataset?.getAttribute(topSplitAttributeID)?.name : undefined + const _topSplitAttributeID = dataConfiguration.attributeDescriptionForRole("topSplit")?.attributeID + const topSplitAttributeID = maybeToV2Id(_topSplitAttributeID) + const topSplitAttributeName = _topSplitAttributeID ? dataset?.getAttribute(_topSplitAttributeID)?.name : undefined - const xAttributeID = dataConfiguration.attributeDescriptionForRole("x")?.attributeID - const xAttributeName = xAttributeID ? dataset?.getAttribute(xAttributeID)?.name : undefined + const _xAttributeID = dataConfiguration.attributeDescriptionForRole("x")?.attributeID + const xAttributeID = maybeToV2Id(_xAttributeID) + const xAttributeName = _xAttributeID ? dataset?.getAttribute(_xAttributeID)?.name : undefined const xAxis = content.getAxis("bottom") const xNumericAxis = isNumericAxisModel(xAxis) ? xAxis : undefined const xLowerBound = xNumericAxis?.min const xUpperBound = xNumericAxis?.max - const yAttributeID = dataConfiguration.attributeDescriptionForRole("y")?.attributeID - const yAttributeName = yAttributeID ? dataset?.getAttribute(yAttributeID)?.name : undefined + const _yAttributeID = dataConfiguration.attributeDescriptionForRole("y")?.attributeID + const yAttributeID = maybeToV2Id(_yAttributeID) + const yAttributeName = _yAttributeID ? dataset?.getAttribute(_yAttributeID)?.name : undefined const yAxis = content.getAxis("left") const yNumericAxis = isNumericAxisModel(yAxis) ? yAxis : undefined const yLowerBound = yNumericAxis?.min const yUpperBound = yNumericAxis?.max - const y2AttributeID = dataConfiguration.attributeDescriptionForRole("rightNumeric")?.attributeID - const y2AttributeName = y2AttributeID ? dataset?.getAttribute(y2AttributeID)?.name : undefined + const _y2AttributeID = dataConfiguration.attributeDescriptionForRole("rightNumeric")?.attributeID + const y2AttributeID = maybeToV2Id(_y2AttributeID) + const y2AttributeName = _y2AttributeID ? dataset?.getAttribute(_y2AttributeID)?.name : undefined const y2Axis = content.getAxis("rightNumeric") const y2NumericAxis = isNumericAxisModel(y2Axis) ? y2Axis : undefined const y2LowerBound = y2NumericAxis?.min From 81330c4d376b8b8d3425a54ade23171f015faf32 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 10:07:01 -0800 Subject: [PATCH 3/8] Update jest test. --- .../graph/component-handler-graph.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/v3/src/components/graph/component-handler-graph.test.ts b/v3/src/components/graph/component-handler-graph.test.ts index 6bd306b26..fee3dd1a3 100644 --- a/v3/src/components/graph/component-handler-graph.test.ts +++ b/v3/src/components/graph/component-handler-graph.test.ts @@ -205,35 +205,35 @@ describe("DataInteractive ComponentHandler Graph", () => { expect(numberToggleLastMode).toBe(content.showOnlyLastCase) const captionAttributeId = dataConfiguration.attributeDescriptionForRole("caption")!.attributeID - expect(captionAttributeID).toBe(captionAttributeId) + expect(captionAttributeID).toBe(toV2Id(captionAttributeId)) expect(captionAttributeName).toBe(graphDataset.getAttribute(captionAttributeId)?.name) const legendAttributeId = dataConfiguration.attributeDescriptionForRole("legend")!.attributeID - expect(legendAttributeID).toBe(legendAttributeId) + expect(legendAttributeID).toBe(toV2Id(legendAttributeId)) expect(legendAttributeName).toBe(graphDataset.getAttribute(legendAttributeId)?.name) const rightSplitId = dataConfiguration.attributeDescriptionForRole("rightSplit")!.attributeID - expect(rightSplitAttributeID).toBe(rightSplitId) + expect(rightSplitAttributeID).toBe(toV2Id(rightSplitId)) expect(rightSplitAttributeName).toBe(graphDataset.getAttribute(rightSplitId)?.name) const topSplitId = dataConfiguration.attributeDescriptionForRole("topSplit")!.attributeID - expect(topSplitAttributeID).toBe(topSplitId) + expect(topSplitAttributeID).toBe(toV2Id(topSplitId)) expect(topSplitAttributeName).toBe(graphDataset.getAttribute(topSplitId)?.name) const xAttributeId = dataConfiguration.attributeDescriptionForRole("x")!.attributeID - expect(xAttributeID).toBe(xAttributeId) + expect(xAttributeID).toBe(toV2Id(xAttributeId)) expect(xAttributeName).toBe(graphDataset.getAttribute(xAttributeId)?.name) expect(xLowerBound).toBe(xAxis.min) expect(xUpperBound).toBe(xAxis.max) const yAttributeId = dataConfiguration.attributeDescriptionForRole("y")!.attributeID - expect(yAttributeID).toBe(yAttributeId) + expect(yAttributeID).toBe(toV2Id(yAttributeId)) expect(yAttributeName).toBe(graphDataset.getAttribute(yAttributeId)?.name) expect(yLowerBound).toBe(yAxis.min) expect(yUpperBound).toBe(yAxis.max) const y2AttributeId = dataConfiguration.attributeDescriptionForRole("rightNumeric")!.attributeID - expect(y2AttributeID).toBe(y2AttributeId) + expect(y2AttributeID).toBe(toV2Id(y2AttributeId)) expect(y2AttributeName).toBe(graphDataset.getAttribute(y2AttributeId)?.name) expect(y2LowerBound).toBe(y2Axis.min) expect(y2UpperBound).toBe(y2Axis.max) From 3b00e2d070a1b866945ba162c71b84eb98df9b89 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 11:52:12 -0800 Subject: [PATCH 4/8] Handle yAttributeIDs and yAttributeNames in update graph API requests. --- v3/src/components/graph/components/graph.tsx | 2 +- v3/src/components/graph/graph-component-handler.ts | 13 +++++++++++-- .../graph/models/graph-data-configuration-model.ts | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/v3/src/components/graph/components/graph.tsx b/v3/src/components/graph/components/graph.tsx index 0e84ecd63..20b0e05e3 100644 --- a/v3/src/components/graph/components/graph.tsx +++ b/v3/src/components/graph/components/graph.tsx @@ -236,7 +236,7 @@ export const Graph = observer(function Graph({graphController, graphRef, pixiPoi let disposer: Maybe if (graphModel) { disposer = onAnyAction(graphModel, action => { - const dataConfigActions = ["setAttribute", "replaceYAttribute", "removeYAttributeAtIndex"] + const dataConfigActions = ["replaceYAttribute", "replaceYAttributes", "removeYAttributeAtIndex", "setAttribute"] if (dataConfigActions.includes(action.name) || isSetAttributeIDAction(action)) { startAnimation() graphController?.handleAttributeAssignment() diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index 4a9b75472..1a8ea3cb2 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -259,7 +259,8 @@ export const graphComponentHandler: DIComponentHandler = { const { dataContext: _dataContext, enableNumberToggle: showParentToggles, numberToggleLastMode: showOnlyLastCase, - xLowerBound, xUpperBound, yAttributeID, yAttributeName, yLowerBound, yUpperBound, y2LowerBound, y2UpperBound + xLowerBound, xUpperBound, yAttributeID, yAttributeIDs, yAttributeName, yAttributeNames, + yLowerBound, yUpperBound, y2LowerBound, y2UpperBound } = values as V2GetGraph const attributeInfo = getAttributeInfo(values) @@ -323,7 +324,15 @@ export const graphComponentHandler: DIComponentHandler = { // Any attribute can be put on the y axis, so we don't check to make sure the attribute is legal first // We don't use dataConfiguration.setAttribute() to make the change because that clears additional y attributes - if (yAttributeID !== undefined) { + if (yAttributeIDs != null) { + content.dataConfiguration.replaceYAttributes(yAttributeIDs.map(id => ({ attributeID: toV3AttrId(id) }))) + } else if (yAttributeNames != null) { + const descriptions = yAttributeNames.map(name => { + const attribute = dataSet?.getAttributeByName(name) + if (attribute) return { attributeID: attribute.id } + }).filter(desc => !!desc) + content.dataConfiguration.replaceYAttributes(descriptions) + } else if (yAttributeID !== undefined) { if (yAttributeID) { content.dataConfiguration.replaceYAttribute({ attributeID: toV3AttrId(yAttributeID) }, 0) } else { diff --git a/v3/src/components/graph/models/graph-data-configuration-model.ts b/v3/src/components/graph/models/graph-data-configuration-model.ts index 23d0a1c37..241c8a5ac 100644 --- a/v3/src/components/graph/models/graph-data-configuration-model.ts +++ b/v3/src/components/graph/models/graph-data-configuration-model.ts @@ -646,6 +646,12 @@ export const GraphDataConfigurationModel = DataConfigurationModel if (self._yAttributeDescriptions[plotNumber]) self.removeYAttributeAtIndex(plotNumber) if (desc) self.addYAttribute(desc, plotNumber) }, + replaceYAttributes(descriptions: IAttributeDescriptionSnapshot[]) { + self._yAttributeDescriptions.clear() + descriptions.forEach(description => { + self.addYAttribute(description) + }) + }, removeYAttributeWithID(id: string) { const index = self._yAttributeDescriptions.findIndex((aDesc) => aDesc.attributeID === id) self.removeYAttributeAtIndex(index) From f8d7ed32ba802a0bc368365dd259696126b4ad45 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 12:38:42 -0800 Subject: [PATCH 5/8] Support yAttributeIDs and yAttributeNames in create graph API requests. --- .../graph/graph-component-handler.ts | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index 1a8ea3cb2..be1f13451 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -72,7 +72,7 @@ export const graphComponentHandler: DIComponentHandler = { create({ values }) { const { dataContext: _dataContext, enableNumberToggle: showParentToggles, numberToggleLastMode: showOnlyLastCase, - yAttributeID, yAttributeName, + yAttributeID, yAttributeIDs, yAttributeName, yAttributeNames } = values as V2Graph const attributeInfo = getAttributeInfo(values) @@ -100,15 +100,27 @@ export const graphComponentHandler: DIComponentHandler = { } } - let yAttribute: Maybe - if (yAttributeID != null) { - yAttribute = dataset.getAttribute(toV3AttrId(yAttributeID)) - } - if (!yAttribute && yAttributeName != null) { - yAttribute = dataset.getAttributeByName(yAttributeName) - } - if (yAttribute) { - _yAttributeDescriptions.push({ attributeID: yAttribute.id, type: yAttribute.type }) + if (yAttributeIDs) { + yAttributeIDs.forEach(id => { + const attribute = dataset.getAttribute(toV3AttrId(id)) + if (attribute) _yAttributeDescriptions.push({ attributeID: attribute.id }) + }) + } else if (yAttributeNames) { + yAttributeNames.forEach(name => { + const attribute = dataset.getAttributeByName(name) + if (attribute) _yAttributeDescriptions.push({ attributeID: attribute.id }) + }) + } else { + let yAttribute: Maybe + if (yAttributeID != null) { + yAttribute = dataset.getAttribute(toV3AttrId(yAttributeID)) + } + if (!yAttribute && yAttributeName != null) { + yAttribute = dataset.getAttributeByName(yAttributeName) + } + if (yAttribute) { + _yAttributeDescriptions.push({ attributeID: yAttribute.id, type: yAttribute.type }) + } } if (showOnlyLastCase) { From 884b83b7e84b48997f55162d9335df7b41866495 Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 13:37:43 -0800 Subject: [PATCH 6/8] Expand jest tests. --- .../graph/component-handler-graph.test.ts | 64 ++++++++++++++++++- .../data-interactive-component-types.ts | 2 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/v3/src/components/graph/component-handler-graph.test.ts b/v3/src/components/graph/component-handler-graph.test.ts index fee3dd1a3..c2d046e9a 100644 --- a/v3/src/components/graph/component-handler-graph.test.ts +++ b/v3/src/components/graph/component-handler-graph.test.ts @@ -84,6 +84,40 @@ describe("DataInteractive ComponentHandler Graph", () => { handler.delete!({ component: tileIds }) expect(documentContent.tileMap.size).toBe(0) + // Create a graph with multiple y attributes using ids + const resultYIDs = handler.create!({}, { + type: "graph", dataContext: "data", yAttributeIDs: [toV2Id(a3.id), toV2Id(a4.id)] + }) + expect(resultYIDs.success).toBe(true) + const resultYIDsValues = resultYIDs.values as DIComponentInfo + const tileYIDs = documentContent.tileMap.get(toV3Id(kGraphIdPrefix, resultYIDsValues.id!))! + expect(tileYIDs).toBeDefined() + expect(isGraphContentModel(tileYIDs.content)).toBe(true) + const tileContentYIDs = tileYIDs.content as IGraphContentModel + expect(tileContentYIDs.dataConfiguration._yAttributeDescriptions.length).toBe(2) + expect(tileContentYIDs.dataConfiguration._yAttributeDescriptions[0].attributeID).toBe(a3.id) + expect(tileContentYIDs.dataConfiguration._yAttributeDescriptions[1].attributeID).toBe(a4.id) + // Delete the graph when we're finished + handler.delete!({ component: tileYIDs }) + expect(documentContent.tileMap.size).toBe(0) + + // Create a graph with multiple y attributes using names + const resultYNames = handler.create!({}, { + type: "graph", dataContext: "data", yAttributeNames: [a3.name, a4.name] + }) + expect(resultYNames.success).toBe(true) + const resultYNamesValues = resultYNames.values as DIComponentInfo + const tileYNames = documentContent.tileMap.get(toV3Id(kGraphIdPrefix, resultYNamesValues.id!))! + expect(tileYNames).toBeDefined() + expect(isGraphContentModel(tileYNames.content)).toBe(true) + const tileContentYNames = tileYNames.content as IGraphContentModel + expect(tileContentYNames.dataConfiguration._yAttributeDescriptions.length).toBe(2) + expect(tileContentYNames.dataConfiguration._yAttributeDescriptions[0].attributeID).toBe(a3.id) + expect(tileContentYNames.dataConfiguration._yAttributeDescriptions[1].attributeID).toBe(a4.id) + // Delete the graph when we're finished + handler.delete!({ component: tileYNames }) + expect(documentContent.tileMap.size).toBe(0) + // Create a graph with options const result = handler.create!({}, { type: "graph", cannotClose: true, dataContext: "data", xAttributeName: "a3", yAttributeName: "a4", @@ -188,13 +222,37 @@ describe("DataInteractive ComponentHandler Graph", () => { }) expect(dataConfig.attributeDescriptionForRole("rightNumeric")?.attributeID).toBe(a3.id) + // Update to remove y attributes + const updateResultRemoveYs = handler.update!({ component: tile }, { + yAttributeNames: [] as string[] + } as V2Graph) + expect(updateResultRemoveYs.success).toBe(true) + expect(dataConfig._yAttributeDescriptions.length).toBe(0) + + // Update to set multiple y attributes with names + const updateResultYNames = handler.update!({ component: tile }, { + yAttributeNames: [a4.name, a3.name] + } as V2Graph) + expect(updateResultYNames.success).toBe(true) + expect(dataConfig._yAttributeDescriptions.length).toBe(2) + expect(dataConfig._yAttributeDescriptions[0].attributeID).toBe(a4.id) + expect(dataConfig._yAttributeDescriptions[1].attributeID).toBe(a3.id) + + // Update to set y attributes with ids + const updateResultYIDs = handler.update!({ component: tile }, { + yAttributeIDs: [toV2Id(a3.id)] + } as V2Graph) + expect(updateResultYIDs.success).toBe(true) + expect(dataConfig._yAttributeDescriptions.length).toBe(1) + expect(dataConfig._yAttributeDescriptions[0].attributeID).toBe(a3.id) + // Get graph testGetComponent(tile, handler, (graphTile, values) => { const { dataContext, enableNumberToggle, numberToggleLastMode, captionAttributeID, captionAttributeName, legendAttributeID, legendAttributeName, rightSplitAttributeID, rightSplitAttributeName, topSplitAttributeID, topSplitAttributeName, xAttributeID, xAttributeName, xLowerBound, xUpperBound, - yAttributeID, yAttributeName, yLowerBound, yUpperBound, + yAttributeID, yAttributeIDs, yAttributeName, yAttributeNames, yLowerBound, yUpperBound, y2AttributeID, y2AttributeName, y2LowerBound, y2UpperBound } = values as V2GetGraph const content = graphTile.content as IGraphContentModel @@ -228,7 +286,11 @@ describe("DataInteractive ComponentHandler Graph", () => { const yAttributeId = dataConfiguration.attributeDescriptionForRole("y")!.attributeID expect(yAttributeID).toBe(toV2Id(yAttributeId)) + expect(yAttributeIDs?.length).toBe(1) + expect(yAttributeIDs?.[0]).toBe(toV2Id(a3.id)) expect(yAttributeName).toBe(graphDataset.getAttribute(yAttributeId)?.name) + expect(yAttributeNames?.length).toBe(1) + expect(yAttributeNames?.[0]).toBe(a3.name) expect(yLowerBound).toBe(yAxis.min) expect(yUpperBound).toBe(yAxis.max) diff --git a/v3/src/data-interactive/data-interactive-component-types.ts b/v3/src/data-interactive/data-interactive-component-types.ts index 7c4c9ce78..15ebb6259 100644 --- a/v3/src/data-interactive/data-interactive-component-types.ts +++ b/v3/src/data-interactive/data-interactive-component-types.ts @@ -81,7 +81,7 @@ export interface V2Graph extends V2Component { xAttributeID?: string | null xAttributeName?: string | null yAttributeID?: string | null - yAttributeIDs?: string[] + yAttributeIDs?: number[] yAttributeName?: string | null yAttributeNames?: string[] y2AttributeID?: string | null From 26a5afcf9db0937f0b7c51bc04f7b18c98f3ab3e Mon Sep 17 00:00:00 2001 From: William Finzer Date: Wed, 11 Dec 2024 16:19:44 -0800 Subject: [PATCH 7/8] * Changes to make sure that during an API request for a graph with multiple y-attributes the `graphDataConfigurationModel` has the desired number of subArrays in its filteredCases array. --- .../components/graph/graph-component-handler.ts | 6 ++++-- .../models/graph-data-configuration-model.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index be1f13451..47286c9e9 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -1,4 +1,4 @@ -import { getSnapshot } from "mobx-state-tree" +import { destroy, getSnapshot } from "mobx-state-tree" import { V2GetGraph, V2Graph } from "../../data-interactive/data-interactive-component-types" import { DIValues } from "../../data-interactive/data-interactive-types" import { DIComponentHandler } from "../../data-interactive/handlers/component-handler" @@ -197,7 +197,9 @@ export const graphComponentHandler: DIComponentHandler = { } }) } - return { content: { ...getSnapshot(graphModel), layers: finalLayers } as ITileContentSnapshotWithType } + const result = { content: { ...getSnapshot(graphModel), layers: finalLayers } as ITileContentSnapshotWithType } + destroy(graphModel) + return result }, get(content: ITileContentModel) { diff --git a/v3/src/components/graph/models/graph-data-configuration-model.ts b/v3/src/components/graph/models/graph-data-configuration-model.ts index 241c8a5ac..0dd79b457 100644 --- a/v3/src/components/graph/models/graph-data-configuration-model.ts +++ b/v3/src/components/graph/models/graph-data-configuration-model.ts @@ -662,6 +662,21 @@ export const GraphDataConfigurationModel = DataConfigurationModel self.rowCases.invalidateAll() self.columnCases.invalidateAll() self.cellCases.invalidateAll() + }, + handleDataSetChange(data?: IDataSet) { + self.actionHandlerDisposer?.() + self.actionHandlerDisposer = undefined + self._clearFilteredCases(data) + const yAttributeDescriptions = getSnapshot(self._yAttributeDescriptions) + const _y2AttributeDescription = self._attributeDescriptions.get("rightNumeric") + const y2AttributeDescription = _y2AttributeDescription + ? { y2AttributeDescription: getSnapshot(_y2AttributeDescription) } + : undefined + const yAttrCount = yAttributeDescriptions.length + (y2AttributeDescription ? 1 : 0) + const filteredCasesRequired = Math.max(1, yAttrCount) + while (self.dataset && self.filteredCases.length < filteredCasesRequired) { + self._addNewFilteredCases() + } } })) .actions(self => { From 5fe757d5b8cb9a6cf7e07b2568e7a84a7ca4d74b Mon Sep 17 00:00:00 2001 From: Teale Fristoe Date: Wed, 11 Dec 2024 20:03:19 -0800 Subject: [PATCH 8/8] Clean up filteredCases synchronizing functions in GraphDataConfigurationModel. --- .../graph/graph-component-handler.ts | 1 + .../models/graph-data-configuration-model.ts | 57 +++++++++---------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/v3/src/components/graph/graph-component-handler.ts b/v3/src/components/graph/graph-component-handler.ts index 47286c9e9..743900a47 100644 --- a/v3/src/components/graph/graph-component-handler.ts +++ b/v3/src/components/graph/graph-component-handler.ts @@ -198,6 +198,7 @@ export const graphComponentHandler: DIComponentHandler = { }) } const result = { content: { ...getSnapshot(graphModel), layers: finalLayers } as ITileContentSnapshotWithType } + // After we get the snapshot, destroy the model to stop all reactions destroy(graphModel) return result }, diff --git a/v3/src/components/graph/models/graph-data-configuration-model.ts b/v3/src/components/graph/models/graph-data-configuration-model.ts index 0dd79b457..99e952cf5 100644 --- a/v3/src/components/graph/models/graph-data-configuration-model.ts +++ b/v3/src/components/graph/models/graph-data-configuration-model.ts @@ -98,6 +98,14 @@ export const GraphDataConfigurationModel = DataConfigurationModel return this.placeCanShowClickHereCue(place) && !self.attributeID(graphPlaceToAttrRole[place === 'left' ? 'bottom' : 'left']) }, + get allYAttributeDescriptions() { + const yAttributeDescriptions = getSnapshot(self._yAttributeDescriptions) + const _y2AttributeDescription = self._attributeDescriptions.get("rightNumeric") + const y2AttributeDescription = _y2AttributeDescription + ? { y2AttributeDescription: getSnapshot(_y2AttributeDescription) } + : undefined + return { yAttributeDescriptions, ...y2AttributeDescription } + } })) .views(self => { const baseRolesForAttribute = self.rolesForAttribute @@ -145,6 +153,21 @@ export const GraphDataConfigurationModel = DataConfigurationModel } else { self._attributeDescriptions.delete(iRole) } + }, + synchronizeFilteredCases(descriptions?: { + yAttributeDescriptions: IAttributeDescriptionSnapshot[], y2AttributeDescription?: IAttributeDescriptionSnapshot + }) { + const { yAttributeDescriptions, y2AttributeDescription } = descriptions ?? self.allYAttributeDescriptions + const yAttrCount = yAttributeDescriptions.length + (y2AttributeDescription ? 1 : 0) + const filteredCasesRequired = Math.max(1, yAttrCount) + // remove any extraneous filteredCases + while (self.filteredCases.length > filteredCasesRequired) { + self.filteredCases.pop()?.destroy() + } + // add any required filteredCases + while (self.dataset && self.filteredCases.length < filteredCasesRequired) { + self._addNewFilteredCases() + } } })) .views(self => ({ @@ -667,16 +690,7 @@ export const GraphDataConfigurationModel = DataConfigurationModel self.actionHandlerDisposer?.() self.actionHandlerDisposer = undefined self._clearFilteredCases(data) - const yAttributeDescriptions = getSnapshot(self._yAttributeDescriptions) - const _y2AttributeDescription = self._attributeDescriptions.get("rightNumeric") - const y2AttributeDescription = _y2AttributeDescription - ? { y2AttributeDescription: getSnapshot(_y2AttributeDescription) } - : undefined - const yAttrCount = yAttributeDescriptions.length + (y2AttributeDescription ? 1 : 0) - const filteredCasesRequired = Math.max(1, yAttrCount) - while (self.dataset && self.filteredCases.length < filteredCasesRequired) { - self._addNewFilteredCases() - } + self.synchronizeFilteredCases() } })) .actions(self => { @@ -695,26 +709,9 @@ export const GraphDataConfigurationModel = DataConfigurationModel afterCreate() { // synchronize filteredCases with attribute configuration addDisposer(self, reaction( - () => { - const yAttributeDescriptions = getSnapshot(self._yAttributeDescriptions) - const _y2AttributeDescription = self._attributeDescriptions.get("rightNumeric") - const y2AttributeDescription = _y2AttributeDescription - ? { y2AttributeDescription: getSnapshot(_y2AttributeDescription) } - : undefined - return { yAttributeDescriptions, ...y2AttributeDescription } - }, - ({ yAttributeDescriptions, y2AttributeDescription }) => { - const yAttrCount = yAttributeDescriptions.length + (y2AttributeDescription ? 1 : 0) - const filteredCasesRequired = Math.max(1, yAttrCount) - // remove any extraneous filteredCases - while (self.filteredCases.length > filteredCasesRequired) { - self.filteredCases.pop()?.destroy() - } - // add any required filteredCases - while (self.dataset && self.filteredCases.length < filteredCasesRequired) { - self._addNewFilteredCases() - } - }, { name: "GraphDataConfigurationModel yAttrDescriptions reaction", equals: comparer.structural } + () => self.allYAttributeDescriptions, + (allYAttributeDescriptions) => self.synchronizeFilteredCases(allYAttributeDescriptions), + { name: "GraphDataConfigurationModel yAttrDescriptions reaction", equals: comparer.structural } )) addDisposer(self, reaction( () => self.getAllCellKeys(),