Advertisement
Guest User

Untitled

a guest
Feb 21st, 2017
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.02 KB | None | 0 0
  1. import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core';
  2. import d3 from '../d3';
  3.  
  4. import { BaseChartComponent } from '../common/base-chart.component';
  5. import { calculateViewDimensions, ViewDimensions } from '../common/view-dimensions.helper';
  6. import { ColorHelper } from '../common/color.helper';
  7. import { getScaleType, getDomain, getScale } from './bubble-chart.utils';
  8.  
  9. @Component({
  10. selector: 'ngx-charts-bubble-chart',
  11. template: `
  12. <ngx-charts-chart
  13. [view]="[width, height]"
  14. [showLegend]="legend"
  15. [activeEntries]="activeEntries"
  16. [legendOptions]="legendOptions"
  17. (legendLabelClick)="onClick($event)"
  18. (legendLabelActivate)="onActivate($event)"
  19. (legendLabelDeactivate)="onDeactivate($event)">
  20.  
  21. <svg:defs>
  22. <svg:clipPath [attr.id]="clipPathId">
  23. <svg:rect
  24. [attr.width]="dims.width + 10"
  25. [attr.height]="dims.height + 10"
  26. [attr.transform]="'translate(-5, -5)'"/>
  27. </svg:clipPath>
  28. </svg:defs>
  29.  
  30. <svg:g [attr.transform]="transform" class="bubble-chart chart">
  31.  
  32. <svg:g ngx-charts-x-axis
  33. *ngIf="xAxis"
  34. [showGridLines]="showGridLines"
  35. [dims]="dims"
  36. [xScale]="xScale"
  37. [showLabel]="showXAxisLabel"
  38. [labelText]="xAxisLabel"
  39. [tickFormatting]="xAxisTickFormatting"
  40. (dimensionsChanged)="updateXAxisHeight($event)"/>
  41.  
  42. <svg:g ngx-charts-y-axis
  43. *ngIf="yAxis"
  44. [showGridLines]="showGridLines"
  45. [yScale]="yScale"
  46. [dims]="dims"
  47. [showLabel]="showYAxisLabel"
  48. [labelText]="yAxisLabel"
  49. [tickFormatting]="yAxisTickFormatting"
  50. (dimensionsChanged)="updateYAxisWidth($event)"/>
  51.  
  52. <svg:rect
  53. class="bubble-chart-area"
  54. x="0"
  55. y="0"
  56. [attr.width]="dims.width"
  57. [attr.height]="dims.height"
  58. style="fill: rgb(255, 0, 0); opacity: 0; cursor: 'auto';"
  59. (mouseenter)="deactivateAll()"
  60. />
  61.  
  62. <svg:g *ngFor="let series of data">
  63. <svg:g ngx-charts-bubble-series
  64. [xScale]="xScale"
  65. [yScale]="yScale"
  66. [rScale]="rScale"
  67. [xScaleType]="xScaleType"
  68. [yScaleType]="yScaleType"
  69. [xAxisLabel]="xAxisLabel"
  70. [yAxisLabel]="yAxisLabel"
  71. [colors]="colors"
  72. [data]="series"
  73. [activeEntries]="activeEntries"
  74. (select)="onClick($event, series)"
  75. (activate)="onActivate($event)"
  76. (deactivate)="onDeactivate($event)" />
  77. </svg:g>
  78.  
  79. </svg:g>
  80. </ngx-charts-chart>`
  81. })
  82. export class BubbleChartComponent extends BaseChartComponent {
  83. @Input() view: number[] = [400, 400];
  84.  
  85. @Input() results;
  86. @Input() showGridLines: boolean = true;
  87. @Input() legend = false;
  88. @Input() xAxis: boolean = true;
  89. @Input() yAxis: boolean = true;
  90. @Input() showXAxisLabel: boolean;
  91. @Input() showYAxisLabel: boolean;
  92. @Input() xAxisLabel: string;
  93. @Input() yAxisLabel: string;
  94. @Input() xAxisTickFormatting: any;
  95. @Input() yAxisTickFormatting: any;
  96. @Input() roundDomains: boolean = false;
  97. @Input() maxRadius = 10;
  98. @Input() minRadius = 3;
  99. @Input() autoScale: boolean;
  100. @Input() schemeType = 'ordinal';
  101. @Input() legendPosition: string = 'right';
  102.  
  103. @Output() activate: EventEmitter<any> = new EventEmitter();
  104. @Output() deactivate: EventEmitter<any> = new EventEmitter();
  105.  
  106. dims: ViewDimensions;
  107. colors: ColorHelper;
  108. scaleType = 'linear';
  109. margin = [10, 20, 10, 20];
  110. data: any;
  111.  
  112. legendOptions: any;
  113. transform: string;
  114.  
  115. seriesDomain: any[];
  116. xDomain: any[];
  117. yDomain: any[];
  118. rDomain: number[];
  119.  
  120. xScaleType: string;
  121. yScaleType: string;
  122.  
  123. yScale: any;
  124. xScale: any;
  125. rScale: any;
  126.  
  127. xAxisHeight: number = 0;
  128. yAxisWidth: number = 0;
  129.  
  130. activeEntries: any[] = [];
  131.  
  132. update(): void {
  133. super.update();
  134.  
  135. this.zone.run(() => {
  136. this.dims = calculateViewDimensions({
  137. width: this.width,
  138. height: this.height,
  139. margins: this.margin,
  140. showXAxis: this.xAxis,
  141. showYAxis: this.yAxis,
  142. xAxisHeight: this.xAxisHeight,
  143. yAxisWidth: this.yAxisWidth,
  144. showXLabel: this.showXAxisLabel,
  145. showYLabel: this.showYAxisLabel,
  146. showLegend: this.legend,
  147. legendType: this.schemeType
  148. });
  149.  
  150. this.seriesDomain = this.results.map(d => d.name);
  151. this.rDomain = this.getRDomain();
  152. this.xDomain = this.getXDomain();
  153. this.yDomain = this.getYDomain();
  154.  
  155. this.transform = `translate(${ this.dims.xOffset },${ this.margin[0] })`;
  156.  
  157. const colorDomain = this.schemeType === 'ordinal' ? this.seriesDomain : this.rDomain;
  158. this.colors = new ColorHelper(this.scheme, this.schemeType, colorDomain, this.customColors);
  159.  
  160. this.data = this.results;
  161.  
  162. this.rScale = this.getRScale(this.rDomain, [this.minRadius, this.maxRadius]);
  163. this.xScale = this.getXScale(this.xDomain, this.dims.width - this.maxRadius * 2);
  164. this.yScale = this.getYScale(this.yDomain, this.dims.height - this.maxRadius);
  165.  
  166. this.legendOptions = this.getLegendOptions();
  167. });
  168. }
  169.  
  170. @HostListener('mouseleave')
  171. hideCircles(): void {
  172. this.deactivateAll();
  173. }
  174.  
  175. onClick(data, series): void {
  176. if (series) {
  177. data.series = series.name;
  178. }
  179. this.select.emit(data);
  180. }
  181.  
  182. getYScale(domain, height): any {
  183. return getScale(domain, [height, this.maxRadius], this.yScaleType, this.roundDomains);
  184. }
  185.  
  186. getXScale(domain, width): any {
  187. return getScale(domain, [this.maxRadius, width], this.xScaleType, this.roundDomains);
  188. }
  189.  
  190. getRScale(domain, range): any {
  191. const scale = d3.scaleLinear()
  192. .range(range)
  193. .domain(domain);
  194.  
  195. return this.roundDomains ? scale.nice() : scale;
  196. }
  197.  
  198. getLegendOptions(): any {
  199. const opts = {
  200. scaleType: this.schemeType,
  201. colors: undefined,
  202. domain: [],
  203. position: this.legendPosition
  204. };
  205.  
  206. if (opts.scaleType === 'ordinal') {
  207. opts.domain = this.seriesDomain;
  208. opts.colors = this.colors;
  209. } else {
  210. opts.domain = this.rDomain;
  211. opts.colors = this.colors.scale;
  212. }
  213.  
  214. return opts;
  215. }
  216.  
  217. getXDomain(): any[] {
  218. const values = [];
  219.  
  220. for (const results of this.results) {
  221. for (const d of results.series){
  222. if (!values.includes(d.x)) {
  223. values.push(d.x);
  224. }
  225. }
  226. }
  227.  
  228. this.xScaleType = getScaleType(values);
  229. return getDomain(values, this.xScaleType, this.autoScale);
  230. }
  231.  
  232. getYDomain(): any[] {
  233. const values = [];
  234.  
  235. for (const results of this.results) {
  236. for (const d of results.series){
  237. if (!values.includes(d.y)) {
  238. values.push(d.y);
  239. }
  240. }
  241. }
  242.  
  243. this.yScaleType = getScaleType(values);
  244. return getDomain(values, this.yScaleType, this.autoScale);
  245. }
  246.  
  247. getRDomain(): number[] {
  248. let min = Infinity;
  249. let max = -Infinity;
  250.  
  251. for (const results of this.results) {
  252. for (const d of results.series){
  253. const value = Number(d.r) || 1;
  254. min = Math.min(min, value);
  255. max = Math.max(max, value);
  256. }
  257. }
  258.  
  259. return [min, max];
  260. }
  261.  
  262. updateYAxisWidth({ width }): void {
  263. this.yAxisWidth = width;
  264. this.update();
  265. }
  266.  
  267. updateXAxisHeight({ height }): void {
  268. this.xAxisHeight = height;
  269. this.update();
  270. }
  271.  
  272. onActivate(item): void {
  273. const idx = this.activeEntries.findIndex(d => {
  274. return d.name === item.name;
  275. });
  276. if (idx > -1) {
  277. return;
  278. }
  279.  
  280. this.activeEntries = [ item, ...this.activeEntries ];
  281. this.activate.emit({ value: item, entries: this.activeEntries });
  282. }
  283.  
  284. onDeactivate(item): void {
  285. const idx = this.activeEntries.findIndex(d => {
  286. return d.name === item.name;
  287. });
  288.  
  289. this.activeEntries.splice(idx, 1);
  290. this.activeEntries = [...this.activeEntries];
  291.  
  292. this.deactivate.emit({ value: item, entries: this.activeEntries });
  293. }
  294.  
  295. deactivateAll() {
  296. this.activeEntries = [...this.activeEntries];
  297. for (const entry of this.activeEntries) {
  298. this.deactivate.emit({ value: entry, entries: [] });
  299. }
  300. this.activeEntries = [];
  301. }
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement