diff --git a/src/app/stores/action_handlers/document.ts b/src/app/stores/action_handlers/document.ts index aa9602c70..3ae37bf23 100644 --- a/src/app/stores/action_handlers/document.ts +++ b/src/app/stores/action_handlers/document.ts @@ -374,6 +374,7 @@ export default function (REG: ActionHandlerRegistry) { } this.updatePlotSegments(); + this.updateNestedCharts(); this.updateDataAxes(); this.updateScales(); this.solveConstraintsAndUpdateGraphics(); diff --git a/src/app/stores/app_store.ts b/src/app/stores/app_store.ts index 6400cfdf6..c480c3396 100644 --- a/src/app/stores/app_store.ts +++ b/src/app/stores/app_store.ts @@ -96,6 +96,7 @@ import { } from "../../core/prototypes/plot_segments/utils"; import { AxisRenderer } from "../../core/prototypes/plot_segments/axis"; import { CompiledGroupBy } from "../../core/prototypes/group_by"; +import glyph from "./action_handlers/glyph"; export interface ChartStoreStateSolverStatus { solving: boolean; @@ -1671,6 +1672,17 @@ export class AppStore extends BaseStore { }); } + public updateNestedCharts() { + const nestedCharts = this.chart.glyphs.flatMap(g => g.marks.map(m => ({glyph: g, mark: m}))).filter( + ({ mark }) => Prototypes.isType(mark.classID, "mark.nested-chart") + ); + + debugger; + nestedCharts.forEach(({ glyph, mark: nestedCharts }) => { + debugger; + }); + } + public updateDataAxes() { const mapElementWithTable = (table: string) => (el: any) => { return { @@ -2455,6 +2467,7 @@ export class AppStore extends BaseStore { }); this.chartState = this.chartManager.chartState; this.updatePlotSegments(); + this.updateNestedCharts(); this.updateDataAxes(); this.updateScales(); this.solveConstraintsAndUpdateGraphics(); diff --git a/src/container/chart_component.tsx b/src/container/chart_component.tsx index a8759883b..c2710d9f1 100644 --- a/src/container/chart_component.tsx +++ b/src/container/chart_component.tsx @@ -271,11 +271,11 @@ export class ChartComponent extends React.Component< return (element, event) => { const rowIndices = element.rowIndices; const modifiers = { - ctrlKey: event.ctrlKey, - shiftKey: event.shiftKey, - metaKey: event.metaKey, - clientX: (event as any).clientX, - clientY: (event as any).clientY, + ctrlKey: event?.ctrlKey, + shiftKey: event?.shiftKey, + metaKey: event?.metaKey, + clientX: (event as any)?.clientX, + clientY: (event as any)?.clientY, event, }; handler({ table: element.plotSegment?.table, rowIndices }, modifiers); diff --git a/src/container/chart_template.ts b/src/container/chart_template.ts index 136729ba1..b59dd9744 100644 --- a/src/container/chart_template.ts +++ b/src/container/chart_template.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines-per-function */ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. @@ -24,10 +25,11 @@ import { import { CompiledGroupBy } from "../core/prototypes/group_by"; import { OrderType } from "../core/specification/spec_types"; import { DataAxisExpression } from "../core/prototypes/marks/data_axis.attrs"; -import { MappingType, ScaleMapping, ValueMapping } from "../core/specification"; +import { IObject, MappingType, ScaleMapping, ValueMapping } from "../core/specification"; import { Region2DSublayoutOptions } from "../core/prototypes/plot_segments/region_2d/base"; import { GuideAttributeNames } from "../core/prototypes/guides"; import { scaleLinear } from "d3-scale"; +import { NestedChartElementProperties } from "../core/prototypes/marks/nested_chart.attrs"; export interface TemplateInstance { chart: Specification.Chart; @@ -139,209 +141,216 @@ export class ChartTemplate { const chart = deepClone(this.template.specification); // Transform table and expressions with current assignments - for (const item of forEachObject(chart)) { - // Replace table with assigned table - if (item.kind == "chart-element") { - // legend with column names - if (Prototypes.isType(item.chartElement.classID, "legend.custom")) { - const scaleMapping = item.chartElement.mappings - .mappingOptions as ScaleMapping; - scaleMapping.expression = this.transformExpression( - scaleMapping.expression, - scaleMapping.table - ); - } - // Guide - if (Prototypes.isType(item.chartElement.classID, "guide.guide")) { - const valueProp = this.template.properties.filter( - (p) => - p.objectID === item.chartElement._id && - p.target.attribute === GuideAttributeNames.value - )[0]; - if (valueProp) { - const valueMapping: Specification.ValueMapping = { - type: MappingType.value, - value: valueProp.default as number, - }; - item.chartElement.mappings.value = valueMapping; - } - } - // PlotSegment - if (Prototypes.isType(item.chartElement.classID, "plot-segment")) { - const plotSegment = item.chartElement as Specification.PlotSegment; - const originalTable = plotSegment.table; - plotSegment.table = this.tableAssignment[originalTable]; - // Also fix filter and gropyBy expressions - if (plotSegment.filter) { - if (plotSegment.filter.categories) { - plotSegment.filter.categories.expression = this.transformExpression( - plotSegment.filter.categories.expression, - originalTable - ); - } - if (plotSegment.filter.expression) { - plotSegment.filter.expression = this.transformExpression( - plotSegment.filter.expression, - originalTable - ); - } + const transformChart = (chart) => { + for (const item of forEachObject(chart)) { + // Replace table with assigned table + if (item.kind == "chart-element") { + // legend with column names + if (Prototypes.isType(item.chartElement.classID, "legend.custom")) { + const scaleMapping = item.chartElement.mappings + .mappingOptions as ScaleMapping; + scaleMapping.expression = this.transformExpression( + scaleMapping.expression, + scaleMapping.table + ); } - if (plotSegment.groupBy) { - if (plotSegment.groupBy.expression) { - plotSegment.groupBy.expression = this.transformExpression( - plotSegment.groupBy.expression, - originalTable - ); + + // Guide + if (Prototypes.isType(item.chartElement.classID, "guide.guide")) { + const valueProp = this.template.properties.filter( + (p) => p.objectID === item.chartElement._id && + p.target.attribute === GuideAttributeNames.value + )[0]; + if (valueProp) { + const valueMapping: Specification.ValueMapping = { + type: MappingType.value, + value: valueProp.default as number, + }; + item.chartElement.mappings.value = valueMapping; } } - if (plotSegment.properties.xData) { - if ((plotSegment.properties.xData as any).expression) { - (plotSegment.properties - .xData as any).expression = this.transformExpression( - (plotSegment.properties.xData as any).expression, - originalTable - ); - } - if ((plotSegment.properties.xData as any).rawExpression) { - (plotSegment.properties - .xData as any).rawExpression = this.transformExpression( - (plotSegment.properties.xData as any).rawExpression, - originalTable - ); + + // PlotSegment + if (Prototypes.isType(item.chartElement.classID, "plot-segment")) { + const plotSegment = item.chartElement as Specification.PlotSegment; + const originalTable = plotSegment.table; + plotSegment.table = this.tableAssignment[originalTable]; + // Also fix filter and gropyBy expressions + if (plotSegment.filter) { + if (plotSegment.filter.categories) { + plotSegment.filter.categories.expression = this.transformExpression( + plotSegment.filter.categories.expression, + originalTable + ); + } + if (plotSegment.filter.expression) { + plotSegment.filter.expression = this.transformExpression( + plotSegment.filter.expression, + originalTable + ); + } } - } - if (plotSegment.properties.yData) { - if ((plotSegment.properties.yData as any).expression) { - (plotSegment.properties - .yData as any).expression = this.transformExpression( - (plotSegment.properties.yData as any).expression, - originalTable - ); + if (plotSegment.groupBy) { + if (plotSegment.groupBy.expression) { + plotSegment.groupBy.expression = this.transformExpression( + plotSegment.groupBy.expression, + originalTable + ); + } } - if ((plotSegment.properties.yData as any).rawExpression) { - (plotSegment.properties - .yData as any).rawExpression = this.transformExpression( - (plotSegment.properties.yData as any).rawExpression, - originalTable - ); + if (plotSegment.properties.xData) { + if ((plotSegment.properties.xData as any).expression) { + (plotSegment.properties + .xData as any).expression = this.transformExpression( + (plotSegment.properties.xData as any).expression, + originalTable + ); + } + if ((plotSegment.properties.xData as any).rawExpression) { + (plotSegment.properties + .xData as any).rawExpression = this.transformExpression( + (plotSegment.properties.xData as any).rawExpression, + originalTable + ); + } } - } - if (plotSegment.properties.axis) { - if ((plotSegment.properties.axis as any).expression) { - (plotSegment.properties - .axis as any).expression = this.transformExpression( - (plotSegment.properties.axis as any).expression, - originalTable - ); + if (plotSegment.properties.yData) { + if ((plotSegment.properties.yData as any).expression) { + (plotSegment.properties + .yData as any).expression = this.transformExpression( + (plotSegment.properties.yData as any).expression, + originalTable + ); + } + if ((plotSegment.properties.yData as any).rawExpression) { + (plotSegment.properties + .yData as any).rawExpression = this.transformExpression( + (plotSegment.properties.yData as any).rawExpression, + originalTable + ); + } } - if ((plotSegment.properties.axis as any).rawExpression) { - (plotSegment.properties - .axis as any).rawExpression = this.transformExpression( - (plotSegment.properties.axis as any).rawExpression, - originalTable - ); + if (plotSegment.properties.axis) { + if ((plotSegment.properties.axis as any).expression) { + (plotSegment.properties + .axis as any).expression = this.transformExpression( + (plotSegment.properties.axis as any).expression, + originalTable + ); + } + if ((plotSegment.properties.axis as any).rawExpression) { + (plotSegment.properties + .axis as any).rawExpression = this.transformExpression( + (plotSegment.properties.axis as any).rawExpression, + originalTable + ); + } } - } - if (plotSegment.properties.sublayout) { - const expression = (plotSegment.properties - .sublayout as Region2DSublayoutOptions).order?.expression; - if (expression) { - (plotSegment.properties - .sublayout as Region2DSublayoutOptions).order.expression = this.transformExpression( - expression, - originalTable - ); + if (plotSegment.properties.sublayout) { + const expression = (plotSegment.properties + .sublayout as Region2DSublayoutOptions).order?.expression; + if (expression) { + (plotSegment.properties + .sublayout as Region2DSublayoutOptions).order.expression = this.transformExpression( + expression, + originalTable + ); + } } } - } - // Links - if (Prototypes.isType(item.chartElement.classID, "links")) { - if (item.chartElement.classID == "links.through") { - const props = item.chartElement - .properties as Prototypes.Links.LinksProperties; - if (props.linkThrough.facetExpressions) { - props.linkThrough.facetExpressions = props.linkThrough.facetExpressions.map( - (x) => - this.transformExpression( + // Links + if (Prototypes.isType(item.chartElement.classID, "links")) { + if (item.chartElement.classID == "links.through") { + const props = item.chartElement + .properties as Prototypes.Links.LinksProperties; + if (props.linkThrough.facetExpressions) { + props.linkThrough.facetExpressions = props.linkThrough.facetExpressions.map( + (x) => this.transformExpression( x, (getById( this.template.specification.elements, props.linkThrough.plotSegment ) as Specification.PlotSegment).table ) - ); + ); + } + } + if (item.chartElement.classID == "links.table") { + const props = item.chartElement + .properties as Prototypes.Links.LinksProperties; + props.linkTable.table = this.tableAssignment[props.linkTable.table]; } - } - if (item.chartElement.classID == "links.table") { - const props = item.chartElement - .properties as Prototypes.Links.LinksProperties; - props.linkTable.table = this.tableAssignment[props.linkTable.table]; } } - } - // Glyphs - if (item.kind == "glyph") { - item.glyph.table = this.tableAssignment[item.glyph.table]; - } + // Glyphs + if (item.kind == "glyph") { + item.glyph.table = this.tableAssignment[item.glyph.table]; + } - if (item.kind == "mark") { - if (Prototypes.isType(item.mark.classID, "mark.data-axis")) { - try { - const glyphId = item.glyph._id; + if (item.kind == "mark") { + if (Prototypes.isType(item.mark.classID, "mark.data-axis")) { + try { + const glyphId = item.glyph._id; - const glyphPlotSegment = [...forEachObject(chart)].find( - (item) => - item.kind == "chart-element" && - Prototypes.isType(item.chartElement.classID, "plot-segment") && - (item.chartElement as any).glyph === glyphId - ); + const glyphPlotSegment = [...forEachObject(chart)].find( + (item) => item.kind == "chart-element" && + Prototypes.isType(item.chartElement.classID, "plot-segment") && + (item.chartElement as any).glyph === glyphId + ); - const dataExpressions = item.mark.properties - .dataExpressions as DataAxisExpression[]; + const dataExpressions = item.mark.properties + .dataExpressions as DataAxisExpression[]; - // table name in plotSegment can be replaced already - const table = - Object.keys(this.tableAssignment).find( - (key) => - this.tableAssignment[key] === + // table name in plotSegment can be replaced already + const table = Object.keys(this.tableAssignment).find( + (key) => this.tableAssignment[key] === (glyphPlotSegment.chartElement as any).table ) || (glyphPlotSegment.chartElement as any).table; - dataExpressions.forEach((expression) => { - expression.expression = this.transformExpression( - expression.expression, - table - ); - }); - } catch (ex) { - console.error(ex); + dataExpressions.forEach((expression) => { + expression.expression = this.transformExpression( + expression.expression, + table + ); + }); + } catch (ex) { + console.error(ex); + } + } + if (Prototypes.isType(item.mark.classID, "mark.nested-chart")) { + // recursive call for nested chart + debugger; + const specification = (item.mark as IObject).properties.specification as Specification.Chart; + transformChart(specification); } } - } - // Replace data-mapping expressions with assigned columns - const mappings = item.object.mappings; - for (const [, mapping] of forEachMapping(mappings)) { - if (mapping.type == MappingType.scale) { - const scaleMapping = mapping as Specification.ScaleMapping; - scaleMapping.expression = this.transformExpression( - scaleMapping.expression, - scaleMapping.table - ); - scaleMapping.table = this.tableAssignment[scaleMapping.table]; - } - if (mapping.type == MappingType.text) { - const textMapping = mapping as Specification.TextMapping; - textMapping.textExpression = this.transformTextExpression( - textMapping.textExpression, - textMapping.table - ); - textMapping.table = this.tableAssignment[textMapping.table]; + // Replace data-mapping expressions with assigned columns + const mappings = item.object.mappings; + for (const [, mapping] of forEachMapping(mappings)) { + if (mapping.type == MappingType.scale) { + const scaleMapping = mapping as Specification.ScaleMapping; + scaleMapping.expression = this.transformExpression( + scaleMapping.expression, + scaleMapping.table + ); + scaleMapping.table = this.tableAssignment[scaleMapping.table]; + } + if (mapping.type == MappingType.text) { + const textMapping = mapping as Specification.TextMapping; + textMapping.textExpression = this.transformTextExpression( + textMapping.textExpression, + textMapping.table + ); + textMapping.table = this.tableAssignment[textMapping.table]; + } } } } + + transformChart(chart); if (!inference) { return { chart, @@ -369,216 +378,222 @@ export class ChartTemplate { }; // Perform inferences - for (const inference of this.template.inference) { - const object = findObjectById(chart, inference.objectID); - if (inference.expression) { - const expr = this.transformExpression( - inference.expression.expression, - inference.dataSource.table - ); - setProperty(object, inference.expression.property, expr); - } - if (inference.axis) { - const axis = inference.axis; - if (axis.type == "default") { - continue; + const chartInferences = async (chart, template) => { + for (const inference of template) { + const object = findObjectById(chart, inference.objectID); + if (inference.expression) { + const expr = this.transformExpression( + inference.expression.expression, + inference.dataSource.table + ); + setProperty(object, inference.expression.property, expr); } - const expression = this.transformExpression( - inference.axis.expression, - inference.dataSource.table - ); - const axisDataBinding = getProperty( - object, - axis.property - ) as SpecTypes.AxisDataBinding; - axisDataBinding.expression = expression; - if (inference.autoDomainMin || inference.autoDomainMax) { - // disableAuto flag responsible for disabling/enabling configulration scale domains when new data is coming - // If disableAuto is true, the same scales will be used for data - // Example: If disableAuto is true, axis values will be same for all new data sets. - let vector = getExpressionVector( - expression, - this.tableAssignment[inference.dataSource.table], - this.transformGroupBy( - inference.dataSource.groupBy, - inference.dataSource.table - ) + if (inference.axis) { + const axis = inference.axis; + if (axis.type == "default") { + continue; + } + const expression = this.transformExpression( + inference.axis.expression, + inference.dataSource.table ); - if (inference.axis.additionalExpressions) { - for (const item of inference.axis.additionalExpressions) { - const expr = this.transformExpression( - item, + const axisDataBinding = getProperty( + object, + axis.property + ) as SpecTypes.AxisDataBinding; + axisDataBinding.expression = expression; + if (inference.autoDomainMin || inference.autoDomainMax) { + // disableAuto flag responsible for disabling/enabling configulration scale domains when new data is coming + // If disableAuto is true, the same scales will be used for data + // Example: If disableAuto is true, axis values will be same for all new data sets. + let vector = getExpressionVector( + expression, + this.tableAssignment[inference.dataSource.table], + this.transformGroupBy( + inference.dataSource.groupBy, inference.dataSource.table - ); - vector = vector.concat( - getExpressionVector( - expr, - this.tableAssignment[inference.dataSource.table], - this.transformGroupBy( - inference.dataSource.groupBy, - inference.dataSource.table + ) + ); + if (inference.axis.additionalExpressions) { + for (const item of inference.axis.additionalExpressions) { + const expr = this.transformExpression( + item, + inference.dataSource.table + ); + vector = vector.concat( + getExpressionVector( + expr, + this.tableAssignment[inference.dataSource.table], + this.transformGroupBy( + inference.dataSource.groupBy, + inference.dataSource.table + ) ) - ) - ); + ); + } } - } - if (axis.type == "categorical") { - const scale = new Scale.CategoricalScale(); - scale.inferParameters( - vector, - inference.axis.orderMode || OrderType.Order - ); - axisDataBinding.categories = new Array(scale.domain.size); - const newData = new Array(scale.domain.size); - - scale.domain.forEach((index, key) => { - newData[index] = key; - }); - // try to save given order from template - if ( - axisDataBinding.order && - axisDataBinding.orderMode === OrderType.Order - ) { - axisDataBinding.order = axisDataBinding.order.filter((value) => - scale.domain.has(value) - ); - const newItems = newData.filter( - (category) => - !axisDataBinding.order.find((order) => order === category) + if (axis.type == "categorical") { + const scale = new Scale.CategoricalScale(); + scale.inferParameters( + vector, + inference.axis.orderMode || OrderType.Order ); - axisDataBinding.categories = new Array( - axisDataBinding.order.length - ); - axisDataBinding.order.forEach((value, index) => { - axisDataBinding.categories[index] = value; - }); - axisDataBinding.categories = axisDataBinding.categories.concat( - newItems - ); - axisDataBinding.order = axisDataBinding.order.concat(newItems); - } else { axisDataBinding.categories = new Array(scale.domain.size); + const newData = new Array(scale.domain.size); + scale.domain.forEach((index, key) => { - axisDataBinding.categories[index] = key; + newData[index] = key; }); - } - axisDataBinding.allCategories = deepClone( - axisDataBinding.categories - ); - - if (axisDataBinding.allowScrolling) { - const start = Math.floor( - ((axisDataBinding.categories.length - - axisDataBinding.windowSize) / - 100) * - axisDataBinding.scrollPosition - ); - axisDataBinding.categories = axisDataBinding.categories.slice( - start, - start + axisDataBinding.windowSize + // try to save given order from template + if ( + axisDataBinding.order && + axisDataBinding.orderMode === OrderType.Order + ) { + axisDataBinding.order = axisDataBinding.order.filter((value) => + scale.domain.has(value) + ); + const newItems = newData.filter( + (category) => + !axisDataBinding.order.find((order) => order === category) + ); + axisDataBinding.categories = new Array( + axisDataBinding.order.length + ); + axisDataBinding.order.forEach((value, index) => { + axisDataBinding.categories[index] = value; + }); + axisDataBinding.categories = axisDataBinding.categories.concat( + newItems + ); + axisDataBinding.order = axisDataBinding.order.concat(newItems); + } else { + axisDataBinding.categories = new Array(scale.domain.size); + scale.domain.forEach((index, key) => { + axisDataBinding.categories[index] = key; + }); + } + axisDataBinding.allCategories = deepClone( + axisDataBinding.categories ); - } - } else if (axis.type == "numerical") { - const scale = new Scale.LinearScale(); - scale.inferParameters(vector); - if (inference.autoDomainMin) { - axisDataBinding.dataDomainMin = scale.domainMin; - axisDataBinding.domainMin = scale.domainMin; - } - if (inference.autoDomainMax) { - axisDataBinding.dataDomainMax = scale.domainMax; - axisDataBinding.domainMax = scale.domainMax; - } - if (axisDataBinding.allowScrolling) { - const scrollScale = scaleLinear() - .domain([0, 100]) - .range([ - axisDataBinding.dataDomainMin, - axisDataBinding.dataDomainMax, - ]); - const start = scrollScale(axisDataBinding.scrollPosition); - axisDataBinding.domainMin = start; - axisDataBinding.domainMax = start + axisDataBinding.windowSize; - } else { + + if (axisDataBinding.allowScrolling) { + const start = Math.floor( + ((axisDataBinding.categories.length - + axisDataBinding.windowSize) / + 100) * + axisDataBinding.scrollPosition + ); + axisDataBinding.categories = axisDataBinding.categories.slice( + start, + start + axisDataBinding.windowSize + ); + } + } else if (axis.type == "numerical") { + const scale = new Scale.LinearScale(); + scale.inferParameters(vector); if (inference.autoDomainMin) { axisDataBinding.dataDomainMin = scale.domainMin; + axisDataBinding.domainMin = scale.domainMin; } if (inference.autoDomainMax) { axisDataBinding.dataDomainMax = scale.domainMax; + axisDataBinding.domainMax = scale.domainMax; + } + if (axisDataBinding.allowScrolling) { + const scrollScale = scaleLinear() + .domain([0, 100]) + .range([ + axisDataBinding.dataDomainMin, + axisDataBinding.dataDomainMax, + ]); + const start = scrollScale(axisDataBinding.scrollPosition); + axisDataBinding.domainMin = start; + axisDataBinding.domainMax = start + axisDataBinding.windowSize; + } else { + if (inference.autoDomainMin) { + axisDataBinding.dataDomainMin = scale.domainMin; + } + if (inference.autoDomainMax) { + axisDataBinding.dataDomainMax = scale.domainMax; + } + } + if (axis.defineCategories) { + axisDataBinding.categories = defineCategories(vector); } - } - if (axis.defineCategories) { - axisDataBinding.categories = defineCategories(vector); } } } - } - if (inference.scale) { - // uses disableAutoMin disableAutoMax for handle old templates - // copy old parameters to new - if ( - inference.autoDomainMin == null && - inference.disableAutoMin != null - ) { - inference.autoDomainMin = !inference.disableAutoMin; - } - // copy old parameters to new - if ( - inference.autoDomainMax == null && - inference.disableAutoMax != null - ) { - inference.autoDomainMax = !inference.disableAutoMax; - } - if (inference.autoDomainMin || inference.autoDomainMax) { - const scale = inference.scale; - const expressions = scale.expressions.map((x) => - this.transformExpression(x, inference.dataSource.table) - ); - const vectors = expressions.map((x) => - getExpressionVector( - x, - this.tableAssignment[inference.dataSource.table], - this.transformGroupBy( - inference.dataSource.groupBy, - inference.dataSource.table + if (inference.scale) { + // uses disableAutoMin disableAutoMax for handle old templates + // copy old parameters to new + if ( + inference.autoDomainMin == null && + inference.disableAutoMin != null + ) { + inference.autoDomainMin = !inference.disableAutoMin; + } + // copy old parameters to new + if ( + inference.autoDomainMax == null && + inference.disableAutoMax != null + ) { + inference.autoDomainMax = !inference.disableAutoMax; + } + if (inference.autoDomainMin || inference.autoDomainMax) { + const scale = inference.scale; + const expressions = scale.expressions.map((x) => + this.transformExpression(x, inference.dataSource.table) + ); + const vectors = expressions.map((x) => + getExpressionVector( + x, + this.tableAssignment[inference.dataSource.table], + this.transformGroupBy( + inference.dataSource.groupBy, + inference.dataSource.table + ) ) - ) - ); - - const vector = vectors.reduce((a, b) => a.concat(b), []); - const scaleClass = Prototypes.ObjectClasses.Create(null, object, { - attributes: {}, - }) as Prototypes.Scales.ScaleClass; - - if (object.classID === "scale.categorical") { - scaleClass.inferParameters(vector, { - reuseRange: true, - extendScaleMin: true, - extendScaleMax: true, - }); - } else { - scaleClass.inferParameters(vector, { - extendScaleMax: inference.autoDomainMax, - extendScaleMin: inference.autoDomainMin, - reuseRange: true, - rangeNumber: [ - (object.mappings.rangeMin as ValueMapping)?.value as number, - (object.mappings.rangeMax as ValueMapping)?.value as number, - ], - }); + ); + + const vector = vectors.reduce((a, b) => a.concat(b), []); + const scaleClass = Prototypes.ObjectClasses.Create(null, object, { + attributes: {}, + }) as Prototypes.Scales.ScaleClass; + + if (object.classID === "scale.categorical") { + scaleClass.inferParameters(vector, { + reuseRange: true, + extendScaleMin: true, + extendScaleMax: true, + }); + } else { + scaleClass.inferParameters(vector, { + extendScaleMax: inference.autoDomainMax, + extendScaleMin: inference.autoDomainMin, + reuseRange: true, + rangeNumber: [ + (object.mappings.rangeMin as ValueMapping)?.value as number, + (object.mappings.rangeMax as ValueMapping)?.value as number, + ], + }); + } } } - } - if (inference.nestedChart) { - const { nestedChart } = inference; - const columnNameMap: { [name: string]: string } = {}; - Object.keys(nestedChart.columnNameMap).forEach((key) => { - const newKey = this.columnAssignment[inference.dataSource.table][key]; - columnNameMap[newKey] = nestedChart.columnNameMap[key]; - }); - setProperty(object, "columnNameMap", columnNameMap); + if (inference.nestedChart) { + const { nestedChart } = inference; + const columnNameMap: { [name: string]: string } = {}; + Object.keys(nestedChart.columnNameMap).forEach((key) => { + const newKey = this.columnAssignment[inference.dataSource.table][key]; + columnNameMap[newKey] = nestedChart.columnNameMap[key]; + }); + setProperty(object, "columnNameMap", columnNameMap); + + const specification = (object as IObject).properties.specification as Specification.Chart; + chartInferences(specification, this.template.inference); + } } } + chartInferences(chart, this.template.inference); return { chart, defaultAttributes: this.template.defaultAttributes, diff --git a/src/core/common/color.ts b/src/core/common/color.ts index be1d31a93..c3916e6bc 100644 --- a/src/core/common/color.ts +++ b/src/core/common/color.ts @@ -384,37 +384,44 @@ const brewer12 = [ "#b15928", ].map(colorFromHTMLColor); -let defaultColorGeneratorFunction: (key: string) => Color = null; -let defaultColorGeneratorResetFunction: () => void; +// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-var +var colors: { + defaultColorGeneratorFunction: (key: string) => Color, + defaultColorGeneratorResetFunction: () => void +} = { + defaultColorGeneratorFunction: null, + defaultColorGeneratorResetFunction: null +}; + export function setDefaultColorPaletteGenerator( generatorFunction: (key: string) => Color ) { - defaultColorGeneratorFunction = generatorFunction; + colors.defaultColorGeneratorFunction = generatorFunction; } export function getDefaultColorPaletteGenerator() { - return defaultColorGeneratorFunction; + return colors.defaultColorGeneratorFunction; } export function setDefaultColorGeneratorResetFunction( resetFunction: () => void ) { - defaultColorGeneratorResetFunction = resetFunction; + colors.defaultColorGeneratorResetFunction = resetFunction; } export function getDefaultColorGeneratorResetFunction() { - return defaultColorGeneratorResetFunction; + return colors.defaultColorGeneratorResetFunction; } export function getDefaultColorPaletteByValue(value: string) { - return defaultColorGeneratorFunction?.(value); + return colors.defaultColorGeneratorFunction?.(value); } export function getDefaultColorPalette(count: number) { - if (defaultColorGeneratorFunction) { + if (colors.defaultColorGeneratorFunction) { return new Array(count) .fill(null) - .map((v, index) => defaultColorGeneratorFunction(index.toString())); + .map((v, index) => colors.defaultColorGeneratorFunction(index.toString())); } let r = brewer12; if (count <= 3) { diff --git a/src/core/prototypes/marks/nested_chart.ts b/src/core/prototypes/marks/nested_chart.ts index f353dcf40..fa20a4383 100644 --- a/src/core/prototypes/marks/nested_chart.ts +++ b/src/core/prototypes/marks/nested_chart.ts @@ -225,8 +225,8 @@ export class NestedChartElementClass extends EmphasizableMarkClass< name: "NestedData", tables: [ { - name: "MainTable", - displayName: "MainTable", + name: "main", + displayName: "Main", columns: table.columns.map((x) => { return { name: columnNameMap[x.name], @@ -436,7 +436,7 @@ export class NestedChartElementClass extends EmphasizableMarkClass< super.createDefault(...args) ); const myGlyphID = uniqueID(); - const tableName = "MainTable"; + const tableName = "main"; obj.properties.specification = { _id: uniqueID(), classID: "chart.rectangle", @@ -582,6 +582,8 @@ export class NestedChartElementClass extends EmphasizableMarkClass< } public getTemplateParameters(): TemplateParameters { + + //TODO get template parameters from nested chart return { inferences: [ {