Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tooltip position on PieChart Doughnut & PieChart #1936

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { isDate } from '../utils/types';
import { Color } from '../utils/color-sets';
import { ScaleType } from './types/scale-type.enum';
import { ViewDimensions } from './types/view-dimension.interface';
import { PieChartService } from '../pie-chart/pie-chart.service';

@Component({
selector: 'base-chart',
Expand All @@ -47,7 +48,8 @@ export class BaseChartComponent implements OnChanges, AfterViewInit, OnDestroy,
protected chartElement: ElementRef,
protected zone: NgZone,
protected cd: ChangeDetectorRef,
@Inject(PLATFORM_ID) public platformId: any
@Inject(PLATFORM_ID) public platformId: any,
protected pieChartSvc: PieChartService,
) {}

ngOnInit() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PieChartService } from '@swimlane/ngx-charts/pie-chart/pie-chart.service';
import { PlacementTypes } from './placement-type.enum';

const caretOffset = 7;
Expand Down Expand Up @@ -210,27 +211,50 @@ export class PositionHelper {
return { top, left };
}

/**
/**
* Position content
*
* @memberOf PositionHelper
*/
static positionContent(placement, elmDim, hostDim, spacing, alignment): any {
static positionContent(placement, elmDim, hostDim, spacing, alignment, pieChartDoughnout?, pieChartSvc?: PieChartService): any {
let top = 0;
let left = 0;

if (placement === PlacementTypes.Right) {
left = hostDim.left + hostDim.width + spacing;
top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
//TODO: Implement positioning adjustment
if (pieChartDoughnout) {
top = PositionHelper.calculateTopPosition(hostDim, pieChartSvc.radius.outerRadius, pieChartSvc.radius.innerRadius, spacing) + pieChartSvc.actuallyCentroidCoords.y - spacing * 2
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment) + pieChartSvc.actuallyCentroidCoords.x
} else {
left = hostDim.left + hostDim.width + spacing;
top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
}
} else if (placement === PlacementTypes.Left) {
left = hostDim.left - elmDim.width - spacing;
top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
//TODO: Implement positioning adjustment
if (pieChartDoughnout) {
top = PositionHelper.calculateTopPosition(hostDim, pieChartSvc.radius.outerRadius, pieChartSvc.radius.innerRadius, spacing) + pieChartSvc.actuallyCentroidCoords.y - spacing * 2
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment) + pieChartSvc.actuallyCentroidCoords.x
} else {
left = hostDim.left - elmDim.width - spacing;
top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
}
} else if (placement === PlacementTypes.Top) {
top = hostDim.top - elmDim.height - spacing;
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
if (pieChartDoughnout) {
const OFFSET_TOP = 20
top = PositionHelper.calculateTopPosition(hostDim, pieChartSvc.radius.outerRadius, pieChartSvc.radius.innerRadius, spacing) + pieChartSvc.actuallyCentroidCoords.y - OFFSET_TOP
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment) + pieChartSvc.actuallyCentroidCoords.x
} else {
top = hostDim.top - elmDim.height - spacing;
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
}
} else if (placement === PlacementTypes.Bottom) {
top = hostDim.top + hostDim.height + spacing;
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
if (pieChartDoughnout) {
const OFFSET_TOP = 40
top = PositionHelper.calculateTopPosition(hostDim, pieChartSvc.radius.outerRadius, pieChartSvc.radius.innerRadius, spacing) + pieChartSvc.actuallyCentroidCoords.y + OFFSET_TOP
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment) + pieChartSvc.actuallyCentroidCoords.x
} else {
top = hostDim.top + hostDim.height + spacing;
left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
}
}

return { top, left };
Expand Down Expand Up @@ -258,4 +282,8 @@ export class PositionHelper {

return placement;
}

static calculateTopPosition(hostDim: DOMRect, outerRadius, innerRadius, spacing): number {
return innerRadius <= 0 ? hostDim.top + hostDim.height/2 - 47 : hostDim.top + hostDim.height/2 - (outerRadius - innerRadius) - spacing
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PositionHelper, PlacementTypes } from './position';

import { StyleTypes } from './style.type';
import { isPlatformBrowser } from '@angular/common';
import { PieChartService } from '@swimlane/ngx-charts/pie-chart/pie-chart.service';

