From 2f440c327031b58c58e87dbeb70602bf3c695ada Mon Sep 17 00:00:00 2001 From: kedi Date: Tue, 7 Nov 2023 18:07:19 -0500 Subject: [PATCH 01/15] line component implemented --- src/app/app.component.html | 30 ++ src/app/app.module.ts | 5 +- src/app/chartTypes.ts | 23 + .../combo-chart.component.html | 113 +++++ .../combo-chart.component.scss | 88 ++++ .../combo-chart.component.ts | 414 ++++++++++++++++++ .../combo-series-vertical.component.ts | 43 ++ .../combo-chart-line-pie/index.ts | 2 + .../line-pie-combo-chart/index.ts | 2 + 9 files changed, 719 insertions(+), 1 deletion(-) create mode 100644 src/app/custom-charts/combo-chart-line-pie/combo-chart.component.html create mode 100644 src/app/custom-charts/combo-chart-line-pie/combo-chart.component.scss create mode 100644 src/app/custom-charts/combo-chart-line-pie/combo-chart.component.ts create mode 100644 src/app/custom-charts/combo-chart-line-pie/combo-series-vertical.component.ts create mode 100644 src/app/custom-charts/combo-chart-line-pie/index.ts create mode 100644 src/app/custom-charts/line-pie-combo-chart/index.ts diff --git a/src/app/app.component.html b/src/app/app.component.html index 6dd4b53cc..3f3cac762 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -597,6 +597,35 @@ (select)="onSelect($event)" > +
+ + +
+
{{ bubbleDemoTempData | json }}
{{ barChart | json }}
{{ lineChartSeries | json }}
+
{{ lineChartSeries | json }}
{{ timelineFilterBarData | json }}
{ + const dataPoint = item.series.find(data => data.name === this.tempXValueForComboPie); + data.push({ name: item.name, + value: dataPoint.value, + extra: { + code: item.name.toLowerCase() + }}); + }) + } + return data; + } + calcStatusData(sales = this.statusData[0].value, dur = this.statusData[2].value) { const ret = sales * this.salePrice; const cost = ((sales * dur) / 60 / 60 / 1000) * this.personnelCost; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f2c7a1c4a..3caa1bda6 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -10,7 +10,7 @@ import { NgxChartsModule } from '@swimlane/ngx-charts/ngx-charts.module'; import { NgxUIModule } from '@swimlane/ngx-ui'; import { ComboChartComponent, ComboSeriesVerticalComponent } from './custom-charts/combo-chart'; import { BubbleChartInteractiveModule } from './custom-charts/bubble-chart-interactive'; -import { ComboChartLinePieComponent, ComboSeriesLinePieVerticalComponent } from './custom-charts/combo-chart-line-pie'; + @NgModule({ providers: [ @@ -32,9 +32,7 @@ import { ComboChartLinePieComponent, ComboSeriesLinePieVerticalComponent } from SparklineComponent, TimelineFilterBarChartComponent, ComboChartComponent, - ComboSeriesVerticalComponent, - ComboChartLinePieComponent, - ComboSeriesLinePieVerticalComponent + ComboSeriesVerticalComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.html b/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.html deleted file mode 100644 index 66428d7ee..000000000 --- a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.scss b/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.scss deleted file mode 100644 index 85409ae43..000000000 --- a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.scss +++ /dev/null @@ -1,88 +0,0 @@ -.ngx-charts { - float: left; - overflow: visible; - - .circle, - .bar, - .arc { - cursor: pointer; - } - - .bar, - .cell, - .arc, - .card { - &.active, - &:hover { - opacity: 0.8; - transition: opacity 100ms ease-in-out; - } - - &:focus { - outline: none; - } - &.hidden { - display: none; - } - } - - g { - &:focus { - outline: none; - } - } - - .line-series, - .line-series-range, - .area-series { - &.inactive { - transition: opacity 100ms ease-in-out; - opacity: 0.2; - } - } - - .line-highlight { - display: none; - - &.active { - display: block; - } - } - - .area { - opacity: 0.6; - } - - .circle { - &:hover { - cursor: pointer; - } - } - - .label { - font-size: 12px; - font-weight: normal; - } - - .tooltip-anchor { - fill: rgb(0, 0, 0); - } - - .gridline-path { - stroke: #ddd; - stroke-width: 1; - fill: none; - } - - .grid-panel { - rect { - fill: none; - } - - &.odd { - rect { - fill: rgba(0, 0, 0, 0.05); - } - } - } -} diff --git a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.ts b/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.ts deleted file mode 100644 index 76d274e94..000000000 --- a/src/app/custom-charts/combo-chart-line-pie/combo-chart.component.ts +++ /dev/null @@ -1,414 +0,0 @@ -import { - Component, - Input, - ViewEncapsulation, - Output, - EventEmitter, - ViewChild, - HostListener, - ContentChild, - TemplateRef -} from '@angular/core'; - -import { curveLinear } from 'd3-shape'; -import { scaleBand, scaleLinear, scalePoint, scaleTime } from 'd3-scale'; -import { - BaseChartComponent, - LineSeriesComponent, - ViewDimensions, - ColorHelper, - calculateViewDimensions, - ScaleType, - Orientation, - Color -} from 'projects/swimlane/ngx-charts/src/public-api'; - -@Component({ - // tslint:disable-next-line: component-selector - selector: 'combo-chart-line-pie-component', - templateUrl: './combo-chart.component.html', - styleUrls: ['./combo-chart.component.scss'], - encapsulation: ViewEncapsulation.None -}) -export class ComboChartLinePieComponent extends BaseChartComponent { - @Input() curve: any = curveLinear; - @Input() legend = false; - @Input() legendTitle: string = 'Legend'; - @Input() legendPosition: string = 'right'; - @Input() xAxis; - @Input() yAxis; - @Input() showXAxisLabel; - @Input() showYAxisLabel; - @Input() showRightYAxisLabel; - @Input() xAxisLabel; - @Input() yAxisLabel; - @Input() yAxisLabelRight; - @Input() tooltipDisabled: boolean = false; - @Input() gradient: boolean; - @Input() showGridLines: boolean = true; - @Input() activeEntries: any[] = []; - @Input() schemeType: ScaleType; - @Input() xAxisTickFormatting: any; - @Input() yAxisTickFormatting: any; - @Input() roundDomains: boolean = false; - @Input() colorSchemeLine: Color; - @Input() autoScale; - @Input() lineChart: any; - @Input() yLeftAxisScaleFactor: any; - @Input() yRightAxisScaleFactor: any; - @Input() rangeFillOpacity: number; - @Input() animations: boolean = true; - @Input() noBarWhenZero: boolean = true; - @Input() wrapTicks = false; - - @Output() activate: EventEmitter = new EventEmitter(); - @Output() deactivate: EventEmitter = new EventEmitter(); - - @ContentChild('tooltipTemplate') tooltipTemplate: TemplateRef; - @ContentChild('seriesTooltipTemplate') seriesTooltipTemplate: TemplateRef; - - @ViewChild(LineSeriesComponent) lineSeriesComponent: LineSeriesComponent; - - dims: ViewDimensions; - xScale: any; - yScale: any; - xDomain: any; - yDomain: any; - transform: string; - colors: ColorHelper; - colorsLine: ColorHelper; - margin: any[] = [10, 20, 10, 20]; - xAxisHeight: number = 0; - yAxisWidth: number = 0; - legendOptions: any; - scaleType = ScaleType.Linear; - xScaleLine; - yScaleLine; - xDomainLine; - yDomainLine; - seriesDomain; - scaledAxis; - combinedSeries; - xSet; - filteredDomain; - hoveredVertical; - yOrientLeft = Orientation.Left; - yOrientRight = Orientation.Right; - legendSpacing = 0; - bandwidth; - barPadding = 8; - - trackBy(index, item): string { - return `${item.name}`; - } - - update(): void { - super.update(); - console.log(this.width) - this.dims = calculateViewDimensions({ - width: this.width, - height: this.height, - margins: this.margin, - showXAxis: this.xAxis, - showYAxis: this.yAxis, - xAxisHeight: this.xAxisHeight, - yAxisWidth: this.yAxisWidth, - showXLabel: this.showXAxisLabel, - showYLabel: this.showYAxisLabel, - showLegend: this.legend, - legendType: this.schemeType, - legendPosition: this.legendPosition as any - }); - - if (!this.yAxis) { - this.legendSpacing = 0; - } else if (this.showYAxisLabel && this.yAxis) { - this.legendSpacing = 100; - } else { - this.legendSpacing = 40; - } - this.xScale = this.getXScale(); - this.yScale = this.getYScale(); - - // line chart - this.xDomainLine = this.getXDomainLine(); - if (this.filteredDomain) { - this.xDomainLine = this.filteredDomain; - } - - this.yDomainLine = this.getYDomainLine(); - this.seriesDomain = this.getSeriesDomain(); - - this.scaleLines(); - - this.setColors(); - this.legendOptions = this.getLegendOptions(); - - this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`; - } - - deactivateAll() { - this.activeEntries = [...this.activeEntries]; - for (const entry of this.activeEntries) { - this.deactivate.emit({ value: entry, entries: [] }); - } - this.activeEntries = []; - } - - @HostListener('mouseleave') - hideCircles(): void { - this.hoveredVertical = null; - this.deactivateAll(); - } - - updateHoveredVertical(item): void { - this.hoveredVertical = item.value; - this.deactivateAll(); - } - - updateDomain(domain): void { - this.filteredDomain = domain; - this.xDomainLine = this.filteredDomain; - this.xScaleLine = this.getXScaleLine(this.xDomainLine, this.dims.width); - } - - scaleLines() { - this.xScaleLine = this.getXScaleLine(this.xDomainLine, this.dims.width); - this.yScaleLine = this.getYScaleLine(this.yDomainLine, this.dims.height); - } - - getSeriesDomain(): any[] { - this.combinedSeries = this.lineChart.slice(0); - this.combinedSeries.push({ - name: this.yAxisLabel, - series: this.results - }); - return this.combinedSeries.map(d => d.name); - } - - isDate(value): boolean { - if (value instanceof Date) { - return true; - } - - return false; - } - - getScaleType(values): ScaleType { - let date = true; - let num = true; - - for (const value of values) { - if (!this.isDate(value)) { - date = false; - } - - if (typeof value !== 'number') { - num = false; - } - } - - if (date) { - return ScaleType.Time; - } - - if (num) { - return ScaleType.Linear; - } - - return ScaleType.Ordinal; - } - - getXDomainLine(): any[] { - let values = []; - - for (const results of this.lineChart) { - for (const d of results.series) { - if (!values.includes(d.name)) { - values.push(d.name); - } - } - } - - this.scaleType = this.getScaleType(values); - let domain = []; - - if (this.scaleType === 'time') { - const min = Math.min(...values); - const max = Math.max(...values); - domain = [min, max]; - } else if (this.scaleType === 'linear') { - values = values.map(v => Number(v)); - const min = Math.min(...values); - const max = Math.max(...values); - domain = [min, max]; - } else { - domain = values; - } - - this.xSet = values; - return domain; - } - - getYDomainLine(): any[] { - const domain = []; - - for (const results of this.lineChart) { - for (const d of results.series) { - if (domain.indexOf(d.value) < 0) { - domain.push(d.value); - } - if (d.min !== undefined) { - if (domain.indexOf(d.min) < 0) { - domain.push(d.min); - } - } - if (d.max !== undefined) { - if (domain.indexOf(d.max) < 0) { - domain.push(d.max); - } - } - } - } - - let min = Math.min(...domain); - const max = Math.max(...domain); - if (this.yRightAxisScaleFactor) { - const minMax = this.yRightAxisScaleFactor(min, max); - return [Math.min(0, minMax.min), minMax.max]; - } else { - min = Math.min(0, min); - return [min, max]; - } - } - - getXScaleLine(domain, width): any { - let scale; - if (this.bandwidth === undefined) { - this.bandwidth = width - this.barPadding; - } - const offset = Math.floor((width + this.barPadding - (this.bandwidth + this.barPadding) * domain.length) / 2); - - if (this.scaleType === 'time') { - scale = scaleTime().range([0, width]).domain(domain); - } else if (this.scaleType === 'linear') { - scale = scaleLinear().range([0, width]).domain(domain); - - if (this.roundDomains) { - scale = scale.nice(); - } - } else if (this.scaleType === 'ordinal') { - scale = scalePoint() - .range([offset + this.bandwidth / 2, width - offset - this.bandwidth / 2]) - .domain(domain); - } - - return scale; - } - - getYScaleLine(domain, height): any { - const scale = scaleLinear().range([height, 0]).domain(domain); - - return this.roundDomains ? scale.nice() : scale; - } - - getXScale(): any { - this.xDomain = this.getXDomain(); - const spacing = this.xDomain.length / (this.dims.width / this.barPadding + 1); - return scaleBand().range([0, this.dims.width]).paddingInner(spacing).domain(this.xDomain); - } - - getYScale(): any { - this.yDomain = this.getYDomain(); - const scale = scaleLinear().range([this.dims.height, 0]).domain(this.yDomain); - return this.roundDomains ? scale.nice() : scale; - } - - getXDomain(): any[] { - return this.results.map(d => d.name); - } - - getYDomain() { - const values = this.results.map(d => d.value); - const min = Math.min(0, ...values); - const max = Math.max(...values); - if (this.yLeftAxisScaleFactor) { - const minMax = this.yLeftAxisScaleFactor(min, max); - return [Math.min(0, minMax.min), minMax.max]; - } else { - return [min, max]; - } - } - - onClick(data) { - this.select.emit(data); - } - - setColors(): void { - let domain; - if (this.schemeType === ScaleType.Ordinal) { - domain = this.xDomain; - } else { - domain = this.yDomain; - } - this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors); - this.colorsLine = new ColorHelper(this.colorSchemeLine, this.schemeType, domain, this.customColors); - } - - getLegendOptions() { - const opts = { - scaleType: this.schemeType, - colors: undefined, - domain: [], - title: undefined, - position: this.legendPosition - }; - if (opts.scaleType === ScaleType.Ordinal) { - opts.domain = this.seriesDomain; - opts.colors = this.colorsLine; - opts.title = this.legendTitle; - } else { - opts.domain = this.seriesDomain; - opts.colors = this.colors.scale; - } - return opts; - } - - updateLineWidth(width): void { - this.bandwidth = width; - this.scaleLines(); - } - - updateYAxisWidth({ width }): void { - this.yAxisWidth = width + 20; - this.update(); - } - - updateXAxisHeight({ height }): void { - this.xAxisHeight = height; - this.update(); - } - - onActivate(item) { - const idx = this.activeEntries.findIndex(d => { - return d.name === item.name && d.value === item.value && d.series === item.series; - }); - if (idx > -1) { - return; - } - - this.activeEntries = [item, ...this.activeEntries]; - this.activate.emit({ value: item, entries: this.activeEntries }); - } - - onDeactivate(item) { - const idx = this.activeEntries.findIndex(d => { - return d.name === item.name && d.value === item.value && d.series === item.series; - }); - - this.activeEntries.splice(idx, 1); - this.activeEntries = [...this.activeEntries]; - - this.deactivate.emit({ value: item, entries: this.activeEntries }); - } -} diff --git a/src/app/custom-charts/combo-chart-line-pie/combo-series-vertical.component.ts b/src/app/custom-charts/combo-chart-line-pie/combo-series-vertical.component.ts deleted file mode 100644 index 3ecb93c9f..000000000 --- a/src/app/custom-charts/combo-chart-line-pie/combo-series-vertical.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Component, Input, Output, EventEmitter, OnChanges, ChangeDetectionStrategy } from '@angular/core'; - - -@Component({ - selector: 'g[ngx-combo-charts-series-vertical-2]', - template: ``, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ComboSeriesLinePieVerticalComponent implements OnChanges { - @Input() dims; - @Input() type = 'standard'; - @Input() series; - @Input() seriesLine; - @Input() xScale; - @Input() yScale; - @Input() colors; - @Input() tooltipDisabled: boolean = false; - @Input() activeEntries: any[]; - @Input() seriesName: string; - @Input() animations: boolean = true; - - @Output() select = new EventEmitter(); - @Output() activate = new EventEmitter(); - @Output() deactivate = new EventEmitter(); - @Output() bandwidth = new EventEmitter(); - - ngOnChanges(changes): void { - this.update(); - } - - update(): void { - let width; - if (this.series.length) { - width = this.xScale.bandwidth(); - this.bandwidth.emit(width); - } - - let total; - if (this.type === 'normalized') { - total = this.series.map(d => d.value).reduce((sum, d) => sum + d, 0); - } - } -} diff --git a/src/app/custom-charts/combo-chart-line-pie/index.ts b/src/app/custom-charts/combo-chart-line-pie/index.ts deleted file mode 100644 index 2a0ab4f22..000000000 --- a/src/app/custom-charts/combo-chart-line-pie/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './combo-chart.component'; -export * from './combo-series-vertical.component'; From 4eb86304a640e9c9bad5511353b0b166869c65e3 Mon Sep 17 00:00:00 2001 From: Kedi Jiang Date: Wed, 15 Nov 2023 21:19:07 -0500 Subject: [PATCH 03/15] added initial pie view, fixed bug on side bar --- src/app/app.component.html | 7 ++++--- src/app/app.component.ts | 22 ++++++++++++++++++++-- src/app/chartTypes.ts | 25 +++++++++++++++++++++---- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 7d9b37ed4..5c72205c4 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -597,6 +597,7 @@ (select)="onSelect($event)" > +
-
+
@@ -1209,7 +1209,8 @@

{{ bubbleDemoTempData | json }}
{{ barChart | json }}
{{ lineChartSeries | json }}
-
{{ lineChartSeries | json }}
+
{{ pieTempData | json }}
+
{{ dateDataWithOrWithoutRange | json }}
{{ timelineFilterBarData | json }}