From 81325ec64a24a98e3677b208a56dd048669fae72 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 23 Apr 2024 23:05:24 -0400 Subject: filter one histogram bar onto child dataviz doc at a time --- src/client/views/nodes/DataVizBox/components/Chart.scss | 3 +-- src/client/views/nodes/DataVizBox/components/Histogram.tsx | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index cf0007cfd..47cad9649 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -15,8 +15,7 @@ font-size: larger; display: flex; flex-direction: row; - margin-top: -20px; - margin-bottom: -20px; + margin-top: -35px; } .asHistogram-checkBox { align-items: left; diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 6672603f3..ff0262c15 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -164,6 +164,18 @@ export class Histogram extends ObservableReactComponent { sameAsCurrent = this._currSelected ? showSelected[xAxisTitle] == this._currSelected![xAxisTitle] && showSelected[yAxisTitle] == this._currSelected![yAxisTitle] : false; this._currSelected = sameAsCurrent ? undefined : showSelected; this.selectedData = sameAsCurrent ? undefined : d; + + // for filtering child dataviz docs + const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + this._tableDataIds.forEach(rowID => { + let match = true; + Object.keys(showSelected).map(key => { + if(key!='frequency' && this._props.records[rowID][key]!=showSelected[key]){ + match = false; + } + }) + if (match && !selectedRows?.includes(rowID)) selectedRows?.push(rowID); + }) } else this.hoverOverData = d; return true; } -- cgit v1.2.3-70-g09d2 From 7d9ced74c93c7282a2125dca0ed4b2bc70df4955 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 24 Apr 2024 00:10:58 -0400 Subject: filtering from histogram bars works from all histogram types --- src/client/views/nodes/DataVizBox/DataVizBox.scss | 1 + .../views/nodes/DataVizBox/components/Histogram.tsx | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss index a4f9dba73..9825d926f 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.scss +++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss @@ -30,6 +30,7 @@ } .liveSchema-checkBox { + margin-left: 10px; margin-bottom: -35px; } .filterData-checkBox { diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index ff0262c15..aef2d64f3 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -43,7 +43,7 @@ export class Histogram extends ObservableReactComponent { private numericalYData: boolean = false; // whether the y axis is controlled by provided data rather than frequency private maxBins = 15; // maximum number of bins that is readable on a normal sized doc @observable _currSelected: any | undefined = undefined; // Object of selected bar - private curBarSelected: any = undefined; // histogram bin of selected bar + private curBarSelected: any = undefined; // histogram bin of selected bar for when just one bar is selected private selectedData: any = undefined; // Selection of selected bar private hoverOverData: any = undefined; // Selection of bar being hovered over @@ -166,16 +166,17 @@ export class Histogram extends ObservableReactComponent { this.selectedData = sameAsCurrent ? undefined : d; // for filtering child dataviz docs - const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); - this._tableDataIds.forEach(rowID => { - let match = true; - Object.keys(showSelected).map(key => { - if(key!='frequency' && this._props.records[rowID][key]!=showSelected[key]){ - match = false; + if (this._props.layoutDoc.dataViz_filterSelection){ + console.log("d", d); + const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + this._tableDataIds.forEach(rowID => { + let match = false; + for (let i=0; i Date: Wed, 24 Apr 2024 02:10:05 -0400 Subject: select / filter with multiple histogram bars --- .../nodes/DataVizBox/components/Histogram.tsx | 51 ++++++++++++++++------ 1 file changed, 37 insertions(+), 14 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index aef2d64f3..14cfda559 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -44,7 +44,8 @@ export class Histogram extends ObservableReactComponent { private maxBins = 15; // maximum number of bins that is readable on a normal sized doc @observable _currSelected: any | undefined = undefined; // Object of selected bar private curBarSelected: any = undefined; // histogram bin of selected bar for when just one bar is selected - private selectedData: any = undefined; // Selection of selected bar + // private selectedData: any = undefined; // Selection of selected bar + private selectedData: any[] = []; // array of selected bars private hoverOverData: any = undefined; // Selection of bar being hovered over constructor(props: any) { @@ -162,19 +163,36 @@ export class Histogram extends ObservableReactComponent { if (changeSelectedVariables) { // for when a bar is selected - not just hovered over sameAsCurrent = this._currSelected ? showSelected[xAxisTitle] == this._currSelected![xAxisTitle] && showSelected[yAxisTitle] == this._currSelected![yAxisTitle] : false; - this._currSelected = sameAsCurrent ? undefined : showSelected; - this.selectedData = sameAsCurrent ? undefined : d; + let sameAsAny = false; + this.selectedData.map(eachData => { + if (!sameAsAny){ + let match = true; + Object.keys(d).map(key => { + if (d[key] != eachData[key]) match = false; + }) + if (match) { + sameAsAny = true; + let index = this.selectedData.indexOf(eachData) + this.selectedData.splice(index, 1); + this._currSelected = undefined; + } + } + }) + if(!sameAsAny) { + this.selectedData.push(d); + this._currSelected = this.selectedData.length>1? undefined : showSelected; + } // for filtering child dataviz docs if (this._props.layoutDoc.dataViz_filterSelection){ - console.log("d", d); const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); this._tableDataIds.forEach(rowID => { let match = false; for (let i=0; i { return false; }); if (changeSelectedVariables) { - if (sameAsCurrent!) this.curBarSelected = undefined; - else this.curBarSelected = selected; + if (this._currSelected) this.curBarSelected = selected; + else this.curBarSelected = undefined; } }; @@ -334,6 +352,11 @@ export class Histogram extends ObservableReactComponent { const hoverOverBar = this.hoverOverData; const selectedData = this.selectedData; svg.selectAll('rect').attr('class', function (d: any) { + let selected = false; + selectedData.map(eachSelectedData => { + if (d[0]==eachSelectedData[0]) selected = true; + }) + return (hoverOverBar && hoverOverBar[0] == d[0]) || selected ? 'histogram-bar hover' : 'histogram-bar'; return (hoverOverBar && hoverOverBar[0] == d[0]) || (selectedData && selectedData[0] == d[0]) ? 'histogram-bar hover' : 'histogram-bar'; }); }; @@ -389,13 +412,13 @@ export class Histogram extends ObservableReactComponent { .attr('width', eachRectWidth) .attr( 'class', - selected - ? function (d) { - return selected && selected[0] === d[0] ? 'histogram-bar hover' : 'histogram-bar'; - } - : function (d) { - return 'histogram-bar'; - } + function (d) { + let selectThisData = false; + selected.map(eachSelectedData => { + if (d[0]==eachSelectedData[0]) selectThisData = true; + }) + return selectThisData ? 'histogram-bar hover' : 'histogram-bar'; + } ) .attr('fill', d => { var barColor; -- cgit v1.2.3-70-g09d2 From 04589cb1f5f957d1d95f8f7f29e2f9599059fa92 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 24 Apr 2024 23:47:01 -0400 Subject: bars stay selected on refresh / componentdidmount --- .../nodes/DataVizBox/components/Histogram.tsx | 48 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 14cfda559..12e2be341 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -105,11 +105,29 @@ export class Histogram extends ObservableReactComponent { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } componentDidMount() { + // draw histogram this._disposers.chartData = reaction( () => ({ dataSet: this._histogramData, w: this.width, h: this.height }), ({ dataSet, w, h }) => dataSet!.length > 0 && this.drawChart(dataSet, w, h), { fireImmediately: true } ); + + // restore selected bars + var svg = this._histogramSvg; + if (svg) { + const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_histogram_selectedData) + svg.selectAll('rect').attr('class', (d: any) => { + let selected = false; + selectedDataBars.map(eachSelectedData => { + if (d[0]==eachSelectedData) selected = true; + }) + if (selected){ + this.selectedData.push(d); + return 'histogram-bar hover' + } + else return 'histogram-bar'; + }); + } } @action @@ -164,6 +182,7 @@ export class Histogram extends ObservableReactComponent { // for when a bar is selected - not just hovered over sameAsCurrent = this._currSelected ? showSelected[xAxisTitle] == this._currSelected![xAxisTitle] && showSelected[yAxisTitle] == this._currSelected![yAxisTitle] : false; let sameAsAny = false; + const selectedDataBars = Cast(this._props.layoutDoc.dataViz_histogram_selectedData, listSpec('number'), null); this.selectedData.map(eachData => { if (!sameAsAny){ let match = true; @@ -174,14 +193,17 @@ export class Histogram extends ObservableReactComponent { sameAsAny = true; let index = this.selectedData.indexOf(eachData) this.selectedData.splice(index, 1); + selectedDataBars.splice(index, 1); this._currSelected = undefined; } } }) if(!sameAsAny) { this.selectedData.push(d); + selectedDataBars.push(d[0]); this._currSelected = this.selectedData.length>1? undefined : showSelected; } + console.log(selectedDataBars.length) // for filtering child dataviz docs if (this._props.layoutDoc.dataViz_filterSelection){ @@ -357,7 +379,6 @@ export class Histogram extends ObservableReactComponent { if (d[0]==eachSelectedData[0]) selected = true; }) return (hoverOverBar && hoverOverBar[0] == d[0]) || selected ? 'histogram-bar hover' : 'histogram-bar'; - return (hoverOverBar && hoverOverBar[0] == d[0]) || (selectedData && selectedData[0] == d[0]) ? 'histogram-bar hover' : 'histogram-bar'; }); }; svg.on('click', onPointClick).on('mouseover', onHover).on('mouseout', mouseOut); @@ -451,9 +472,11 @@ export class Histogram extends ObservableReactComponent { barColors.forEach(each => each.split('::')[0] === barName && barColors.splice(barColors.indexOf(each), 1)); }; - updateBarColors = () => { + // reloads the bar colors and selected bars + updateSavedUI = () => { var svg = this._histogramSvg; - if (svg) + if (svg) { + // bar color svg.selectAll('rect').attr('fill', (d: any) => { var barColor; const barColors = StrListCast(this._props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::')); @@ -466,10 +489,26 @@ export class Histogram extends ObservableReactComponent { }); return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor); }); + // selected bars + // const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_histogram_selectedData) + // let filledSelectedData = this.selectedData.length>0; + // console.log(selectedDataBars.length) + // svg.selectAll('rect').attr('class', (d: any) => { + // let selected = false; + // selectedDataBars.map(eachSelectedData => { + // if (d[0]==eachSelectedData) selected = true; + // }) + // if (selected){ + // if (!filledSelectedData) this.selectedData.push(d); + // return 'histogram-bar hover' + // } + // else return 'histogram-bar'; + // }); + } }; render() { - this.updateBarColors(); + this.updateSavedUI(); this._histogramData; var curSelectedBarName = ''; var titleAccessor: any = 'dataViz_histogram_title'; @@ -478,6 +517,7 @@ export class Histogram extends ObservableReactComponent { if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this._props.layoutDoc.dataViz_histogram_defaultColor) this._props.layoutDoc.dataViz_histogram_defaultColor = '#69b3a2'; if (!this._props.layoutDoc.dataViz_histogram_barColors) this._props.layoutDoc.dataViz_histogram_barColors = new List(); + if (!this._props.layoutDoc.dataViz_histogram_selectedData) this._props.layoutDoc.dataViz_histogram_selectedData = new List(); var selected = 'none'; if (this._currSelected) { curSelectedBarName = StrCast(this._currSelected![this._props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ Date: Wed, 24 Apr 2024 23:47:24 -0400 Subject: cleaned --- .../views/nodes/DataVizBox/components/Histogram.tsx | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 12e2be341..d9f355f67 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -203,7 +203,6 @@ export class Histogram extends ObservableReactComponent { selectedDataBars.push(d[0]); this._currSelected = this.selectedData.length>1? undefined : showSelected; } - console.log(selectedDataBars.length) // for filtering child dataviz docs if (this._props.layoutDoc.dataViz_filterSelection){ @@ -489,21 +488,6 @@ export class Histogram extends ObservableReactComponent { }); return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor); }); - // selected bars - // const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_histogram_selectedData) - // let filledSelectedData = this.selectedData.length>0; - // console.log(selectedDataBars.length) - // svg.selectAll('rect').attr('class', (d: any) => { - // let selected = false; - // selectedDataBars.map(eachSelectedData => { - // if (d[0]==eachSelectedData) selected = true; - // }) - // if (selected){ - // if (!filledSelectedData) this.selectedData.push(d); - // return 'histogram-bar hover' - // } - // else return 'histogram-bar'; - // }); } }; -- cgit v1.2.3-70-g09d2 From 8de07e0c17c2914bb6aff54f86e198eef5d2ac06 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Thu, 25 Apr 2024 02:40:33 -0400 Subject: fixed filteres axes, console errors --- src/client/views/nodes/DataVizBox/components/Histogram.tsx | 8 ++++---- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index d9f355f67..74711bd58 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -408,8 +408,8 @@ export class Histogram extends ObservableReactComponent { const eachData = histDataSet.filter((data: { [x: string]: number }) => { return data[xAxisTitle] == d[0]; }); - const length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { const eachData = histDataSet.filter((data: { [x: string]: number }) => { return data[xAxisTitle] == d[0]; }); - const length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { makeObservable(this); } + @action componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), // then we need to remove any selected rows that are no longer part of the visualized dataset. @@ -137,7 +138,7 @@ export class TableBox extends ObservableReactComponent { const targetCreator = (annotationOn: Doc | undefined) => { const embedding = Doc.MakeEmbedding(this._props.docView?.()!.Document!); embedding._dataViz = DataVizView.TABLE; - embedding._dataViz_axes = new List([col, col]); + embedding._dataViz_axes = new List([col]); embedding._dataViz_parentViz = this._props.Document; embedding.annotationOn = annotationOn; embedding.histogramBarColors = Field.Copy(this._props.layoutDoc.histogramBarColors); -- cgit v1.2.3-70-g09d2 From bf89ce9ec19c22dec4ad302a755e354e34182f66 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Sun, 28 Apr 2024 18:35:44 -0400 Subject: pie chart filtering, mult-selection, selection on refresh updates --- .../views/nodes/DataVizBox/components/Chart.scss | 11 +-- .../nodes/DataVizBox/components/Histogram.tsx | 10 +-- .../views/nodes/DataVizBox/components/PieChart.tsx | 98 +++++++++++++++++----- 3 files changed, 86 insertions(+), 33 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss index 47cad9649..0eb27b65b 100644 --- a/src/client/views/nodes/DataVizBox/components/Chart.scss +++ b/src/client/views/nodes/DataVizBox/components/Chart.scss @@ -18,14 +18,9 @@ margin-top: -35px; } .asHistogram-checkBox { - align-items: left; - align-self: left; - align-content: left; - justify-content: flex-end; - float: left; - left: 0; - position: relative; - margin-bottom: -35px; + margin-left: 10px; + margin-bottom: -10px; + margin-top: -20px; } .selected-data { align-items: center; diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 74711bd58..1fc33396a 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -118,7 +118,7 @@ export class Histogram extends ObservableReactComponent { const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_histogram_selectedData) svg.selectAll('rect').attr('class', (d: any) => { let selected = false; - selectedDataBars.map(eachSelectedData => { + selectedDataBars.forEach(eachSelectedData => { if (d[0]==eachSelectedData) selected = true; }) if (selected){ @@ -183,10 +183,10 @@ export class Histogram extends ObservableReactComponent { sameAsCurrent = this._currSelected ? showSelected[xAxisTitle] == this._currSelected![xAxisTitle] && showSelected[yAxisTitle] == this._currSelected![yAxisTitle] : false; let sameAsAny = false; const selectedDataBars = Cast(this._props.layoutDoc.dataViz_histogram_selectedData, listSpec('number'), null); - this.selectedData.map(eachData => { + this.selectedData.forEach(eachData => { if (!sameAsAny){ let match = true; - Object.keys(d).map(key => { + Object.keys(d).forEach(key => { if (d[key] != eachData[key]) match = false; }) if (match) { @@ -374,7 +374,7 @@ export class Histogram extends ObservableReactComponent { const selectedData = this.selectedData; svg.selectAll('rect').attr('class', function (d: any) { let selected = false; - selectedData.map(eachSelectedData => { + selectedData.forEach(eachSelectedData => { if (d[0]==eachSelectedData[0]) selected = true; }) return (hoverOverBar && hoverOverBar[0] == d[0]) || selected ? 'histogram-bar hover' : 'histogram-bar'; @@ -434,7 +434,7 @@ export class Histogram extends ObservableReactComponent { 'class', function (d) { let selectThisData = false; - selected.map(eachSelectedData => { + selected.forEach(eachSelectedData => { if (d[0]==eachSelectedData[0]) selectThisData = true; }) return selectThisData ? 'histogram-bar hover' : 'histogram-bar'; diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index fc23f47de..364a5c2ff 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -38,8 +38,8 @@ export class PieChart extends ObservableReactComponent { private _disposers: { [key: string]: IReactionDisposer } = {}; private _piechartRef: React.RefObject = React.createRef(); private _piechartSvg: d3.Selection | undefined; - private curSliceSelected: any = undefined; // d3 data of selected slice - private selectedData: any = undefined; // Selection of selected slice + private curSliceSelected: any = undefined; // d3 data of selected slice for when just one slice is selected + private selectedData: any[] = []; // array of selected slices private hoverOverData: any = undefined; // Selection of slice being hovered over @observable _currSelected: any | undefined = undefined; // Object of selected slice @@ -84,20 +84,35 @@ export class PieChart extends ObservableReactComponent { @computed get parentViz() { return DocCast(this._props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links - // .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link - // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } componentWillUnmount() { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } componentDidMount() { + // draw chart this._disposers.chartData = reaction( () => ({ dataSet: this._pieChartData, w: this.width, h: this.height }), ({ dataSet, w, h }) => dataSet!.length > 0 && this.drawChart(dataSet, w, h), { fireImmediately: true } ); + // restore selected slices + let key = Object.keys(this._pieChartData[0])[0] + var svg = this._piechartSvg; + if (svg) { + const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_pie_selectedData) + svg.selectAll('path').attr('class', (d: any) => { + let selected = false; + selectedDataBars.map(eachSelectedData => { + if (d[key]==eachSelectedData) selected = true; + }) + if (selected){ + this.selectedData.push(d); + return 'slice hover' + } + else return 'slice'; + }); + } } @action @@ -163,21 +178,54 @@ export class PieChart extends ObservableReactComponent { if (lineCrossCount % 2 != 0) { // inside the slice of it crosses an odd number of edges var showSelected = this.byCategory ? pieDataSet[index] : this._pieChartData[index]; + let key = 'data' // key that represents slice + if (Object.keys(showSelected)[0]=='frequency') key = Object.keys(showSelected)[1] if (changeSelectedVariables) { // for when a bar is selected - not just hovered over sameAsCurrent = this._currSelected ? showSelected[Object.keys(showSelected)[0]] == this._currSelected![Object.keys(showSelected)[0]] && showSelected[Object.keys(showSelected)[1]] == this._currSelected![Object.keys(showSelected)[1]] : this._currSelected === showSelected; - this._currSelected = sameAsCurrent ? undefined : showSelected; - this.selectedData = sameAsCurrent ? undefined : d; + let sameAsAny = false; + const selectedDataSlices = Cast(this._props.layoutDoc.dataViz_pie_selectedData, listSpec('number'), null); + this.selectedData.forEach(eachData => { + if (!sameAsAny){ + let match = true; + Object.keys(d).forEach(key => { + if (d[key] != eachData[key]) match = false; + }) + if (match) { + sameAsAny = true; + let index = this.selectedData.indexOf(eachData) + this.selectedData.splice(index, 1); + selectedDataSlices.splice(index, 1); + this._currSelected = undefined; + } + } + }) + if(!sameAsAny) { + this.selectedData.push(d); + selectedDataSlices.push(d[key]); + this._currSelected = this.selectedData.length>1? undefined : showSelected; + } + + // for filtering child dataviz docs + if (this._props.layoutDoc.dataViz_filterSelection){ + const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + this._tableDataIds.forEach(rowID => { + let match = false; + if (this._props.records[rowID][key] == d[key]) match = true; + if (match && !selectedRows?.includes(rowID)) selectedRows?.push(rowID); // adding to filtered rows + else if (match && sameAsAny) selectedRows.splice(selectedRows.indexOf(rowID), 1); // removing from filtered rows + }) + } } else this.hoverOverData = d; return true; } return false; }); if (changeSelectedVariables) { - if (sameAsCurrent!) this.curSliceSelected = undefined; - else this.curSliceSelected = selected; + if (this._currSelected) this.curSliceSelected = selected; + else this.curSliceSelected = undefined; } }; @@ -237,9 +285,11 @@ export class PieChart extends ObservableReactComponent { const hoverOverSlice = this.hoverOverData; const selectedData = this.selectedData; svg.selectAll('path').attr('class', function (d: any) { - return (selectedData && d.startAngle == selectedData.startAngle && d.endAngle == selectedData.endAngle) || (hoverOverSlice && d.startAngle == hoverOverSlice.startAngle && d.endAngle == hoverOverSlice.endAngle) - ? 'slice hover' - : 'slice'; + let selected = false; + selectedData.forEach((eachSelectedData: any) => { + if (d.startAngle==eachSelectedData.startAngle) selected = true; + }) + return selected || (hoverOverSlice && d.startAngle == hoverOverSlice.startAngle && d.endAngle == hoverOverSlice.endAngle) ? 'slice hover' : 'slice'; }); }; @@ -257,8 +307,14 @@ export class PieChart extends ObservableReactComponent { possibleDataPointVals.push(dataPointVal); }); const sliceColors = StrListCast(this._props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::')); + + // to make sure all important slice information is on 'd' object + let addKey: any = false; + if (Object.keys(pieDataSet[0])[0]=='frequency'){ + addKey = Object.keys(pieDataSet[0])[1] + } arcs.append('path') - .attr('fill', (d, i) => { + .attr('fill', (d: any, i) => { var dataPoint; const possibleDataPoints = possibleDataPointVals.filter((pval: any) => pval[percentField] === Number(d.data)); if (possibleDataPoints.length == 1) dataPoint = possibleDataPoints[0]; @@ -268,6 +324,7 @@ export class PieChart extends ObservableReactComponent { } var sliceColor; if (dataPoint) { + if (addKey) d[addKey] = dataPoint[addKey] // adding all slice information to d const sliceTitle = dataPoint[this._props.axes[0]]; const accessByName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\ each[0] == accessByName && (sliceColor = each[1])); @@ -276,13 +333,13 @@ export class PieChart extends ObservableReactComponent { }) .attr( 'class', - selected - ? function (d) { - return selected && d.startAngle == selected.startAngle && d.endAngle == selected.endAngle ? 'slice hover' : 'slice'; - } - : function (d) { - return 'slice'; - } + function (d: any) { + let selectThisData = false; + selected.forEach((eachSelectedData: any) => { + if (d.startAngle==eachSelectedData.startAngle) selectThisData = true; + }) + return selectThisData ? 'slice hover' : 'slice'; + } ) // @ts-ignore .attr('d', arc) @@ -337,6 +394,7 @@ export class PieChart extends ObservableReactComponent { else if (this._props.axes.length > 0) titleAccessor = titleAccessor + this._props.axes[0]; if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this._props.layoutDoc.dataViz_pie_sliceColors) this._props.layoutDoc.dataViz_pie_sliceColors = new List(); + if (!this._props.layoutDoc.dataViz_pie_selectedData) this._props.layoutDoc.dataViz_pie_selectedData = new List(); var selected: string; var curSelectedSliceName = ''; if (this._currSelected) { -- cgit v1.2.3-70-g09d2 From 4b4b7d2b4e905b3c64b0d0b42dd3ed329bad857e Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 1 May 2024 01:52:59 -0400 Subject: last for LineCharts --- .../nodes/DataVizBox/components/Histogram.tsx | 1 - .../nodes/DataVizBox/components/LineChart.tsx | 124 +++++++++++---------- .../views/nodes/DataVizBox/components/PieChart.tsx | 2 +- 3 files changed, 67 insertions(+), 60 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 1fc33396a..2152df8a1 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -44,7 +44,6 @@ export class Histogram extends ObservableReactComponent { private maxBins = 15; // maximum number of bins that is readable on a normal sized doc @observable _currSelected: any | undefined = undefined; // Object of selected bar private curBarSelected: any = undefined; // histogram bin of selected bar for when just one bar is selected - // private selectedData: any = undefined; // Selection of selected bar private selectedData: any[] = []; // array of selected bars private hoverOverData: any = undefined; // Selection of bar being hovered over diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index e093ec648..11d117b29 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -48,6 +48,8 @@ export class LineChart extends ObservableReactComponent { private _lineChartRef: React.RefObject = React.createRef(); private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: any | undefined = undefined; + private selectedData: any[] = []; // array of selected data points + // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates constructor(props: any) { super(props); @@ -71,11 +73,6 @@ export class LineChart extends ObservableReactComponent { } @computed get parentViz() { return DocCast(this._props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links - // .filter(link => { - // return link.link_anchor_1 == this._props.Document.dataViz_parentViz; - // }) // get links where this chart doc is the target of the link - // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get incomingHighlited() { // return selected x and y axes @@ -91,6 +88,7 @@ export class LineChart extends ObservableReactComponent { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } componentDidMount() { + // draw chart this._disposers.chartData = reaction( () => ({ dataSet: this._lineChartData, w: this.width, h: this.height }), ({ dataSet, w, h }) => { @@ -100,31 +98,23 @@ export class LineChart extends ObservableReactComponent { }, { fireImmediately: true } ); - this._disposers.annos = reaction( - () => DocListCast(this._props.dataDoc[this._props.fieldKey + '_annotations']), - annotations => { - // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way - // could be blue colored to make it look like anchor - // this.drawAnnotations() - // loop through annotations and draw them - // annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y))); - // this.drawAnnotations(annotations.x, annotations.y); - }, - { fireImmediately: true } - ); - this._disposers.highlights = reaction( - () => ({ - selected: this._currSelected, - incomingHighlited: this.incomingHighlited, - }), - ({ selected, incomingHighlited }) => { - // redraw annotations when the chart data has changed, or the local or inherited selection has changed - this.clearAnnotations(); - selected && this.drawAnnotations(Number(selected.x), Number(selected.y), true); - incomingHighlited?.forEach((record: any) => this.drawAnnotations(Number(record[this._props.axes[0]]), Number(record[this._props.axes[1]]))); - }, - { fireImmediately: true } - ); + + // coloring the selected point + const elements = document.querySelectorAll('.datapoint'); + for (let i = 0; i < elements.length; i++) { + const x = Number(elements[i].getAttribute('data-x')); + const y = Number(elements[i].getAttribute('data-y')); + const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_lineChart_selectedData) + let selected = false; + selectedDataBars.forEach(eachSelectedData => { + // parse each selected point into x,y + let xy = eachSelectedData.split(','); + if (Number(xy[0])===x && Number(xy[1])===y) selected = true; + }) + if (selected) { + this.drawAnnotations(x, y, false); + } + } } // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that @@ -137,12 +127,9 @@ export class LineChart extends ObservableReactComponent { element.classList.remove('selected'); } }; - // gets called whenever the "data_annotations" fields gets updated + + // draws red annotation on data points when selected drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => { - // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements - // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY - // if it exists, then highlight it - // if it doesn't exist, then remove the highlight const elements = document.querySelectorAll('.datapoint'); for (let i = 0; i < elements.length; i++) { const element = elements[i]; @@ -151,25 +138,11 @@ export class LineChart extends ObservableReactComponent { if (x === dataX.toString() && y === dataY.toString()) { element.classList.add(selected ? 'selected' : 'brushed'); } - // TODO: nda - this remove highlight code should go where we remove the links - // } else { - // } } }; @action - restoreView = (data: Doc) => { - const coords = Cast(data.config_dataVizSelection, listSpec('number'), null); - if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) { - this.setCurrSelected(coords[0], coords[1]); - return true; - } - if (this._currSelected) { - this.setCurrSelected(); - return true; - } - return false; - }; + restoreView = (data: Doc) => {}; // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { @@ -211,13 +184,48 @@ export class LineChart extends ObservableReactComponent { .style('font-size', '12px'); } - // TODO: nda - use this everyewhere we update currSelected? @action - setCurrSelected(x?: number, y?: number) { - // TODO: nda - get rid of svg element in the list? - if (this._currSelected && this._currSelected.x == x && this._currSelected.y == y) this._currSelected = undefined; - else this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; - this._props.records.forEach(record => record[this._props.axes[0]] === x && record[this._props.axes[1]] === y && (record.selected = true)); + setCurrSelected(d: DataPoint) { + let sameAsAny = false; + const selectedDatapoints = Cast(this._props.layoutDoc.dataViz_lineChart_selectedData, listSpec('string'), null); + this.selectedData.forEach(eachData => { + if (!sameAsAny){ + if (eachData.x==d.x && eachData.y==d.y) { + sameAsAny = true; + let index = this.selectedData.indexOf(eachData) + this.selectedData.splice(index, 1); + selectedDatapoints.splice(index, 1); + this._currSelected = undefined; + } + } + }) + if(!sameAsAny) { + this.selectedData.push(d); + selectedDatapoints.push(d.x + "," + d.y); + this._currSelected = this.selectedData.length>1? undefined : d; + } + + // for filtering child dataviz docs + if (this._props.layoutDoc.dataViz_filterSelection){ + const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + this._tableDataIds.forEach(rowID => { + if (this._props.records[rowID][this._props.axes[0]]==d.x && this._props.records[rowID][this._props.axes[1]]==d.y) { + if (!selectedRows?.includes(rowID)) selectedRows?.push(rowID); // adding to filtered rows + else if (sameAsAny) selectedRows.splice(selectedRows.indexOf(rowID), 1); // removing from filtered rows + } + }) + } + + // coloring the selected point + const elements = document.querySelectorAll('.datapoint'); + for (let i = 0; i < elements.length; i++) { + const x = Number(elements[i].getAttribute('data-x')); + const y = Number(elements[i].getAttribute('data-y')); + if (x===d.x && y===d.y) { + if (sameAsAny) elements[i].classList.remove('brushed'); + else elements[i].classList.add('brushed'); + } + } } drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear, yScale: d3.ScaleLinear) { @@ -345,8 +353,7 @@ export class LineChart extends ObservableReactComponent { const x0 = bisect(data, xScale.invert(xPos - 5)); // shift x by -5 so that you can reach points on the left-side axis const d0 = data[x0]; // find .circle-d1 with data-x = d0.x and data-y = d0.y - const selected = svg.selectAll('.datapoint').filter((d: any) => d['data-x'] === d0.x && d['data-y'] === d0.y); - this.setCurrSelected(d0.x, d0.y); + this.setCurrSelected(d0); this.updateTooltip(higlightFocusPt, xScale, d0, yScale, tooltip); }); @@ -398,6 +405,7 @@ export class LineChart extends ObservableReactComponent { if (this._props.axes.length == 2) titleAccessor = titleAccessor + this._props.axes[0] + '-' + this._props.axes[1]; else if (this._props.axes.length > 0) titleAccessor = titleAccessor + this._props.axes[0]; if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; + if (!this._props.layoutDoc.dataViz_lineChart_selectedData) this._props.layoutDoc.dataViz_lineChart_selectedData = new List(); const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; var selectedTitle = ""; if (this._currSelected && this._props.titleCol){ diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 364a5c2ff..3819c2f82 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -103,7 +103,7 @@ export class PieChart extends ObservableReactComponent { const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_pie_selectedData) svg.selectAll('path').attr('class', (d: any) => { let selected = false; - selectedDataBars.map(eachSelectedData => { + selectedDataBars.forEach(eachSelectedData => { if (d[key]==eachSelectedData) selected = true; }) if (selected){ -- cgit v1.2.3-70-g09d2 From 0d38f3e9bc4306c9e38decef5497c88c67376a83 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Sun, 5 May 2024 13:50:22 -0400 Subject: $, %, etc... can be selected for histograms and linecharts --- src/client/views/nodes/DataVizBox/components/Histogram.tsx | 2 +- src/client/views/nodes/DataVizBox/components/LineChart.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 2152df8a1..110626923 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -209,7 +209,7 @@ export class Histogram extends ObservableReactComponent { this._tableDataIds.forEach(rowID => { let match = false; for (let i=0; i { if (this._props.layoutDoc.dataViz_filterSelection){ const selectedRows = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); this._tableDataIds.forEach(rowID => { - if (this._props.records[rowID][this._props.axes[0]]==d.x && this._props.records[rowID][this._props.axes[1]]==d.y) { + if (this._props.records[rowID][this._props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ Date: Sun, 5 May 2024 13:59:55 -0400 Subject: bug fixed - when piechart has no data --- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 3819c2f82..5c341e0b4 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -97,9 +97,9 @@ export class PieChart extends ObservableReactComponent { { fireImmediately: true } ); // restore selected slices - let key = Object.keys(this._pieChartData[0])[0] var svg = this._piechartSvg; - if (svg) { + if (svg && this._pieChartData[0]) { + let key = Object.keys(this._pieChartData[0])[0] const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_pie_selectedData) svg.selectAll('path').attr('class', (d: any) => { let selected = false; -- cgit v1.2.3-70-g09d2 From 9589dd92470e59ef041770af5ffc287a74c2752c Mon Sep 17 00:00:00 2001 From: srichman333 Date: Tue, 7 May 2024 12:08:29 -0400 Subject: filtering for a range of strings --- src/client/views/nodes/DataVizBox/components/TableBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 553fb2f65..5578b10cb 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -188,8 +188,8 @@ export class TableBox extends ObservableReactComponent { var start: any; var end: any; if (this.filteringType=="Range"){ - start = (this.filteringVal[0] as Number)? Number(this.filteringVal[0]): this.filteringVal[0] - end = (this.filteringVal[1] as Number)? Number(this.filteringVal[1]): this.filteringVal[0] + start = Number.isNaN(Number(this.filteringVal[0]))? this.filteringVal[0]: Number(this.filteringVal[0]); + end = Number.isNaN(Number(this.filteringVal[1]))? this.filteringVal[1]: Number(this.filteringVal[1]); } this._tableDataIds.forEach(rowID => { @@ -202,7 +202,7 @@ export class TableBox extends ObservableReactComponent { } else { let compare = this._props.records[rowID][this.filteringColumn] - if (compare as Number) compare = Number(compare) + if (!Number.isNaN(Number(compare))) compare = Number(compare) if (start<=compare && compare<=end){ if (!NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowID)) { this.tableRowClick(e, rowID); -- cgit v1.2.3-70-g09d2 From 87bca251d87b5a95da06b2212400ce9427152193 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 May 2024 13:46:44 -0400 Subject: cleaning up dataviz code --- src/client/apis/gpt/GPT.ts | 9 ++-- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 49 ++++++++++------------ .../views/nodes/DataVizBox/components/TableBox.tsx | 5 +-- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 5 +-- 4 files changed, 33 insertions(+), 35 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 8747a00a6..9deae7cff 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -24,9 +24,12 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { summary: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: 'Summarize the text given in simpler terms.' }, edit: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: 'Reword the text.' }, completion: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful assistant. Answer the user's prompt." }, - // data: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful resarch assistant. Analyze the user's data to find meaningful patterns and/or correlation. Please keep your response short and to the point." }, - data: { model: 'gpt-3.5-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful resarch assistant. Analyze the user's data to find meaningful patterns and/or correlation. Please only return a JSON with a correlation column 1 propert, a correlation column 2 property, and an analysis property. " }, - + data: { + model: 'gpt-3.5-turbo', + maxTokens: 256, + temp: 0.5, + prompt: "You are a helpful resarch assistant. Analyze the user's data to find meaningful patterns and/or correlation. Please only return a JSON with a correlation column 1 propert, a correlation column 2 property, and an analysis property. ", + }, }; /** diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 01258a996..3f16220a5 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -1,4 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Checkbox } from '@mui/material'; import { Colors, Toggle, ToggleType, Type } from 'browndash-components'; import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -14,22 +15,20 @@ import { TraceMobx } from '../../../../fields/util'; import { DocUtils, Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; +import { ContextMenu } from '../../ContextMenu'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; import { MarqueeAnnotator } from '../../MarqueeAnnotator'; import { SidebarAnnos } from '../../SidebarAnnos'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup'; import { DocumentView } from '../DocumentView'; -import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; +import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView'; import { PinProps } from '../trails'; import './DataVizBox.scss'; import { Histogram } from './components/Histogram'; import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; -import { Checkbox } from '@mui/material'; -import { ContextMenu } from '../../ContextMenu'; -import { DragManager } from '../../../util/DragManager'; export enum DataVizView { TABLE = 'table', @@ -404,16 +403,16 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im // represents whether or not a data viz box created from a schema table displays live updates to the canvas @action changeLiveSchemaCheckbox = () => { - this.layoutDoc.dataViz_schemaLive = !this.layoutDoc.dataViz_schemaLive - } + this.layoutDoc.dataViz_schemaLive = !this.layoutDoc.dataViz_schemaLive; + }; - // represents whether or not clicking on a peice of data in the visualization + // represents whether or not clicking on a peice of data in the visualization // (i.e. a data point in a linechart, a bar on a histogram, or a slice of a pie chart) // filters the data onto a new data viz doc created off of this one @action changeFilteringCheckbox = () => { - this.layoutDoc.dataViz_filterSelection = !this.layoutDoc.dataViz_filterSelection - } + this.layoutDoc.dataViz_filterSelection = !this.layoutDoc.dataViz_filterSelection; + }; specificContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; @@ -421,41 +420,39 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im const optionItems = options && 'subitems' in options ? options.subitems : []; optionItems.push({ description: `Analyze with AI`, event: () => this.askGPT(), icon: 'lightbulb' }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); - } - + }; askGPT = action(async () => { GPTPopup.Instance.setSidebarId('data_sidebar'); GPTPopup.Instance.addDoc = this.sidebarAddDocument; GPTPopup.Instance.createFilteredDoc = this.createFilteredDoc; - GPTPopup.Instance.setDataJson(""); + GPTPopup.Instance.setDataJson(''); GPTPopup.Instance.setMode(GPTPopupMode.DATA); - let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); - let input = JSON.stringify(data); - GPTPopup.Instance.setDataJson(input); + const data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); + GPTPopup.Instance.setDataJson(JSON.stringify(data)); GPTPopup.Instance.generateDataAnalysis(); }); /** * creates a new dataviz document filter from this one - * it appears to the right of this document, with the + * it appears to the right of this document, with the * parameters passed in being used to create an initial display */ - createFilteredDoc = (axes?: any, type?: DataVizView) => { + createFilteredDoc = (axes?: any) => { const embedding = Doc.MakeEmbedding(this.Document!); embedding._layout_showSidebar = false; - embedding._dataViz = type? type : DataVizView.LINECHART; + embedding._dataViz = DataVizView.LINECHART; embedding._dataViz_axes = new List(axes); embedding._dataViz_parentViz = this.Document; embedding.histogramBarColors = Field.Copy(this.layoutDoc.histogramBarColors); embedding.defaultHistogramColor = this.layoutDoc.defaultHistogramColor; embedding.pieSliceColors = Field.Copy(this.layoutDoc.pieSliceColors); embedding._layout_showSidebar = false; - embedding.width = NumCast(this.layoutDoc._width)- this.sidebarWidth(); - embedding._layout_sidebarWidthPercent = "0%"; + embedding.width = NumCast(this.layoutDoc._width) - this.sidebarWidth(); + embedding._layout_sidebarWidthPercent = '0%'; this._props.addDocument?.(embedding); - embedding._dataViz_axes = new List(axes) - this.layoutDoc.dataViz_selectedRows = new List(this.records.map((rec, i) => i)) + embedding._dataViz_axes = new List(axes); + this.layoutDoc.dataViz_selectedRows = new List(this.records.map((rec, i) => i)); embedding.x = Number(embedding.x) + Number(this.Document.width); return true; @@ -487,7 +484,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == -DataVizView.PIECHART} /> - {(this.layoutDoc && this.layoutDoc.dataViz_asSchema)?( + {this.layoutDoc && this.layoutDoc.dataViz_asSchema ? (
@@ -495,12 +492,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() im
) : null} - {this.layoutDoc._dataViz != DataVizView.TABLE?( + {this.layoutDoc._dataViz != DataVizView.TABLE ? (
Select data to filter -
) - : null } + + ) : null} {this.renderVizView} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 7ad5a0e6b..fa48d66d8 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,5 +1,5 @@ import { Button, Type } from 'browndash-components'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../../Utils'; @@ -53,13 +53,12 @@ export class TableBox extends ObservableReactComponent { makeObservable(this); } - @action componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), // then we need to remove any selected rows that are no longer part of the visualized dataset. this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true }); const selected = NumListCast(this._props.layoutDoc.dataViz_selectedRows); - if (selected.length > 0) this.hasRowsToFilter = true; + if (selected.length > 0) runInAction(() => (this.hasRowsToFilter = true)); this.handleScroll(); } componentWillUnmount() { diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 40946cd36..e90504aa5 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, EditableText, IconButton, Size, Type } from 'browndash-components'; +import { Button, IconButton, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -15,7 +15,6 @@ import { DocUtils, Docs } from '../../../documents/Documents'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { AnchorMenu } from '../AnchorMenu'; import './GPTPopup.scss'; -import { DataVizView } from '../../nodes/DataVizBox/DataVizBox'; export enum GPTPopupMode { SUMMARY, @@ -123,7 +122,7 @@ export class GPTPopup extends ObservableReactComponent { }; public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; - public createFilteredDoc: (axes?: any, type?: DataVizView) => boolean = () => false; + public createFilteredDoc: (axes?: any) => boolean = () => false; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; /** -- cgit v1.2.3-70-g09d2 From 29b70db45b0d5da8cb163ccb062afe4579556fde Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 May 2024 23:50:41 -0400 Subject: fixed line chart rendering to update --- .../nodes/DataVizBox/components/LineChart.tsx | 37 +++++++--------------- 1 file changed, 11 insertions(+), 26 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 80edf2c36..ffced14f8 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -42,7 +42,7 @@ export interface LineChartProps { @observer export class LineChart extends ObservableReactComponent { private _disposers: { [key: string]: IReactionDisposer } = {}; - private _lineChartRef: React.RefObject = React.createRef(); + private _lineChartRef: HTMLDivElement | null = null; private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: DataPoint | undefined = undefined; @@ -83,17 +83,6 @@ export class LineChart extends ObservableReactComponent { Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]()); } componentDidMount() { - // draw chart - this._disposers.chartData = reaction( - () => ({ dataSet: this._lineChartData, w: this.width, h: this.height }), - ({ dataSet, w, h }) => { - if (dataSet) { - this.drawChart([dataSet], this.rangeVals, w, h); - } - }, - { fireImmediately: true } - ); - // coloring the selected point this.colorSelectedPt(); } @@ -169,16 +158,7 @@ export class LineChart extends ObservableReactComponent { } setupTooltip() { - return d3 - .select(this._lineChartRef.current) - .append('div') - .attr('class', 'tooltip') - .style('opacity', 0) - .style('background', '#fff') - .style('border', '1px solid #ccc') - .style('padding', '5px') - .style('position', 'absolute') - .style('font-size', '12px'); + return d3.select(this._lineChartRef).append('div').attr('class', 'tooltip').style('opacity', 0).style('background', '#fff').style('border', '1px solid #ccc').style('padding', '5px').style('position', 'absolute').style('font-size', '12px'); } @action @@ -261,8 +241,8 @@ export class LineChart extends ObservableReactComponent { drawChart = (dataSet: any[][], rangeVals: { xMin?: number; xMax?: number; yMin?: number; yMax?: number }, width: number, height: number) => { // clearing tooltip and the current chart - d3.select(this._lineChartRef.current).select('svg').remove(); - d3.select(this._lineChartRef.current).select('.tooltip').remove(); + d3.select(this._lineChartRef).select('svg').remove(); + d3.select(this._lineChartRef).select('.tooltip').remove(); let { xMin, xMax, yMin, yMax } = rangeVals; if (xMin === undefined || xMax === undefined || yMin === undefined || yMax === undefined) { @@ -272,7 +252,7 @@ export class LineChart extends ObservableReactComponent { // adding svg const { margin } = this._props; const svg = (this._lineChartSvg = d3 - .select(this._lineChartRef.current) + .select(this._lineChartRef) .append('svg') .attr('class', 'graph') .attr('width', `${width + margin.left + margin.right}`) @@ -414,7 +394,12 @@ export class LineChart extends ObservableReactComponent { fillWidth /> -
+
{ + this._lineChartRef = r; + this.drawChart([this._lineChartData], this.rangeVals, this.width, this.height); + }} + /> {selectedPt !== 'none' ? (
{`Selected: ${selectedPt}`} -- cgit v1.2.3-70-g09d2 From 2bd8fb7fa526d8c03bbbf16ad3fe3b7447d2ca41 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 May 2024 23:54:56 -0400 Subject: made text unselectable in pieCharts --- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index c82496f1a..ce770d4f1 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -357,6 +357,7 @@ export class PieChart extends ObservableReactComponent { const heightOffset = (centroid[1] / radius) * Math.abs(centroid[1]); return 'translate(' + (centroid[0] + centroid[0] / (radius * 0.02)) + ',' + (centroid[1] + heightOffset) + ')'; }) + .attr('pointer-events', 'none') .attr('text-anchor', 'middle') .text(d => { let dataPoint; -- cgit v1.2.3-70-g09d2 From d6149b71d54fee2a303363c8342d51fdfdac3bb2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 May 2024 00:14:14 -0400 Subject: fix showing saved selections on pieCharts --- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index ce770d4f1..2bb8df9e5 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,7 +1,7 @@ import { Checkbox } from '@mui/material'; import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -98,7 +98,7 @@ export class PieChart extends ObservableReactComponent { svg.selectAll('path').attr('class', (d: any) => { let selected = false; selectedDataBars.forEach(eachSelectedData => { - if (d[key] === eachSelectedData) selected = true; + if (d.data === eachSelectedData) selected = true; }); if (selected) { this.selectedData.push(d); -- cgit v1.2.3-70-g09d2 From 0b1d434ad7f0d057456631ac786ed338c84a7f41 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 May 2024 00:20:59 -0400 Subject: simplified pieChart text --- src/client/views/nodes/DataVizBox/components/PieChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 2bb8df9e5..d5410c1aa 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -367,7 +367,7 @@ export class PieChart extends ObservableReactComponent { dataPoint = pieDataSet[possibleDataPointVals.indexOf(possibleDataPoints[trackDuplicates[d.data.toString()]])]; trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1; } - return dataPoint ? dataPoint[percentField]! + (!descriptionField ? '' : ' - ' + dataPoint[descriptionField])! : ''; + return dataPoint ? (descriptionField ? dataPoint[descriptionField] : dataPoint[percentField]!) : ''; }); }; -- cgit v1.2.3-70-g09d2 From 78fa489cd6e93ba5952c509deabafa4a69b74fd6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 May 2024 15:24:31 -0400 Subject: lint cleanup --- src/client/apis/gpt/customization.ts | 2 +- src/client/views/PropertiesView.tsx | 72 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 5 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 6 +- .../nodes/DataVizBox/components/LineChart.tsx | 2 +- .../views/nodes/DataVizBox/components/PieChart.tsx | 1 - .../views/nodes/DataVizBox/components/TableBox.tsx | 5 +- .../views/nodes/trails/CubicBezierEditor.tsx | 87 ++++---- src/client/views/nodes/trails/PresBox.tsx | 226 ++++++++------------- src/client/views/nodes/trails/SlideEffect.tsx | 17 +- 10 files changed, 189 insertions(+), 234 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts index 7da04918d..61b666bd3 100644 --- a/src/client/apis/gpt/customization.ts +++ b/src/client/apis/gpt/customization.ts @@ -103,7 +103,7 @@ export const getSlideTransitionSuggestions = async (inputText: string) => { } }; -export const gptTrailSlideCustomization = async (inputText: string, properties: any | any[], applyToWhole?: boolean) => { +export const gptTrailSlideCustomization = async (inputText: string, properties: any | any[]) => { let prompt = prompts.trails.description; prompts.trails.features.forEach(feature => { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 24f50eb8b..df4ed98ac 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1044,32 +1044,30 @@ export class PropertiesView extends ObservableReactComponent { this._sliderBatch?.end(); }; - getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => { - return ( -
- - { - this._sliderBatch = UndoManager.StartBatch('slider ' + label); - }} - multithumb={false} - color={this.color} - size={Size.XSMALL} - min={min} - max={max} - autorangeMinVal={autorangeMinVal} - autorange={autorange} - number={number} - unit={unit} - decimals={1} - setFinalNumber={this.setFinalNumber} - setNumber={setNumber} - fillWidth - /> -
- ); - }; + getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => ( +
+ + { + this._sliderBatch = UndoManager.StartBatch('slider ' + label); + }} + multithumb={false} + color={this.color} + size={Size.XSMALL} + min={min} + max={max} + autorangeMinVal={autorangeMinVal} + autorange={autorange} + number={number} + unit={unit} + decimals={1} + setFinalNumber={this.setFinalNumber} + setNumber={setNumber} + fillWidth + /> +
+ ); setVal = (func: (doc: Doc, val: number) => void) => (val: number) => this.selectedDoc && !isNaN(val) && func(this.selectedDoc, val); @computed get transformEditor() { @@ -1770,12 +1768,14 @@ export class PropertiesView extends ObservableReactComponent
(this.openPresTransitions = !this.openPresTransitions))} + onPointerDown={action(() => { + this.openPresTransitions = !this.openPresTransitions; + })} style={{ color: SnappingManager.userColor, backgroundColor: this.openPresTransitions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, }}> -     Transitions +     Transitions
@@ -1787,12 +1787,14 @@ export class PropertiesView extends ObservableReactComponent
(this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))} + onPointerDown={action(() => { + this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; + })} style={{ color: SnappingManager.userColor, backgroundColor: this.openPresVisibilityAndDuration ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, }}> -     Visibility +     Visibility
@@ -1804,12 +1806,14 @@ export class PropertiesView extends ObservableReactComponent
(this.openPresProgressivize = !this.openPresProgressivize))} + onPointerDown={action(() => { + this.openPresProgressivize = !this.openPresProgressivize; + })} style={{ color: SnappingManager.userColor, backgroundColor: this.openPresProgressivize ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, }}> -     Progressivize +     Progressivize
@@ -1821,7 +1825,9 @@ export class PropertiesView extends ObservableReactComponent
(this.openSlideOptions = !this.openSlideOptions))} + onPointerDown={action(() => { + this.openSlideOptions = !this.openSlideOptions; + })} style={{ color: SnappingManager.userColor, backgroundColor: this.openSlideOptions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 069132ec3..53493a968 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -14,6 +14,7 @@ import { DocData, Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; +import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../../fields/Types'; @@ -53,10 +54,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import { PropertiesView } from '../../PropertiesView'; -import { ExtractColors } from '../../ExtractColors'; -import { extname } from 'path'; -import { RichTextField } from '../../../../fields/RichTextField'; class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> { render() { diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index e91ed45c3..4d5f15a3e 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -14,6 +14,7 @@ import { Cast, CsvCast, DocCast, NumCast, StrCast } from '../../../../fields/Typ import { CsvField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { DocUtils } from '../../../documents/DocUtils'; +import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { UndoManager, undoable } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; @@ -31,7 +32,6 @@ import { Histogram } from './components/Histogram'; import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; -import { DocumentType } from '../../../documents/DocumentTypes'; export enum DataVizView { TABLE = 'table', @@ -127,8 +127,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors restoreView = (data: Doc) => { - const changedView = data.config_dataViz && this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz); - const changedAxes = data.config_dataVizAxes && this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List(StrListCast(data.config_dataVizAxes))); + // const changedView = data.config_dataViz && this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz); + // const changedAxes = data.config_dataVizAxes && this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List(StrListCast(data.config_dataVizAxes))); this.layoutDoc.dataViz_selectedRows = Field.Copy(data.dataViz_selectedRows); this.layoutDoc.dataViz_histogram_barColors = Field.Copy(data.dataViz_histogram_barColors); this.layoutDoc.dataViz_histogram_defaultColor = data.dataViz_histogram_defaultColor; diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index ffced14f8..d055d269c 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -1,6 +1,6 @@ import { Button, EditableText, Size } from 'browndash-components'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, NumListCast, StrListCast } from '../../../../../fields/Doc'; diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index d5410c1aa..19ea8e4fa 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -93,7 +93,6 @@ export class PieChart extends ObservableReactComponent { // restore selected slices const svg = this._piechartSvg; if (svg && this._pieChartData[0]) { - const key = Object.keys(this._pieChartData[0])[0]; const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_pie_selectedData); svg.selectAll('path').attr('class', (d: any) => { let selected = false; diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index bcd8e54f2..a1deb1625 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -64,7 +64,10 @@ export class TableBox extends ObservableReactComponent { // then we need to remove any selected rows that are no longer part of the visualized dataset. this._inputChangedDisposer = reaction(() => this._tableData.slice(), this.filterSelectedRowsDown, { fireImmediately: true }); const selected = NumListCast(this._props.layoutDoc.dataViz_selectedRows); - if (selected.length > 0) runInAction(() => (this.hasRowsToFilter = true)); + if (selected.length > 0) + runInAction(() => { + this.hasRowsToFilter = true; + }); this.handleScroll(); } componentWillUnmount() { diff --git a/src/client/views/nodes/trails/CubicBezierEditor.tsx b/src/client/views/nodes/trails/CubicBezierEditor.tsx index a5e21259a..e1ad1e6e5 100644 --- a/src/client/views/nodes/trails/CubicBezierEditor.tsx +++ b/src/client/views/nodes/trails/CubicBezierEditor.tsx @@ -3,7 +3,6 @@ import React, { useEffect, useState } from 'react'; type Props = { setFunc: (newPoints: { p1: number[]; p2: number[] }) => void; currPoints: { p1: number[]; p2: number[] }; - easeFunc: string; }; const ANIMATION_DURATION = 750; @@ -20,52 +19,50 @@ export const TIMING_DEFAULT_MAPPINGS = { 'ease-in-out': 'cubic-bezier(0.42, 0, 0.58, 1.0)', }; +export function EaseFuncToPoints(func: string) { + let strPoints = func || 'ease'; + if (!strPoints.startsWith('cubic')) { + switch (func) { + case 'linear': + strPoints = 'cubic-bezier(0.0, 0.0, 1.0, 1.0)'; + break; + case 'ease': + strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; + break; + case 'ease-in': + strPoints = 'cubic-bezier(0.42, 0, 1.0, 1.0)'; + break; + case 'ease-out': + strPoints = 'cubic-bezier(0, 0, 0.58, 1.0)'; + break; + case 'ease-in-out': + strPoints = 'cubic-bezier(0.42, 0, 0.58, 1.0)'; + break; + default: + strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; + } + } + const components = strPoints + .split('(')[1] + .split(')')[0] + .split(',') + .map(elem => parseFloat(elem)); + return { + p1: [components[0], components[1]], + p2: [components[2], components[3]], + }; +} + /** * Visual editor for a bezier curve with draggable control points. * */ -const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { +function CubicBezierEditor({ setFunc, currPoints }: Props) { const [animating, setAnimating] = useState(false); const [c1Down, setC1Down] = useState(false); const [c2Down, setC2Down] = useState(false); - const roundToHundredth = (num: number) => { - return Math.round(num * 100) / 100; - }; - - const convertToPoints = (func: string) => { - let strPoints = func ? func : 'ease'; - if (!strPoints.startsWith('cubic')) { - switch (func) { - case 'linear': - strPoints = 'cubic-bezier(0.0, 0.0, 1.0, 1.0)'; - break; - case 'ease': - strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; - break; - case 'ease-in': - strPoints = 'cubic-bezier(0.42, 0, 1.0, 1.0)'; - break; - case 'ease-out': - strPoints = 'cubic-bezier(0, 0, 0.58, 1.0)'; - break; - case 'ease-in-out': - strPoints = 'cubic-bezier(0.42, 0, 0.58, 1.0)'; - break; - default: - strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; - } - } - const components = strPoints - .split('(')[1] - .split(')')[0] - .split(',') - .map(elem => parseFloat(elem)); - return { - p1: [components[0], components[1]], - p2: [components[2], components[3]], - }; - }; + const roundToHundredth = (num: number) => Math.round(num * 100) / 100; useEffect(() => { if (animating) { @@ -76,7 +73,7 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { }, [animating]); useEffect(() => { - if (!c1Down) return; + if (!c1Down) return undefined; window.addEventListener('pointerup', () => { setC1Down(false); }); @@ -99,7 +96,7 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { // Sets up pointer events for moving the control points useEffect(() => { - if (!c2Down) return; + if (!c2Down) return undefined; window.addEventListener('pointerup', () => { setC2Down(false); }); @@ -163,7 +160,7 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { e.stopPropagation(); setC1Down(true); }} - onPointerUp={e => { + onPointerUp={() => { setC1Down(false); }} /> @@ -173,7 +170,7 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { e.stopPropagation(); setC2Down(true); }} - onPointerUp={e => { + onPointerUp={() => { setC2Down(false); }} x1={`${EDITOR_WIDTH + OFFSET}`} @@ -193,13 +190,13 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { e.stopPropagation(); setC2Down(true); }} - onPointerUp={e => { + onPointerUp={() => { setC2Down(false); }} />
); -}; +} export default CubicBezierEditor; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index c718b5b3c..69d03ac2e 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2,9 +2,16 @@ /* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; +import Slider from '@mui/material/Slider'; +import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { AiOutlineSend } from 'react-icons/ai'; +import { BiMicrophone } from 'react-icons/bi'; +import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp } from 'react-icons/fa'; +import ReactLoading from 'react-loading'; +import ReactTextareaAutosize from 'react-textarea-autosize'; import { lightOrDark, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../ClientUtils'; import { Doc, DocListCast, Field, FieldResult, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Animation, DocData, TransitionTimer } from '../../../../fields/DocSymbols'; @@ -16,9 +23,11 @@ import { listSpec } from '../../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast, toList } from '../../../../fields/Types'; import { emptyFunction, emptyPath, stringHash } from '../../../../Utils'; +import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization'; import { DocServer } from '../../../DocServer'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; +import { DictationManager } from '../../../util/DictationManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { SerializationHelper } from '../../../util/SerializationHelper'; @@ -36,21 +45,12 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { FocusViewOptions } from '../FocusViewOptions'; import { OpenWhere, OpenWhereMod } from '../OpenWhere'; import { ScriptingBox } from '../ScriptingBox'; +import CubicBezierEditor, { EaseFuncToPoints, TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor'; import './PresBox.scss'; -import ReactLoading from 'react-loading'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; -import ReactTextareaAutosize from 'react-textarea-autosize'; -import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components'; -import { BiMicrophone } from 'react-icons/bi'; -import { AiOutlineSend } from 'react-icons/ai'; -import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization'; -import { DictationManager } from '../../../util/DictationManager'; -import CubicBezierEditor, { TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor'; -import Slider from '@mui/material/Slider'; -import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaCompressArrowsAlt } from 'react-icons/fa'; -import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings, AnimationSettings, springPreviewColors } from './SpringUtils'; import SlideEffect from './SlideEffect'; -import { IoMdInformationCircleOutline } from 'react-icons/io'; +import { AnimationSettings, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors, SpringSettings, SpringType } from './SpringUtils'; + @observer export class PresBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { @@ -161,9 +161,6 @@ export class PresBox extends ViewBoxBaseComponent() { this.isLoading = isLoading; }; - @action - public setChatActive = (active: boolean) => {}; - @action public setIsRecording = (isRecording: boolean) => { this.isRecording = isRecording; @@ -188,37 +185,8 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get currCPoints() { - let strPoints = this.activeItem.presEaseFunc ? StrCast(this.activeItem.presEaseFunc) : 'ease'; - if (!strPoints.startsWith('cubic')) { - switch (StrCast(this.activeItem.presEaseFunc)) { - case 'linear': - strPoints = 'cubic-bezier(0.0, 0.0, 1.0, 1.0)'; - break; - case 'ease': - strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; - break; - case 'ease-in': - strPoints = 'cubic-bezier(0.42, 0, 1.0, 1.0)'; - break; - case 'ease-out': - strPoints = 'cubic-bezier(0, 0, 0.58, 1.0)'; - break; - case 'ease-in-out': - strPoints = 'cubic-bezier(0.42, 0, 0.58, 1.0)'; - break; - default: - strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; - } - } - const components = strPoints - .split('(')[1] - .split(')')[0] - .split(',') - .map(elem => parseFloat(elem)); - return { - p1: [components[0], components[1]], - p2: [components[2], components[3]], - }; + const strPoints = this.activeItem.presEaseFunc ? StrCast(this.activeItem.presEaseFunc) : 'ease'; + return EaseFuncToPoints(strPoints); } @computed @@ -364,7 +332,7 @@ export class PresBox extends ViewBoxBaseComponent() { } }); }; - stopDictation = (abort: boolean) => { + stopDictation = () => { this.setIsRecording(false); DictationManager.Controls.stop(); }; @@ -375,7 +343,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; @action - customizeAnimations = async (input: string) => { + customizeAnimations = async () => { this.setIsLoading(true); try { const res = await getSlideTransitionSuggestions(this.animationChat); @@ -396,19 +364,18 @@ export class PresBox extends ViewBoxBaseComponent() { this.setIsRecording(false); this.setIsLoading(true); - let currSlideProperties: { [key: string]: any } = {}; - for (const key of gptSlideProperties) { + const currSlideProperties: { [key: string]: any } = {}; + gptSlideProperties.forEach(key => { if (this.activeItem[key]) { currSlideProperties[key] = this.activeItem[key]; - } else { - // default values - if (key === 'presentation_transition') { - currSlideProperties[key] = 500; - } else if (key === 'config_zoom') { - currSlideProperties[key] = 1.0; - } } - } + // default values + else if (key === 'presentation_transition') { + currSlideProperties[key] = 500; + } else if (key === 'config_zoom') { + currSlideProperties[key] = 1.0; + } + }); console.log('current slide props ', currSlideProperties); try { @@ -416,7 +383,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (typeof res === 'string') { const resObj = JSON.parse(res); console.log('Parsed GPT Result ', resObj); - for (let key in resObj) { + // eslint-disable-next-line no-restricted-syntax + for (const key in resObj) { if (resObj[key]) { console.log('typeof property', typeof resObj[key]); this.activeItem[key] = resObj[key]; @@ -1612,10 +1580,12 @@ export class PresBox extends ViewBoxBaseComponent() { doc.presEaseFunc = activeItem.presEaseFunc; }); }; - + setEaseFunc = (activeItem: Doc, easeFunc: string) => { activeItem.presEaseFunc = easeFunc; - this.selectedArray.forEach(doc => (doc.presEaseFunc = activeItem.presEaseFunc)); + this.selectedArray.forEach(doc => { + doc.presEaseFunc = activeItem.presEaseFunc; + }); }; @undoBatch @@ -1633,7 +1603,9 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateEffectTiming = (activeItem: Doc, timing: SpringSettings) => { activeItem.presEffectTiming = JSON.stringify(timing); - this.selectedArray.forEach(doc => (doc.presEffectTiming = activeItem.presEffectTiming)); + this.selectedArray.forEach(doc => { + doc.presEffectTiming = activeItem.presEffectTiming; + }); }; static _sliderBatch: any; @@ -1702,7 +1674,7 @@ export class PresBox extends ViewBoxBaseComponent() { Hide before
- {'Hide while presented'}
}> + Hide while presented
}>
() { Hide
- {'Hide after presented'}
}> + Hide after presented
}>
() {
- {'Open in lightbox view'}
}> + Open in lightbox view}>
() {
Slide Duration
- e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s + e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
{PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)} -
+
Short
Medium
Long
@@ -1784,12 +1756,12 @@ export class PresBox extends ViewBoxBaseComponent() { // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list. let dataField = Doc.LayoutFieldKey(tagDoc); - if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations'; + if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField += '_annotations'; if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`); else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`); }} - checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false} + checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined} />
@@ -1798,7 +1770,9 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-checkbox" style={{ margin: 10, border: `solid 1px ${SnappingManager.userColor}` }} type="checkbox" - onChange={() => (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)} + onChange={() => { + activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1; + }} checked={!NumCast(activeItem.presentation_indexedStart)} />
@@ -1808,7 +1782,9 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-checkbox" style={{ margin: 10, border: `solid 1px ${SnappingManager.userColor}` }} type="checkbox" - onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)} + onChange={() => { + activeItem.presBulletExpand = !activeItem.presBulletExpand; + }} checked={BoolCast(activeItem.presBulletExpand)} />
@@ -1828,14 +1804,14 @@ export class PresBox extends ViewBoxBaseComponent() { border: this._openBulletEffectDropdown ? `solid 2px ${SnappingManager.userVariantColor}` : `solid 1px ${SnappingManager.userColor}`, }}> {effect?.toString()} - +
e.stopPropagation()}> {Object.values(PresEffect) .filter(v => isNaN(Number(v))) - .map(effect => bulletEffect(effect))} + .map(pEffect => bulletEffect(pEffect))}
@@ -1847,14 +1823,13 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get gptDropdown() { - const activeItem = this.activeItem; - return
; + return
; } @computed get transitionDropdown() { const { activeItem } = this; // Retrieving spring timing properties - let timing = StrCast(activeItem.presEffectTiming); + const timing = StrCast(activeItem.presEffectTiming); let timingConfig: SpringSettings | undefined; if (timing) { timingConfig = JSON.parse(timing); @@ -1869,32 +1844,6 @@ export class PresBox extends ViewBoxBaseComponent() { }; } - const presEffect = (effect: PresEffect) => ( -
this.updateEffect(effect, false)}> - {effect} -
- ); - const presMovement = (movement: PresMovement) => ( -
this.updateMovement(movement)}> - {movement} -
- ); - const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? SnappingManager.userVariantColor : SnappingManager.userColor; - return ( - {direction}
}> -
this.updateEffectDirection(direction)}> - {icon ? : null} -
-
- ); - }; - if (activeItem && this.targetDoc) { const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; const zoom = NumCast(activeItem.config_zoom, 1) * 100; @@ -1903,7 +1852,7 @@ export class PresBox extends ViewBoxBaseComponent() { return ( <> - {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT*/} + {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT */}
Customize Slide Properties{' '} @@ -1921,7 +1870,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.setChatInput(e.target.value); }} onKeyDown={e => { - this.stopDictation(true); + this.stopDictation(); e.stopPropagation(); }} /> @@ -1929,12 +1878,12 @@ export class PresBox extends ViewBoxBaseComponent() { type={Type.TERT} color={this.isRecording ? '#2bcaff' : StrCast(Doc.UserDoc().userVariantColor)} tooltip="Record" - icon={} + icon={} onClick={() => { if (!this.isRecording) { this.recordDictation(); } else { - this.stopDictation(true); + this.stopDictation(); } }} /> @@ -1943,11 +1892,11 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ alignSelf: 'flex-end' }} text="Send" type={Type.TERT} - icon={this.isLoading ? : } + icon={this.isLoading ? : } iconPlacement="right" color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => { - this.stopDictation(true); + this.stopDictation(); this.customizeWithGPT(this.chatInput); }} /> @@ -1971,8 +1920,8 @@ export class PresBox extends ViewBoxBaseComponent() { Movement { @@ -1984,18 +1933,18 @@ export class PresBox extends ViewBoxBaseComponent() {
Zoom (% screen filled)
- this.updateZoom(e.target.value)} />% + this.updateZoom(e.target.value)} />%
{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
Transition Time
- e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s + e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
{PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} -
+
Fast
Medium
Slow
@@ -2003,8 +1952,8 @@ export class PresBox extends ViewBoxBaseComponent() { {/* Easing function */} { @@ -2040,7 +1989,7 @@ export class PresBox extends ViewBoxBaseComponent() {

Custom Timing Function

- +
)} @@ -2057,7 +2006,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.setAnimationChat(e.target.value); }} onKeyDown={e => { - this.stopDictation(true); + this.stopDictation(); e.stopPropagation(); }} /> @@ -2066,12 +2015,10 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ alignSelf: 'flex-end' }} text="Send" type={Type.TERT} - icon={this.isLoading ? : } + icon={this.isLoading ? : } iconPlacement="right" color={StrCast(Doc.UserDoc().userVariantColor)} - onClick={() => { - this.customizeAnimations(this.animationChat); - }} + onClick={this.customizeAnimations} />
@@ -2093,6 +2040,7 @@ export class PresBox extends ViewBoxBaseComponent() {
{this.generatedAnimations.map((elem, i) => (
{ @@ -2106,7 +2054,7 @@ export class PresBox extends ViewBoxBaseComponent() { }); }}> -
+
))} @@ -2115,8 +2063,8 @@ export class PresBox extends ViewBoxBaseComponent() { {/* Effect dropdown */} { @@ -2142,14 +2090,14 @@ export class PresBox extends ViewBoxBaseComponent() { type={Type.TERT} color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} tooltip="Left" - icon={} + icon={} onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} /> } + icon={} onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} /> {effect !== PresEffect.Roll && ( @@ -2158,14 +2106,14 @@ export class PresBox extends ViewBoxBaseComponent() { type={Type.TERT} color={activeItem.presentation_effectDirection === PresEffectDirection.Top ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} tooltip="Top" - icon={} + icon={} onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} /> } + icon={} onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} /> @@ -2179,8 +2127,8 @@ export class PresBox extends ViewBoxBaseComponent() { <> { @@ -2261,7 +2209,7 @@ export class PresBox extends ViewBoxBaseComponent() {
-
+
@@ -2274,17 +2222,21 @@ export class PresBox extends ViewBoxBaseComponent() { {/* Toggles */}
(activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} + onClick={() => { + activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio); + }} color={SnappingManager.userColor} /> (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} + onClick={() => { + activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText); + }} color={SnappingManager.userColor} />
{/* presbox chatbox */} - {this.chatActive &&
} + {this.chatActive &&
}
); } diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx index e0be86875..03cd88f45 100644 --- a/src/client/views/nodes/trails/SlideEffect.tsx +++ b/src/client/views/nodes/trails/SlideEffect.tsx @@ -1,9 +1,10 @@ -import { useSpring, animated, easings, to, useInView } from '@react-spring/web'; -import React, { useEffect, useState } from 'react'; -import { PresEffect, PresEffectDirection } from './PresEnums'; -import './SlideEffect.scss'; +/* eslint-disable react/require-default-props */ +import { animated, to, useInView, useSpring } from '@react-spring/web'; +import React, { useEffect } from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; +import { PresEffect, PresEffectDirection } from './PresEnums'; +import './SlideEffect.scss'; interface SlideEffectProps { // pass in doc to extract width, height, bg @@ -296,7 +297,7 @@ export default function SpringAnimation({ doc, dir, friction, tension, mass, pre {dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? ( <> `perspective(600px) rotateX(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, @@ -305,7 +306,7 @@ export default function SpringAnimation({ doc, dir, friction, tension, mass, pre }} /> `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} @@ -313,11 +314,11 @@ export default function SpringAnimation({ doc, dir, friction, tension, mass, pre ) : ( <> `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }} /> `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} -- cgit v1.2.3-70-g09d2 From fdd0e62c148fde01c82504700a83fcc56463a68d Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 May 2024 16:18:46 -0400 Subject: cleaned up highlighting selected points in lineChart --- .../nodes/DataVizBox/components/LineChart.tsx | 69 ++++++++-------------- 1 file changed, 23 insertions(+), 46 deletions(-) (limited to 'src/client/views/nodes/DataVizBox/components') diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index d055d269c..c2f5388a2 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -1,6 +1,6 @@ import { Button, EditableText, Size } from 'browndash-components'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, makeObservable, observable } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, NumListCast, StrListCast } from '../../../../../fields/Doc'; @@ -52,6 +52,13 @@ export class LineChart extends ObservableReactComponent { makeObservable(this); } + @computed get titleAccessor() { + let titleAccessor: any = 'dataViz_lineChart_title'; + if (this._props.axes.length === 2) titleAccessor = titleAccessor + this._props.axes[0] + '-' + this._props.axes[1]; + else if (this._props.axes.length > 0) titleAccessor += this._props.axes[0]; + return titleAccessor; + } + @computed get _tableDataIds() { return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } @@ -84,7 +91,9 @@ export class LineChart extends ObservableReactComponent { } componentDidMount() { // coloring the selected point - this.colorSelectedPt(); + if (!this._props.layoutDoc[this.titleAccessor]) this._props.layoutDoc[this.titleAccessor] = this.defaultGraphTitle; + if (!this._props.layoutDoc.dataViz_lineChart_selectedData) this._props.layoutDoc.dataViz_lineChart_selectedData = new List(); + this._disposers.selector = reaction(() => StrListCast(this._props.layoutDoc.dataViz_lineChart_selectedData).slice(), this.colorSelectedPts, { fireImmediately: true }); } // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that @@ -98,19 +107,6 @@ export class LineChart extends ObservableReactComponent { } }; - // draws red annotation on data points when selected - drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => { - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - const x = element.getAttribute('data-x'); - const y = element.getAttribute('data-y'); - if (x === dataX.toString() && y === dataY.toString()) { - element.classList.add(selected ? 'selected' : 'brushed'); - } - } - }; - // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc) getAnchor = (pinProps?: PinProps) => { const anchor = Docs.Create.ConfigDocument({ @@ -122,23 +118,20 @@ export class LineChart extends ObservableReactComponent { return anchor; }; - private colorSelectedPt() { + private colorSelectedPts = () => { const elements = document.querySelectorAll('.datapoint'); for (let i = 0; i < elements.length; i++) { - const x = Number(elements[i].getAttribute('data-x')); - const y = Number(elements[i].getAttribute('data-y')); + const dx = Number(elements[i].getAttribute('data-x')); + const dy = Number(elements[i].getAttribute('data-y')); const selectedDataBars = StrListCast(this._props.layoutDoc.dataViz_lineChart_selectedData); - let selected = false; - selectedDataBars.forEach(eachSelectedData => { - // parse each selected point into x,y - const xy = eachSelectedData.split(','); - if (Number(xy[0]) === x && Number(xy[1]) === y) selected = true; + const selected = selectedDataBars.some(eachSelectedData => { + const [sx, sy] = eachSelectedData.split(','); // parse each selected point into x,y + return Number(sx) === dx && Number(sy) === dy; }); - if (selected) { - this.drawAnnotations(x, y, false); - } + if (selected) elements[i].classList.add('brushed'); + else elements[i].classList.remove('brushed'); } - } + }; @computed get height() { return this._props.height - this._props.margin.top - this._props.margin.bottom; @@ -195,17 +188,6 @@ export class LineChart extends ObservableReactComponent { } }); } - - // coloring the selected point - const elements = document.querySelectorAll('.datapoint'); - for (let i = 0; i < elements.length; i++) { - const x = Number(elements[i].getAttribute('data-x')); - const y = Number(elements[i].getAttribute('data-y')); - if (x === d.x && y === d.y) { - if (ptWasSelected) elements[i].classList.remove('brushed'); - else elements[i].classList.add('brushed'); - } - } } drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear, yScale: d3.ScaleLinear, higlightFocusPt: any, tooltip: any) { @@ -234,7 +216,6 @@ export class LineChart extends ObservableReactComponent { // find .circle-d1 with data-x = d0.x and data-y = d0.y this.setCurrSelected(d0); this.updateTooltip(higlightFocusPt, xScale, d0, yScale, tooltip); - this.colorSelectedPt(); }); } } @@ -341,6 +322,7 @@ export class LineChart extends ObservableReactComponent { .attr('width', 20) .style('text-anchor', 'middle') .text(this._props.axes[1]); + this.colorSelectedPts(); }; private updateTooltip( @@ -360,11 +342,6 @@ export class LineChart extends ObservableReactComponent { } render() { - let titleAccessor: any = 'dataViz_lineChart_title'; - if (this._props.axes.length === 2) titleAccessor = titleAccessor + this._props.axes[0] + '-' + this._props.axes[1]; - else if (this._props.axes.length > 0) titleAccessor += this._props.axes[0]; - if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; - if (!this._props.layoutDoc.dataViz_lineChart_selectedData) this._props.layoutDoc.dataViz_lineChart_selectedData = new List(); const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; let selectedTitle = ''; if (this._currSelected && this._props.titleCol) { @@ -382,10 +359,10 @@ export class LineChart extends ObservableReactComponent {
{ - this._props.layoutDoc[titleAccessor] = val as string; + this._props.layoutDoc[this.titleAccessor] = val as string; }), 'Change Graph Title' )} -- cgit v1.2.3-70-g09d2