@Component({
selector: 'ngx-tooltip-content',
Expand Down Expand Up @@ -58,7 +59,7 @@ export class TooltipContentComponent implements AfterViewInit {
return clz;
}

constructor(public element: ElementRef, private renderer: Renderer2, @Inject(PLATFORM_ID) private platformId: any) {}
constructor(public element: ElementRef, private renderer: Renderer2, @Inject(PLATFORM_ID) private platformId: any, private pieChartSvc: PieChartService) {}

ngAfterViewInit(): void {
setTimeout(this.position.bind(this));
Expand All @@ -70,14 +71,26 @@ export class TooltipContentComponent implements AfterViewInit {
}

const nativeElm = this.element.nativeElement;
const hostDim = this.host.nativeElement.getBoundingClientRect();
const hostSvg = this.renderer.parentNode(this.host.nativeElement)
//TODO: Implement positioning adjustment for other placements
const isPieChart = this.renderer.parentNode(this.renderer.parentNode(hostSvg)).classList.contains('pie-chart') && (this.placement === 'bottom' || this.placement === 'top');

let hostDim

//TODO: Implement positioning adjustment for other placements
if (isPieChart) {
const hostSvg = this.renderer.parentNode(this.host.nativeElement)
hostDim = this.renderer.parentNode(hostSvg).getBoundingClientRect();
} else {
hostDim = this.host.nativeElement.getBoundingClientRect();
}

// if no dims were found, never show
if (!hostDim.height && !hostDim.width) return;

const elmDim = nativeElm.getBoundingClientRect();
this.checkFlip(hostDim, elmDim);
this.positionContent(nativeElm, hostDim, elmDim);
this.positionContent(nativeElm, hostDim, elmDim, isPieChart);

if (this.showCaret) {
this.positionCaret(hostDim, elmDim);
Expand All @@ -87,12 +100,12 @@ export class TooltipContentComponent implements AfterViewInit {
setTimeout(() => this.renderer.addClass(nativeElm, 'animate'), 1);
}

positionContent(nativeElm: HTMLElement, hostDim: DOMRect, elmDim: DOMRect): void {
const { top, left } = PositionHelper.positionContent(this.placement, elmDim, hostDim, this.spacing, this.alignment);

this.renderer.setStyle(nativeElm, 'top', `${top}px`);
this.renderer.setStyle(nativeElm, 'left', `${left}px`);
}
positionContent(nativeElm: HTMLElement, hostDim: DOMRect, elmDim: DOMRect, isPieChart: boolean ): void {
const { top, left } = PositionHelper.positionContent(this.placement, elmDim, hostDim, this.spacing, this.alignment, isPieChart, this.pieChartSvc);
this.renderer.setStyle(nativeElm, 'top', `${top}px`);
this.renderer.setStyle(nativeElm, 'left', `${left}px`);
}

positionCaret(hostDim: DOMRect, elmDim: DOMRect): void {
const caretElm = this.caretElm.nativeElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { arc } from 'd3-shape';
import { id } from '../utils/id';
import { DataItem } from '../models/chart-data.model';
import { BarOrientation } from '../common/types/bar-orientation.enum';
import { PieChartService } from './pie-chart.service';

@Component({
selector: 'g[ngx-charts-pie-arc]',
Expand Down Expand Up @@ -57,7 +58,7 @@ export class PieArcComponent implements OnChanges {
@Output() activate = new EventEmitter();
@Output() deactivate = new EventEmitter();
@Output() dblclick = new EventEmitter();

barOrientation = BarOrientation;

element: HTMLElement;
Expand All @@ -69,7 +70,7 @@ export class PieArcComponent implements OnChanges {

private _timeout;

constructor(element: ElementRef) {
constructor(element: ElementRef, private PieChartSvg: PieChartService) {
this.element = element.nativeElement;
}

Expand All @@ -90,6 +91,8 @@ export class PieArcComponent implements OnChanges {
this.startOpacity = 0.5;
this.radialGradientId = 'linearGrad' + id().toString();
this.gradientFill = `url(#${this.radialGradientId})`;
this.PieChartSvg.newCoords(this.calculateCentroid(calc))
this.PieChartSvg.setRadius(this.outerRadius, this.innerRadius)

if (this.animate) {
if (this.initialized) {
Expand All @@ -112,6 +115,12 @@ export class PieArcComponent implements OnChanges {
return arc().innerRadius(this.innerRadius).outerRadius(outerRadius).cornerRadius(this.cornerRadius);
}

calculateCentroid(arc): any {
//Example: https://d3js.org/d3-shape/arc#arc_centroid
const [centroidX, centroidY] = arc.centroid({innerRadius: this.innerRadius , outerRadius: this.outerRadius , endAngle: this.endAngle , startAngle: this.startAngle});
return {x: centroidX, y: centroidY}
}

loadAnimation(): void {
const node = select(this.element)
.selectAll('.arc')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ import {
EventEmitter,
ChangeDetectionStrategy,
ContentChild,
TemplateRef
TemplateRef,
ElementRef,
NgZone,
ChangeDetectorRef,
PLATFORM_ID,
Inject,
Renderer2
} from '@angular/core';
import { calculateViewDimensions } from '../common/view-dimensions.helper';
import { ColorHelper } from '../common/color.helper';
import { BaseChartComponent } from '../common/base-chart.component';
import { DataItem } from '../models/chart-data.model';
import { PieChartService } from './pie-chart.service';
import { LegendOptions, LegendPosition } from '../common/types/legend.model';
import { ViewDimensions } from '../common/types/view-dimension.interface';
import { ScaleType } from '../common/types/scale-type.enum';
Expand Down Expand Up @@ -83,6 +90,15 @@ export class PieChartComponent extends BaseChartComponent {

@ContentChild('tooltipTemplate') tooltipTemplate: TemplateRef<any>;

constructor( protected chartElement: ElementRef,
protected zone: NgZone,
protected cd: ChangeDetectorRef,
protected renderer: Renderer2,
protected pieChartSvc: PieChartService,
@Inject(PLATFORM_ID) public platformId: any) {
super(chartElement, zone, cd, renderer, pieChartSvc);
}

translation: string;
outerRadius: number;
innerRadius: number;
Expand All @@ -94,7 +110,7 @@ export class PieChartComponent extends BaseChartComponent {

update(): void {
super.update();

if (this.labels && this.hasNoOptionalMarginsSet()) {
this.margins = [30, 80, 30, 80];
} else if (!this.labels && this.hasNoOptionalMarginsSet()) {
Expand Down Expand Up @@ -177,6 +193,10 @@ export class PieChartComponent extends BaseChartComponent {
}

this.activeEntries = [item, ...this.activeEntries];
const selected = this.results.findIndex(d => {
return d === this.activeEntries[0];
});
this.pieChartSvc.setSelectedObject(selected)
this.activate.emit({ value: item, entries: this.activeEntries });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PieChartComponent } from './pie-chart.component';
import { PieGridComponent } from './pie-grid.component';
import { PieGridSeriesComponent } from './pie-grid-series.component';
import { PieSeriesComponent } from './pie-series.component';
import { PieChartService } from './pie-chart.service';

@NgModule({
imports: [ChartCommonModule],
Expand All @@ -27,6 +28,7 @@ import { PieSeriesComponent } from './pie-series.component';
PieGridComponent,
PieGridSeriesComponent,
PieSeriesComponent
]
],
providers: [PieChartService],
})
export class PieChartModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';

@Injectable()
export class PieChartService {
centroidCoords = [];
idxSelectedObject = 0;
idxCoords = 0;
innerRadius = 0
outerRadius = 0

newCoords(newCoords) {
if (!this.centroidCoords.some(coord => coord.x === newCoords.x && coord.y === newCoords.y)) {
this.centroidCoords.push(newCoords);
}
this.idxCoords = this.getIdxCoords(newCoords)
}

clearCoords() {
this.centroidCoords = [];
}

getIdxCoords(coords){
return this.centroidCoords.findIndex(d => {
return d.x === coords.x && d.y === coords.y
});
}

setSelectedObject(objectSelected) {
this.idxSelectedObject = objectSelected;
}

setRadius(outerRadius, innerRadius){
this.innerRadius = innerRadius
this.outerRadius = outerRadius
}

get radius() : any {
return { innerRadius: this.innerRadius, outerRadius: this.outerRadius }
}

get idxSelected() : number {
return this.idxSelectedObject
}

get actuallyCentroidCoords(): {x: number, y: number} {
return this.centroidCoords[this.idxCoords]
}

}