UNPKG

539 kBJavaScriptView Raw
1import { Injectable, ApplicationRef, ComponentFactoryResolver, Injector, Component, ViewEncapsulation, ElementRef, Renderer2, Inject, PLATFORM_ID, Input, ViewChild, HostBinding, HostListener, EventEmitter, ChangeDetectionStrategy, Output, Directive, NgZone, ChangeDetectorRef, NgModule, ViewContainerRef, ContentChild } from '@angular/core';
2import { isPlatformBrowser, isPlatformServer, CommonModule } from '@angular/common';
3import { trigger, transition, style, animate } from '@angular/animations';
4import { DomPortalOutlet, ComponentPortal } from '@angular/cdk/portal';
5import { __decorate } from 'tslib';
6import { fromEvent } from 'rxjs';
7import { debounceTime } from 'rxjs/operators';
8import { select } from 'd3-selection';
9import { brushX } from 'd3-brush';
10import { scaleTime, scaleLinear, scalePoint, scaleOrdinal, scaleQuantile, scaleBand } from 'd3-scale';
11import { curveLinear, area, line, curveCardinalClosed, lineRadial, arc, pie } from 'd3-shape';
12import { range, min, max, quantile } from 'd3-array';
13import { interpolate } from 'd3-interpolate';
14import { easeSinInOut } from 'd3-ease';
15import cloneDeep from 'clone-deep';
16import { format } from 'd3-format';
17import * as d3_color from 'd3-color';
18import { treemap, stratify } from 'd3-hierarchy';
19import { timeFormat } from 'd3-time-format';
20
21function isViewContainerRef(x) {
22 return x.element;
23}
24/**
25 * Injection service is a helper to append components
26 * dynamically to a known location in the DOM, most
27 * noteably for dialogs/tooltips appending to body.
28 *
29 * @export
30 */
31class InjectionService {
32 constructor(applicationRef, componentFactoryResolver, injector) {
33 this.applicationRef = applicationRef;
34 this.componentFactoryResolver = componentFactoryResolver;
35 this.injector = injector;
36 }
37 /**
38 * Sets a default global root view container. This is useful for
39 * things like ngUpgrade that doesn't have a ApplicationRef root.
40 *
41 * @param container
42 */
43 static setGlobalRootViewContainer(container) {
44 InjectionService.globalRootViewContainer = container;
45 }
46 /**
47 * Gets the root view container to inject the component to.
48 *
49 * @memberOf InjectionService
50 */
51 getRootViewContainer() {
52 if (this._container)
53 return this._container;
54 if (InjectionService.globalRootViewContainer)
55 return InjectionService.globalRootViewContainer;
56 if (this.applicationRef.components.length)
57 return this.applicationRef.components[0];
58 throw new Error('View Container not found! ngUpgrade needs to manually set this via setRootViewContainer or setGlobalRootViewContainer.');
59 }
60 /**
61 * Overrides the default root view container. This is useful for
62 * things like ngUpgrade that doesn't have a ApplicationRef root.
63 *
64 * @param container
65 *
66 * @memberOf InjectionService
67 */
68 setRootViewContainer(container) {
69 this._container = container;
70 }
71 /**
72 * Gets the html element for a component ref.
73 *
74 * @param componentRef
75 *
76 * @memberOf InjectionService
77 */
78 getComponentRootNode(component) {
79 if (isViewContainerRef(component)) {
80 return component.element.nativeElement;
81 }
82 if (component.hostView && component.hostView.rootNodes.length > 0) {
83 return component.hostView.rootNodes[0];
84 }
85 // the top most component root node has no `hostView`
86 return component.location.nativeElement;
87 }
88 /**
89 * Gets the root component container html element.
90 *
91 * @memberOf InjectionService
92 */
93 getRootViewContainerNode(component) {
94 return this.getComponentRootNode(component);
95 }
96 /**
97 * Projects the bindings onto the component
98 *
99 * @param component
100 * @param options
101 *
102 * @memberOf InjectionService
103 */
104 projectComponentBindings(component, bindings) {
105 if (bindings) {
106 if (bindings.inputs !== undefined) {
107 const bindingKeys = Object.getOwnPropertyNames(bindings.inputs);
108 for (const bindingName of bindingKeys) {
109 component.instance[bindingName] = bindings.inputs[bindingName];
110 }
111 }
112 if (bindings.outputs !== undefined) {
113 const eventKeys = Object.getOwnPropertyNames(bindings.outputs);
114 for (const eventName of eventKeys) {
115 component.instance[eventName] = bindings.outputs[eventName];
116 }
117 }
118 }
119 return component;
120 }
121 /**
122 * Appends a component to a adjacent location
123 *
124 * @param componentClass
125 * @param [options={}]
126 * @param [location]
127 *
128 * @memberOf InjectionService
129 */
130 appendComponent(componentClass, bindings = {}, location) {
131 if (!location)
132 location = this.getRootViewContainer();
133 const appendLocation = this.getComponentRootNode(location);
134 const portalHost = new DomPortalOutlet(appendLocation, this.componentFactoryResolver, this.applicationRef, this.injector);
135 const portal = new ComponentPortal(componentClass);
136 const componentRef = portalHost.attach(portal);
137 this.projectComponentBindings(componentRef, bindings);
138 return componentRef;
139 }
140}
141InjectionService.globalRootViewContainer = null;
142InjectionService.decorators = [
143 { type: Injectable }
144];
145InjectionService.ctorParameters = () => [
146 { type: ApplicationRef },
147 { type: ComponentFactoryResolver },
148 { type: Injector }
149];
150
151/**
152 * Throttle a function
153 *
154 */
155function throttle(func, wait, options) {
156 options = options || {};
157 let context;
158 let args;
159 let result;
160 let timeout = null;
161 let previous = 0;
162 function later() {
163 previous = options.leading === false ? 0 : +new Date();
164 timeout = null;
165 result = func.apply(context, args);
166 }
167 return function () {
168 const now = +new Date();
169 if (!previous && options.leading === false) {
170 previous = now;
171 }
172 const remaining = wait - (now - previous);
173 context = this;
174 args = arguments;
175 if (remaining <= 0) {
176 clearTimeout(timeout);
177 timeout = null;
178 previous = now;
179 result = func.apply(context, args);
180 }
181 else if (!timeout && options.trailing !== false) {
182 timeout = setTimeout(later, remaining);
183 }
184 return result;
185 };
186}
187/**
188 * Throttle decorator
189 *
190 * class MyClass {
191 * throttleable(10)
192 * myFn() { ... }
193 * }
194 */
195function throttleable(duration, options) {
196 return function innerDecorator(target, key, descriptor) {
197 return {
198 configurable: true,
199 enumerable: descriptor.enumerable,
200 get: function getter() {
201 Object.defineProperty(this, key, {
202 configurable: true,
203 enumerable: descriptor.enumerable,
204 value: throttle(descriptor.value, duration, options)
205 });
206 return this[key];
207 }
208 };
209 };
210}
211
212var PlacementTypes;
213(function (PlacementTypes) {
214 PlacementTypes["Top"] = "top";
215 PlacementTypes["Bottom"] = "bottom";
216 PlacementTypes["Left"] = "left";
217 PlacementTypes["Right"] = "right";
218 PlacementTypes["Center"] = "center";
219})(PlacementTypes || (PlacementTypes = {}));
220
221const caretOffset = 7;
222function verticalPosition(elDimensions, popoverDimensions, alignment) {
223 if (alignment === PlacementTypes.Top) {
224 return elDimensions.top - caretOffset;
225 }
226 if (alignment === PlacementTypes.Bottom) {
227 return elDimensions.top + elDimensions.height - popoverDimensions.height + caretOffset;
228 }
229 if (alignment === PlacementTypes.Center) {
230 return elDimensions.top + elDimensions.height / 2 - popoverDimensions.height / 2;
231 }
232 return undefined;
233}
234function horizontalPosition(elDimensions, popoverDimensions, alignment) {
235 if (alignment === PlacementTypes.Left) {
236 return elDimensions.left - caretOffset;
237 }
238 if (alignment === PlacementTypes.Right) {
239 return elDimensions.left + elDimensions.width - popoverDimensions.width + caretOffset;
240 }
241 if (alignment === PlacementTypes.Center) {
242 return elDimensions.left + elDimensions.width / 2 - popoverDimensions.width / 2;
243 }
244 return undefined;
245}
246/**
247 * Position helper for the popover directive.
248 *
249 * @export
250 */
251class PositionHelper {
252 /**
253 * Calculate vertical alignment position
254 *
255 * @memberOf PositionHelper
256 */
257 static calculateVerticalAlignment(elDimensions, popoverDimensions, alignment) {
258 let result = verticalPosition(elDimensions, popoverDimensions, alignment);
259 if (result + popoverDimensions.height > window.innerHeight) {
260 result = window.innerHeight - popoverDimensions.height;
261 }
262 return result;
263 }
264 /**
265 * Calculate vertical caret position
266 *
267 * @memberOf PositionHelper
268 */
269 static calculateVerticalCaret(elDimensions, popoverDimensions, caretDimensions, alignment) {
270 let result;
271 if (alignment === PlacementTypes.Top) {
272 result = elDimensions.height / 2 - caretDimensions.height / 2 + caretOffset;
273 }
274 if (alignment === PlacementTypes.Bottom) {
275 result = popoverDimensions.height - elDimensions.height / 2 - caretDimensions.height / 2 - caretOffset;
276 }
277 if (alignment === PlacementTypes.Center) {
278 result = popoverDimensions.height / 2 - caretDimensions.height / 2;
279 }
280 const popoverPosition = verticalPosition(elDimensions, popoverDimensions, alignment);
281 if (popoverPosition + popoverDimensions.height > window.innerHeight) {
282 result += popoverPosition + popoverDimensions.height - window.innerHeight;
283 }
284 return result;
285 }
286 /**
287 * Calculate horz alignment position
288 *
289 * @memberOf PositionHelper
290 */
291 static calculateHorizontalAlignment(elDimensions, popoverDimensions, alignment) {
292 let result = horizontalPosition(elDimensions, popoverDimensions, alignment);
293 if (result + popoverDimensions.width > window.innerWidth) {
294 result = window.innerWidth - popoverDimensions.width;
295 }
296 return result;
297 }
298 /**
299 * Calculate horz caret position
300 *
301 * @memberOf PositionHelper
302 */
303 static calculateHorizontalCaret(elDimensions, popoverDimensions, caretDimensions, alignment) {
304 let result;
305 if (alignment === PlacementTypes.Left) {
306 result = elDimensions.width / 2 - caretDimensions.width / 2 + caretOffset;
307 }
308 if (alignment === PlacementTypes.Right) {
309 result = popoverDimensions.width - elDimensions.width / 2 - caretDimensions.width / 2 - caretOffset;
310 }
311 if (alignment === PlacementTypes.Center) {
312 result = popoverDimensions.width / 2 - caretDimensions.width / 2;
313 }
314 const popoverPosition = horizontalPosition(elDimensions, popoverDimensions, alignment);
315 if (popoverPosition + popoverDimensions.width > window.innerWidth) {
316 result += popoverPosition + popoverDimensions.width - window.innerWidth;
317 }
318 return result;
319 }
320 /**
321 * Checks if the element's position should be flipped
322 *
323 * @memberOf PositionHelper
324 */
325 static shouldFlip(elDimensions, popoverDimensions, placement, spacing) {
326 let flip = false;
327 if (placement === PlacementTypes.Right) {
328 if (elDimensions.left + elDimensions.width + popoverDimensions.width + spacing > window.innerWidth) {
329 flip = true;
330 }
331 }
332 if (placement === PlacementTypes.Left) {
333 if (elDimensions.left - popoverDimensions.width - spacing < 0) {
334 flip = true;
335 }
336 }
337 if (placement === PlacementTypes.Top) {
338 if (elDimensions.top - popoverDimensions.height - spacing < 0) {
339 flip = true;
340 }
341 }
342 if (placement === PlacementTypes.Bottom) {
343 if (elDimensions.top + elDimensions.height + popoverDimensions.height + spacing > window.innerHeight) {
344 flip = true;
345 }
346 }
347 return flip;
348 }
349 /**
350 * Position caret
351 *
352 * @memberOf PositionHelper
353 */
354 static positionCaret(placement, elmDim, hostDim, caretDimensions, alignment) {
355 let top = 0;
356 let left = 0;
357 if (placement === PlacementTypes.Right) {
358 left = -7;
359 top = PositionHelper.calculateVerticalCaret(hostDim, elmDim, caretDimensions, alignment);
360 }
361 else if (placement === PlacementTypes.Left) {
362 left = elmDim.width;
363 top = PositionHelper.calculateVerticalCaret(hostDim, elmDim, caretDimensions, alignment);
364 }
365 else if (placement === PlacementTypes.Top) {
366 top = elmDim.height;
367 left = PositionHelper.calculateHorizontalCaret(hostDim, elmDim, caretDimensions, alignment);
368 }
369 else if (placement === PlacementTypes.Bottom) {
370 top = -7;
371 left = PositionHelper.calculateHorizontalCaret(hostDim, elmDim, caretDimensions, alignment);
372 }
373 return { top, left };
374 }
375 /**
376 * Position content
377 *
378 * @memberOf PositionHelper
379 */
380 static positionContent(placement, elmDim, hostDim, spacing, alignment) {
381 let top = 0;
382 let left = 0;
383 if (placement === PlacementTypes.Right) {
384 left = hostDim.left + hostDim.width + spacing;
385 top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
386 }
387 else if (placement === PlacementTypes.Left) {
388 left = hostDim.left - elmDim.width - spacing;
389 top = PositionHelper.calculateVerticalAlignment(hostDim, elmDim, alignment);
390 }
391 else if (placement === PlacementTypes.Top) {
392 top = hostDim.top - elmDim.height - spacing;
393 left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
394 }
395 else if (placement === PlacementTypes.Bottom) {
396 top = hostDim.top + hostDim.height + spacing;
397 left = PositionHelper.calculateHorizontalAlignment(hostDim, elmDim, alignment);
398 }
399 return { top, left };
400 }
401 /**
402 * Determine placement based on flip
403 *
404 * @memberOf PositionHelper
405 */
406 static determinePlacement(placement, elmDim, hostDim, spacing) {
407 const shouldFlip = PositionHelper.shouldFlip(hostDim, elmDim, placement, spacing);
408 if (shouldFlip) {
409 if (placement === PlacementTypes.Right) {
410 return PlacementTypes.Left;
411 }
412 else if (placement === PlacementTypes.Left) {
413 return PlacementTypes.Right;
414 }
415 else if (placement === PlacementTypes.Top) {
416 return PlacementTypes.Bottom;
417 }
418 else if (placement === PlacementTypes.Bottom) {
419 return PlacementTypes.Top;
420 }
421 }
422 return placement;
423 }
424}
425
426class TooltipContentComponent {
427 constructor(element, renderer, platformId) {
428 this.element = element;
429 this.renderer = renderer;
430 this.platformId = platformId;
431 }
432 get cssClasses() {
433 let clz = 'ngx-charts-tooltip-content';
434 clz += ` position-${this.placement}`;
435 clz += ` type-${this.type}`;
436 clz += ` ${this.cssClass}`;
437 return clz;
438 }
439 ngAfterViewInit() {
440 setTimeout(this.position.bind(this));
441 }
442 position() {
443 if (!isPlatformBrowser(this.platformId)) {
444 return;
445 }
446 const nativeElm = this.element.nativeElement;
447 const hostDim = this.host.nativeElement.getBoundingClientRect();
448 // if no dims were found, never show
449 if (!hostDim.height && !hostDim.width)
450 return;
451 const elmDim = nativeElm.getBoundingClientRect();
452 this.checkFlip(hostDim, elmDim);
453 this.positionContent(nativeElm, hostDim, elmDim);
454 if (this.showCaret) {
455 this.positionCaret(hostDim, elmDim);
456 }
457 // animate its entry
458 setTimeout(() => this.renderer.addClass(nativeElm, 'animate'), 1);
459 }
460 positionContent(nativeElm, hostDim, elmDim) {
461 const { top, left } = PositionHelper.positionContent(this.placement, elmDim, hostDim, this.spacing, this.alignment);
462 this.renderer.setStyle(nativeElm, 'top', `${top}px`);
463 this.renderer.setStyle(nativeElm, 'left', `${left}px`);
464 }
465 positionCaret(hostDim, elmDim) {
466 const caretElm = this.caretElm.nativeElement;
467 const caretDimensions = caretElm.getBoundingClientRect();
468 const { top, left } = PositionHelper.positionCaret(this.placement, elmDim, hostDim, caretDimensions, this.alignment);
469 this.renderer.setStyle(caretElm, 'top', `${top}px`);
470 this.renderer.setStyle(caretElm, 'left', `${left}px`);
471 }
472 checkFlip(hostDim, elmDim) {
473 this.placement = PositionHelper.determinePlacement(this.placement, elmDim, hostDim, this.spacing);
474 }
475 onWindowResize() {
476 this.position();
477 }
478}
479TooltipContentComponent.decorators = [
480 { type: Component, args: [{
481 selector: 'ngx-tooltip-content',
482 template: `
483 <div>
484 <span #caretElm [hidden]="!showCaret" class="tooltip-caret position-{{ this.placement }}"> </span>
485 <div class="tooltip-content">
486 <span *ngIf="!title">
487 <ng-template [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{ model: context }"> </ng-template>
488 </span>
489 <span *ngIf="title" [innerHTML]="title"> </span>
490 </div>
491 </div>
492 `,
493 encapsulation: ViewEncapsulation.None,
494 styles: [".ngx-charts-tooltip-content{position:fixed;border-radius:3px;z-index:5000;display:block;font-weight:normal;opacity:0;pointer-events:none!important}.ngx-charts-tooltip-content.type-popover{background:#fff;color:#060709;border:1px solid #72809b;box-shadow:0 1px 3px #0003,0 1px 1px #00000024,0 2px 1px -1px #0000001f;font-size:13px;padding:4px}.ngx-charts-tooltip-content.type-popover .tooltip-caret{position:absolute;z-index:5001;width:0;height:0}.ngx-charts-tooltip-content.type-popover .tooltip-caret.position-left{border-top:7px solid transparent;border-bottom:7px solid transparent;border-left:7px solid #fff}.ngx-charts-tooltip-content.type-popover .tooltip-caret.position-top{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #fff}.ngx-charts-tooltip-content.type-popover .tooltip-caret.position-right{border-top:7px solid transparent;border-bottom:7px solid transparent;border-right:7px solid #fff}.ngx-charts-tooltip-content.type-popover .tooltip-caret.position-bottom{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #fff}.ngx-charts-tooltip-content.type-tooltip{color:#fff;background:rgba(0,0,0,.75);font-size:12px;padding:0 10px;text-align:center;pointer-events:auto}.ngx-charts-tooltip-content.type-tooltip .tooltip-caret.position-left{border-top:7px solid transparent;border-bottom:7px solid transparent;border-left:7px solid rgba(0,0,0,.75)}.ngx-charts-tooltip-content.type-tooltip .tooltip-caret.position-top{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid rgba(0,0,0,.75)}.ngx-charts-tooltip-content.type-tooltip .tooltip-caret.position-right{border-top:7px solid transparent;border-bottom:7px solid transparent;border-right:7px solid rgba(0,0,0,.75)}.ngx-charts-tooltip-content.type-tooltip .tooltip-caret.position-bottom{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid rgba(0,0,0,.75)}.ngx-charts-tooltip-content .tooltip-label{display:block;line-height:1em;padding:8px 5px 5px;font-size:1em}.ngx-charts-tooltip-content .tooltip-val{display:block;font-size:1.3em;line-height:1em;padding:0 5px 8px}.ngx-charts-tooltip-content .tooltip-caret{position:absolute;z-index:5001;width:0;height:0}.ngx-charts-tooltip-content.position-right{transform:translate(10px)}.ngx-charts-tooltip-content.position-left{transform:translate(-10px)}.ngx-charts-tooltip-content.position-top{transform:translateY(-10px)}.ngx-charts-tooltip-content.position-bottom{transform:translateY(10px)}.ngx-charts-tooltip-content.animate{opacity:1;transition:opacity .3s,transform .3s;transform:translate(0);pointer-events:auto}.area-tooltip-container{padding:5px 0;pointer-events:none}.tooltip-item{text-align:left;line-height:1.2em;padding:5px 0}.tooltip-item .tooltip-item-color{display:inline-block;height:12px;width:12px;margin-right:5px;color:#5b646b;border-radius:3px}\n"]
495 },] }
496];
497TooltipContentComponent.ctorParameters = () => [
498 { type: ElementRef },
499 { type: Renderer2 },
500 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
501];
502TooltipContentComponent.propDecorators = {
503 host: [{ type: Input }],
504 showCaret: [{ type: Input }],
505 type: [{ type: Input }],
506 placement: [{ type: Input }],
507 alignment: [{ type: Input }],
508 spacing: [{ type: Input }],
509 cssClass: [{ type: Input }],
510 title: [{ type: Input }],
511 template: [{ type: Input }],
512 context: [{ type: Input }],
513 caretElm: [{ type: ViewChild, args: ['caretElm',] }],
514 cssClasses: [{ type: HostBinding, args: ['class',] }],
515 onWindowResize: [{ type: HostListener, args: ['window:resize',] }]
516};
517__decorate([
518 throttleable(100)
519], TooltipContentComponent.prototype, "onWindowResize", null);
520
521class InjectionRegisteryService {
522 constructor(injectionService) {
523 this.injectionService = injectionService;
524 this.defaults = {};
525 this.components = new Map();
526 }
527 getByType(type = this.type) {
528 return this.components.get(type);
529 }
530 create(bindings) {
531 return this.createByType(this.type, bindings);
532 }
533 createByType(type, bindings) {
534 bindings = this.assignDefaults(bindings);
535 const component = this.injectComponent(type, bindings);
536 this.register(type, component);
537 return component;
538 }
539 destroy(instance) {
540 const compsByType = this.components.get(instance.componentType);
541 if (compsByType && compsByType.length) {
542 const idx = compsByType.indexOf(instance);
543 if (idx > -1) {
544 const component = compsByType[idx];
545 component.destroy();
546 compsByType.splice(idx, 1);
547 }
548 }
549 }
550 destroyAll() {
551 this.destroyByType(this.type);
552 }
553 destroyByType(type) {
554 const comps = this.components.get(type);
555 if (comps && comps.length) {
556 let i = comps.length - 1;
557 while (i >= 0) {
558 this.destroy(comps[i--]);
559 }
560 }
561 }
562 injectComponent(type, bindings) {
563 return this.injectionService.appendComponent(type, bindings);
564 }
565 assignDefaults(bindings) {
566 const inputs = Object.assign({}, this.defaults.inputs);
567 const outputs = Object.assign({}, this.defaults.outputs);
568 if (!bindings.inputs && !bindings.outputs) {
569 bindings = { inputs: bindings };
570 }
571 if (inputs) {
572 bindings.inputs = Object.assign(Object.assign({}, inputs), bindings.inputs);
573 }
574 if (outputs) {
575 bindings.outputs = Object.assign(Object.assign({}, outputs), bindings.outputs);
576 }
577 return bindings;
578 }
579 register(type, component) {
580 if (!this.components.has(type)) {
581 this.components.set(type, []);
582 }
583 const types = this.components.get(type);
584 types.push(component);
585 }
586}
587
588class TooltipService extends InjectionRegisteryService {
589 constructor(injectionService) {
590 super(injectionService);
591 this.type = TooltipContentComponent;
592 }
593}
594TooltipService.decorators = [
595 { type: Injectable }
596];
597TooltipService.ctorParameters = () => [
598 { type: InjectionService }
599];
600
601var LegendPosition;
602(function (LegendPosition) {
603 LegendPosition["Right"] = "right";
604 LegendPosition["Below"] = "below";
605})(LegendPosition || (LegendPosition = {}));
606var LegendType;
607(function (LegendType) {
608 LegendType["ScaleLegend"] = "scaleLegend";
609 LegendType["Legend"] = "legend";
610})(LegendType || (LegendType = {}));
611
612var ScaleType;
613(function (ScaleType) {
614 ScaleType["Time"] = "time";
615 ScaleType["Linear"] = "linear";
616 ScaleType["Ordinal"] = "ordinal";
617 ScaleType["Quantile"] = "quantile";
618})(ScaleType || (ScaleType = {}));
619
620class ChartComponent {
621 constructor() {
622 this.showLegend = false;
623 this.animations = true;
624 this.legendLabelClick = new EventEmitter();
625 this.legendLabelActivate = new EventEmitter();
626 this.legendLabelDeactivate = new EventEmitter();
627 this.LegendPosition = LegendPosition;
628 this.LegendType = LegendType;
629 }
630 ngOnChanges(changes) {
631 this.update();
632 }
633 update() {
634 let legendColumns = 0;
635 if (this.showLegend) {
636 this.legendType = this.getLegendType();
637 if (!this.legendOptions || this.legendOptions.position === LegendPosition.Right) {
638 if (this.legendType === LegendType.ScaleLegend) {
639 legendColumns = 1;
640 }
641 else {
642 legendColumns = 2;
643 }
644 }
645 }
646 const chartColumns = 12 - legendColumns;
647 this.chartWidth = Math.floor((this.view[0] * chartColumns) / 12.0);
648 this.legendWidth =
649 !this.legendOptions || this.legendOptions.position === LegendPosition.Right
650 ? Math.floor((this.view[0] * legendColumns) / 12.0)
651 : this.chartWidth;
652 }
653 getLegendType() {
654 return this.legendOptions.scaleType === ScaleType.Linear ? LegendType.ScaleLegend : LegendType.Legend;
655 }
656}
657ChartComponent.decorators = [
658 { type: Component, args: [{
659 providers: [TooltipService],
660 selector: 'ngx-charts-chart',
661 template: `
662 <div class="ngx-charts-outer" [style.width.px]="view[0]" [@animationState]="'active'" [@.disabled]="!animations">
663 <svg class="ngx-charts" [attr.width]="chartWidth" [attr.height]="view[1]">
664 <ng-content></ng-content>
665 </svg>
666 <ngx-charts-scale-legend
667 *ngIf="showLegend && legendType === LegendType.ScaleLegend"
668 class="chart-legend"
669 [horizontal]="legendOptions && legendOptions.position === LegendPosition.Below"
670 [valueRange]="legendOptions.domain"
671 [colors]="legendOptions.colors"
672 [height]="view[1]"
673 [width]="legendWidth"
674 >
675 </ngx-charts-scale-legend>
676 <ngx-charts-legend
677 *ngIf="showLegend && legendType === LegendType.Legend"
678 class="chart-legend"
679 [horizontal]="legendOptions && legendOptions.position === LegendPosition.Below"
680 [data]="legendOptions.domain"
681 [title]="legendOptions.title"
682 [colors]="legendOptions.colors"
683 [height]="view[1]"
684 [width]="legendWidth"
685 [activeEntries]="activeEntries"
686 (labelClick)="legendLabelClick.emit($event)"
687 (labelActivate)="legendLabelActivate.emit($event)"
688 (labelDeactivate)="legendLabelDeactivate.emit($event)"
689 >
690 </ngx-charts-legend>
691 </div>
692 `,
693 changeDetection: ChangeDetectionStrategy.OnPush,
694 animations: [
695 trigger('animationState', [
696 transition(':enter', [style({ opacity: 0 }), animate('500ms 100ms', style({ opacity: 1 }))])
697 ])
698 ]
699 },] }
700];
701ChartComponent.propDecorators = {
702 view: [{ type: Input }],
703 showLegend: [{ type: Input }],
704 legendOptions: [{ type: Input }],
705 legendType: [{ type: Input }],
706 activeEntries: [{ type: Input }],
707 animations: [{ type: Input }],
708 legendLabelClick: [{ type: Output }],
709 legendLabelActivate: [{ type: Output }],
710 legendLabelDeactivate: [{ type: Output }]
711};
712
713/**
714 * Visibility Observer
715 */
716class VisibilityObserver {
717 constructor(element, zone) {
718 this.element = element;
719 this.zone = zone;
720 this.visible = new EventEmitter();
721 this.isVisible = false;
722 this.runCheck();
723 }
724 destroy() {
725 clearTimeout(this.timeout);
726 }
727 onVisibilityChange() {
728 // trigger zone recalc for columns
729 this.zone.run(() => {
730 this.isVisible = true;
731 this.visible.emit(true);
732 });
733 }
734 runCheck() {
735 const check = () => {
736 if (!this.element) {
737 return;
738 }
739 // https://davidwalsh.name/offsetheight-visibility
740 const { offsetHeight, offsetWidth } = this.element.nativeElement;
741 if (offsetHeight && offsetWidth) {
742 clearTimeout(this.timeout);
743 this.onVisibilityChange();
744 }
745 else {
746 clearTimeout(this.timeout);
747 this.zone.runOutsideAngular(() => {
748 this.timeout = setTimeout(() => check(), 100);
749 });
750 }
751 };
752 this.zone.runOutsideAngular(() => {
753 this.timeout = setTimeout(() => check());
754 });
755 }
756}
757VisibilityObserver.decorators = [
758 { type: Directive, args: [{
759 selector: 'visibility-observer'
760 },] }
761];
762VisibilityObserver.ctorParameters = () => [
763 { type: ElementRef },
764 { type: NgZone }
765];
766VisibilityObserver.propDecorators = {
767 visible: [{ type: Output }]
768};
769
770function isDate(value) {
771 return toString.call(value) === '[object Date]';
772}
773function isNumber(value) {
774 return typeof value === 'number';
775}
776
777class BaseChartComponent {
778 constructor(chartElement, zone, cd, platformId) {
779 this.chartElement = chartElement;
780 this.zone = zone;
781 this.cd = cd;
782 this.platformId = platformId;
783 this.scheme = 'cool';
784 this.schemeType = ScaleType.Ordinal;
785 this.animations = true;
786 this.select = new EventEmitter();
787 }
788 ngOnInit() {
789 if (isPlatformServer(this.platformId)) {
790 this.animations = false;
791 }
792 }
793 ngAfterViewInit() {
794 this.bindWindowResizeEvent();
795 // listen for visibility of the element for hidden by default scenario
796 this.visibilityObserver = new VisibilityObserver(this.chartElement, this.zone);
797 this.visibilityObserver.visible.subscribe(this.update.bind(this));
798 }
799 ngOnDestroy() {
800 this.unbindEvents();
801 if (this.visibilityObserver) {
802 this.visibilityObserver.visible.unsubscribe();
803 this.visibilityObserver.destroy();
804 }
805 }
806 ngOnChanges(changes) {
807 this.update();
808 }
809 update() {
810 if (this.results) {
811 this.results = this.cloneData(this.results);
812 }
813 else {
814 this.results = [];
815 }
816 if (this.view) {
817 this.width = this.view[0];
818 this.height = this.view[1];
819 }
820 else {
821 const dims = this.getContainerDims();
822 if (dims) {
823 this.width = dims.width;
824 this.height = dims.height;
825 }
826 }
827 // default values if width or height are 0 or undefined
828 if (!this.width) {
829 this.width = 600;
830 }
831 if (!this.height) {
832 this.height = 400;
833 }
834 this.width = Math.floor(this.width);
835 this.height = Math.floor(this.height);
836 if (this.cd) {
837 this.cd.markForCheck();
838 }
839 }
840 getContainerDims() {
841 let width;
842 let height;
843 const hostElem = this.chartElement.nativeElement;
844 if (isPlatformBrowser(this.platformId) && hostElem.parentNode !== null) {
845 // Get the container dimensions
846 const dims = hostElem.parentNode.getBoundingClientRect();
847 width = dims.width;
848 height = dims.height;
849 }
850 if (width && height) {
851 return { width, height };
852 }
853 return null;
854 }
855 /**
856 * Converts all date objects that appear as name
857 * into formatted date strings
858 */
859 formatDates() {
860 for (let i = 0; i < this.results.length; i++) {
861 const g = this.results[i];
862 g.label = g.name;
863 if (isDate(g.label)) {
864 g.label = g.label.toLocaleDateString();
865 }
866 if (g.series) {
867 for (let j = 0; j < g.series.length; j++) {
868 const d = g.series[j];
869 d.label = d.name;
870 if (isDate(d.label)) {
871 d.label = d.label.toLocaleDateString();
872 }
873 }
874 }
875 }
876 }
877 unbindEvents() {
878 if (this.resizeSubscription) {
879 this.resizeSubscription.unsubscribe();
880 }
881 }
882 bindWindowResizeEvent() {
883 if (!isPlatformBrowser(this.platformId)) {
884 return;
885 }
886 const source = fromEvent(window, 'resize');
887 const subscription = source.pipe(debounceTime(200)).subscribe(e => {
888 this.update();
889 if (this.cd) {
890 this.cd.markForCheck();
891 }
892 });
893 this.resizeSubscription = subscription;
894 }
895 /**
896 * Clones the data into a new object
897 *
898 * @memberOf BaseChart
899 */
900 cloneData(data) {
901 const results = [];
902 for (const item of data) {
903 const copy = {
904 name: item['name']
905 };
906 if (item['value'] !== undefined) {
907 copy['value'] = item['value'];
908 }
909 if (item['series'] !== undefined) {
910 copy['series'] = [];
911 for (const seriesItem of item['series']) {
912 const seriesItemCopy = Object.assign({}, seriesItem);
913 copy['series'].push(seriesItemCopy);
914 }
915 }
916 if (item['extra'] !== undefined) {
917 copy['extra'] = JSON.parse(JSON.stringify(item['extra']));
918 }
919 results.push(copy);
920 }
921 return results;
922 }
923}
924BaseChartComponent.decorators = [
925 { type: Component, args: [{
926 selector: 'base-chart',
927 template: ` <div></div> `
928 },] }
929];
930BaseChartComponent.ctorParameters = () => [
931 { type: ElementRef },
932 { type: NgZone },
933 { type: ChangeDetectorRef },
934 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
935];
936BaseChartComponent.propDecorators = {
937 results: [{ type: Input }],
938 view: [{ type: Input }],
939 scheme: [{ type: Input }],
940 schemeType: [{ type: Input }],
941 customColors: [{ type: Input }],
942 animations: [{ type: Input }],
943 select: [{ type: Output }]
944};
945
946var Orientation;
947(function (Orientation) {
948 Orientation["Top"] = "top";
949 Orientation["Bottom"] = "bottom";
950 Orientation["Left"] = "left";
951 Orientation["Right"] = "right";
952})(Orientation || (Orientation = {}));
953
954class AxisLabelComponent {
955 constructor(element) {
956 this.textHeight = 25;
957 this.margin = 5;
958 this.element = element.nativeElement;
959 }
960 ngOnChanges(changes) {
961 this.update();
962 }
963 update() {
964 this.strokeWidth = '0.01';
965 this.textAnchor = 'middle';
966 this.transform = '';
967 switch (this.orient) {
968 case Orientation.Top:
969 this.y = this.offset;
970 this.x = this.width / 2;
971 break;
972 case Orientation.Bottom:
973 this.y = this.offset;
974 this.x = this.width / 2;
975 break;
976 case Orientation.Left:
977 this.y = -(this.offset + this.textHeight + this.margin);
978 this.x = -this.height / 2;
979 this.transform = 'rotate(270)';
980 break;
981 case Orientation.Right:
982 this.y = this.offset + this.margin;
983 this.x = -this.height / 2;
984 this.transform = 'rotate(270)';
985 break;
986 default:
987 }
988 }
989}
990AxisLabelComponent.decorators = [
991 { type: Component, args: [{
992 selector: 'g[ngx-charts-axis-label]',
993 template: `
994 <svg:text
995 [attr.stroke-width]="strokeWidth"
996 [attr.x]="x"
997 [attr.y]="y"
998 [attr.text-anchor]="textAnchor"
999 [attr.transform]="transform"
1000 >
1001 {{ label }}
1002 </svg:text>
1003 `,
1004 changeDetection: ChangeDetectionStrategy.OnPush
1005 },] }
1006];
1007AxisLabelComponent.ctorParameters = () => [
1008 { type: ElementRef }
1009];
1010AxisLabelComponent.propDecorators = {
1011 orient: [{ type: Input }],
1012 label: [{ type: Input }],
1013 offset: [{ type: Input }],
1014 width: [{ type: Input }],
1015 height: [{ type: Input }]
1016};
1017
1018function trimLabel(s, max = 16) {
1019 if (typeof s !== 'string') {
1020 if (typeof s === 'number') {
1021 return s + '';
1022 }
1023 else {
1024 return '';
1025 }
1026 }
1027 s = s.trim();
1028 if (s.length <= max) {
1029 return s;
1030 }
1031 else {
1032 return `${s.slice(0, max)}...`;
1033 }
1034}
1035
1036function reduceTicks(ticks, maxTicks) {
1037 if (ticks.length > maxTicks) {
1038 const reduced = [];
1039 const modulus = Math.floor(ticks.length / maxTicks);
1040 for (let i = 0; i < ticks.length; i++) {
1041 if (i % modulus === 0) {
1042 reduced.push(ticks[i]);
1043 }
1044 }
1045 ticks = reduced;
1046 }
1047 return ticks;
1048}
1049
1050var TextAnchor;
1051(function (TextAnchor) {
1052 TextAnchor["Start"] = "start";
1053 TextAnchor["Middle"] = "middle";
1054 TextAnchor["End"] = "end";
1055})(TextAnchor || (TextAnchor = {}));
1056
1057class XAxisTicksComponent {
1058 constructor(platformId) {
1059 this.platformId = platformId;
1060 this.tickArguments = [5];
1061 this.tickStroke = '#ccc';
1062 this.trimTicks = true;
1063 this.maxTickLength = 16;
1064 this.showGridLines = false;
1065 this.rotateTicks = true;
1066 this.dimensionsChanged = new EventEmitter();
1067 this.verticalSpacing = 20;
1068 this.rotateLabels = false;
1069 this.innerTickSize = 6;
1070 this.outerTickSize = 6;
1071 this.tickPadding = 3;
1072 this.textAnchor = TextAnchor.Middle;
1073 this.maxTicksLength = 0;
1074 this.maxAllowedLength = 16;
1075 this.height = 0;
1076 this.approxHeight = 10;
1077 }
1078 ngOnChanges(changes) {
1079 this.update();
1080 }
1081 ngAfterViewInit() {
1082 setTimeout(() => this.updateDims());
1083 }
1084 updateDims() {
1085 if (!isPlatformBrowser(this.platformId)) {
1086 // for SSR, use approximate value instead of measured
1087 this.dimensionsChanged.emit({ height: this.approxHeight });
1088 return;
1089 }
1090 const height = parseInt(this.ticksElement.nativeElement.getBoundingClientRect().height, 10);
1091 if (height !== this.height) {
1092 this.height = height;
1093 this.dimensionsChanged.emit({ height: this.height });
1094 setTimeout(() => this.updateDims());
1095 }
1096 }
1097 update() {
1098 const scale = this.scale;
1099 this.ticks = this.getTicks();
1100 if (this.tickFormatting) {
1101 this.tickFormat = this.tickFormatting;
1102 }
1103 else if (scale.tickFormat) {
1104 this.tickFormat = scale.tickFormat.apply(scale, this.tickArguments);
1105 }
1106 else {
1107 this.tickFormat = function (d) {
1108 if (d.constructor.name === 'Date') {
1109 return d.toLocaleDateString();
1110 }
1111 return d.toLocaleString();
1112 };
1113 }
1114 const angle = this.rotateTicks ? this.getRotationAngle(this.ticks) : null;
1115 this.adjustedScale = this.scale.bandwidth
1116 ? function (d) {
1117 return this.scale(d) + this.scale.bandwidth() * 0.5;
1118 }
1119 : this.scale;
1120 this.textTransform = '';
1121 if (angle && angle !== 0) {
1122 this.textTransform = `rotate(${angle})`;
1123 this.textAnchor = TextAnchor.End;
1124 this.verticalSpacing = 10;
1125 }
1126 else {
1127 this.textAnchor = TextAnchor.Middle;
1128 }
1129 setTimeout(() => this.updateDims());
1130 }
1131 getRotationAngle(ticks) {
1132 let angle = 0;
1133 this.maxTicksLength = 0;
1134 for (let i = 0; i < ticks.length; i++) {
1135 const tick = this.tickFormat(ticks[i]).toString();
1136 let tickLength = tick.length;
1137 if (this.trimTicks) {
1138 tickLength = this.tickTrim(tick).length;
1139 }
1140 if (tickLength > this.maxTicksLength) {
1141 this.maxTicksLength = tickLength;
1142 }
1143 }
1144 const len = Math.min(this.maxTicksLength, this.maxAllowedLength);
1145 const charWidth = 7; // need to measure this
1146 const wordWidth = len * charWidth;
1147 let baseWidth = wordWidth;
1148 const maxBaseWidth = Math.floor(this.width / ticks.length);
1149 // calculate optimal angle
1150 while (baseWidth > maxBaseWidth && angle > -90) {
1151 angle -= 30;
1152 baseWidth = Math.cos(angle * (Math.PI / 180)) * wordWidth;
1153 }
1154 this.approxHeight = Math.max(Math.abs(Math.sin(angle * (Math.PI / 180)) * wordWidth), 10);
1155 return angle;
1156 }
1157 getTicks() {
1158 let ticks;
1159 const maxTicks = this.getMaxTicks(20);
1160 const maxScaleTicks = this.getMaxTicks(100);
1161 if (this.tickValues) {
1162 ticks = this.tickValues;
1163 }
1164 else if (this.scale.ticks) {
1165 ticks = this.scale.ticks.apply(this.scale, [maxScaleTicks]);
1166 }
1167 else {
1168 ticks = this.scale.domain();
1169 ticks = reduceTicks(ticks, maxTicks);
1170 }
1171 return ticks;
1172 }
1173 getMaxTicks(tickWidth) {
1174 return Math.floor(this.width / tickWidth);
1175 }
1176 tickTransform(tick) {
1177 return 'translate(' + this.adjustedScale(tick) + ',' + this.verticalSpacing + ')';
1178 }
1179 gridLineTransform() {
1180 return `translate(0,${-this.verticalSpacing - 5})`;
1181 }
1182 tickTrim(label) {
1183 return this.trimTicks ? trimLabel(label, this.maxTickLength) : label;
1184 }
1185}
1186XAxisTicksComponent.decorators = [
1187 { type: Component, args: [{
1188 selector: 'g[ngx-charts-x-axis-ticks]',
1189 template: `
1190 <svg:g #ticksel>
1191 <svg:g *ngFor="let tick of ticks" class="tick" [attr.transform]="tickTransform(tick)">
1192 <title>{{ tickFormat(tick) }}</title>
1193 <svg:text
1194 stroke-width="0.01"
1195 [attr.text-anchor]="textAnchor"
1196 [attr.transform]="textTransform"
1197 [style.font-size]="'12px'"
1198 >
1199 {{ tickTrim(tickFormat(tick)) }}
1200 </svg:text>
1201 </svg:g>
1202 </svg:g>
1203
1204 <svg:g *ngFor="let tick of ticks" [attr.transform]="tickTransform(tick)">
1205 <svg:g *ngIf="showGridLines" [attr.transform]="gridLineTransform()">
1206 <svg:line class="gridline-path gridline-path-vertical" [attr.y1]="-gridLineHeight" y2="0" />
1207 </svg:g>
1208 </svg:g>
1209 `,
1210 changeDetection: ChangeDetectionStrategy.OnPush
1211 },] }
1212];
1213XAxisTicksComponent.ctorParameters = () => [
1214 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
1215];
1216XAxisTicksComponent.propDecorators = {
1217 scale: [{ type: Input }],
1218 orient: [{ type: Input }],
1219 tickArguments: [{ type: Input }],
1220 tickValues: [{ type: Input }],
1221 tickStroke: [{ type: Input }],
1222 trimTicks: [{ type: Input }],
1223 maxTickLength: [{ type: Input }],
1224 tickFormatting: [{ type: Input }],
1225 showGridLines: [{ type: Input }],
1226 gridLineHeight: [{ type: Input }],
1227 width: [{ type: Input }],
1228 rotateTicks: [{ type: Input }],
1229 dimensionsChanged: [{ type: Output }],
1230 ticksElement: [{ type: ViewChild, args: ['ticksel',] }]
1231};
1232
1233class XAxisComponent {
1234 constructor() {
1235 this.rotateTicks = true;
1236 this.showGridLines = false;
1237 this.xOrient = Orientation.Bottom;
1238 this.xAxisOffset = 0;
1239 this.dimensionsChanged = new EventEmitter();
1240 this.xAxisClassName = 'x axis';
1241 this.labelOffset = 0;
1242 this.fill = 'none';
1243 this.stroke = 'stroke';
1244 this.tickStroke = '#ccc';
1245 this.strokeWidth = 'none';
1246 this.padding = 5;
1247 this.orientation = Orientation;
1248 }
1249 ngOnChanges(changes) {
1250 this.update();
1251 }
1252 update() {
1253 this.transform = `translate(0,${this.xAxisOffset + this.padding + this.dims.height})`;
1254 if (typeof this.xAxisTickCount !== 'undefined') {
1255 this.tickArguments = [this.xAxisTickCount];
1256 }
1257 }
1258 emitTicksHeight({ height }) {
1259 const newLabelOffset = height + 25 + 5;
1260 if (newLabelOffset !== this.labelOffset) {
1261 this.labelOffset = newLabelOffset;
1262 setTimeout(() => {
1263 this.dimensionsChanged.emit({ height });
1264 }, 0);
1265 }
1266 }
1267}
1268XAxisComponent.decorators = [
1269 { type: Component, args: [{
1270 selector: 'g[ngx-charts-x-axis]',
1271 template: `
1272 <svg:g [attr.class]="xAxisClassName" [attr.transform]="transform">
1273 <svg:g
1274 ngx-charts-x-axis-ticks
1275 *ngIf="xScale"
1276 [trimTicks]="trimTicks"
1277 [rotateTicks]="rotateTicks"
1278 [maxTickLength]="maxTickLength"
1279 [tickFormatting]="tickFormatting"
1280 [tickArguments]="tickArguments"
1281 [tickStroke]="tickStroke"
1282 [scale]="xScale"
1283 [orient]="xOrient"
1284 [showGridLines]="showGridLines"
1285 [gridLineHeight]="dims.height"
1286 [width]="dims.width"
1287 [tickValues]="ticks"
1288 (dimensionsChanged)="emitTicksHeight($event)"
1289 />
1290 <svg:g
1291 ngx-charts-axis-label
1292 *ngIf="showLabel"
1293 [label]="labelText"
1294 [offset]="labelOffset"
1295 [orient]="orientation.Bottom"
1296 [height]="dims.height"
1297 [width]="dims.width"
1298 ></svg:g>
1299 </svg:g>
1300 `,
1301 changeDetection: ChangeDetectionStrategy.OnPush
1302 },] }
1303];
1304XAxisComponent.propDecorators = {
1305 xScale: [{ type: Input }],
1306 dims: [{ type: Input }],
1307 trimTicks: [{ type: Input }],
1308 rotateTicks: [{ type: Input }],
1309 maxTickLength: [{ type: Input }],
1310 tickFormatting: [{ type: Input }],
1311 showGridLines: [{ type: Input }],
1312 showLabel: [{ type: Input }],
1313 labelText: [{ type: Input }],
1314 ticks: [{ type: Input }],
1315 xAxisTickCount: [{ type: Input }],
1316 xOrient: [{ type: Input }],
1317 xAxisOffset: [{ type: Input }],
1318 dimensionsChanged: [{ type: Output }],
1319 ticksComponent: [{ type: ViewChild, args: [XAxisTicksComponent,] }]
1320};
1321
1322/**
1323 * Generates a rounded rectanglar path
1324 *
1325 * @export
1326 * @param x, y, w, h, r, tl, tr, bl, br
1327 */
1328function roundedRect(x, y, w, h, r, [tl, tr, bl, br]) {
1329 let retval = '';
1330 w = Math.floor(w);
1331 h = Math.floor(h);
1332 w = w === 0 ? 1 : w;
1333 h = h === 0 ? 1 : h;
1334 retval = `M${[x + r, y]}`;
1335 retval += `h${w - 2 * r}`;
1336 if (tr) {
1337 retval += `a${[r, r]} 0 0 1 ${[r, r]}`;
1338 }
1339 else {
1340 retval += `h${r}v${r}`;
1341 }
1342 retval += `v${h - 2 * r}`;
1343 if (br) {
1344 retval += `a${[r, r]} 0 0 1 ${[-r, r]}`;
1345 }
1346 else {
1347 retval += `v${r}h${-r}`;
1348 }
1349 retval += `h${2 * r - w}`;
1350 if (bl) {
1351 retval += `a${[r, r]} 0 0 1 ${[-r, -r]}`;
1352 }
1353 else {
1354 retval += `h${-r}v${-r}`;
1355 }
1356 retval += `v${2 * r - h}`;
1357 if (tl) {
1358 retval += `a${[r, r]} 0 0 1 ${[r, -r]}`;
1359 }
1360 else {
1361 retval += `v${-r}h${r}`;
1362 }
1363 retval += `z`;
1364 return retval;
1365}
1366
1367class YAxisTicksComponent {
1368 constructor(platformId) {
1369 this.platformId = platformId;
1370 this.tickArguments = [5];
1371 this.tickStroke = '#ccc';
1372 this.trimTicks = true;
1373 this.maxTickLength = 16;
1374 this.showGridLines = false;
1375 this.showRefLabels = false;
1376 this.showRefLines = false;
1377 this.dimensionsChanged = new EventEmitter();
1378 this.innerTickSize = 6;
1379 this.tickPadding = 3;
1380 this.verticalSpacing = 20;
1381 this.textAnchor = TextAnchor.Middle;
1382 this.width = 0;
1383 this.outerTickSize = 6;
1384 this.rotateLabels = false;
1385 this.referenceLineLength = 0;
1386 this.Orientation = Orientation;
1387 }
1388 ngOnChanges(changes) {
1389 this.update();
1390 }
1391 ngAfterViewInit() {
1392 setTimeout(() => this.updateDims());
1393 }
1394 updateDims() {
1395 if (!isPlatformBrowser(this.platformId)) {
1396 // for SSR, use approximate value instead of measured
1397 this.width = this.getApproximateAxisWidth();
1398 this.dimensionsChanged.emit({ width: this.width });
1399 return;
1400 }
1401 const width = parseInt(this.ticksElement.nativeElement.getBoundingClientRect().width, 10);
1402 if (width !== this.width) {
1403 this.width = width;
1404 this.dimensionsChanged.emit({ width });
1405 setTimeout(() => this.updateDims());
1406 }
1407 }
1408 update() {
1409 let scale;
1410 const sign = this.orient === Orientation.Top || this.orient === Orientation.Right ? -1 : 1;
1411 this.tickSpacing = Math.max(this.innerTickSize, 0) + this.tickPadding;
1412 scale = this.scale;
1413 this.ticks = this.getTicks();
1414 if (this.tickFormatting) {
1415 this.tickFormat = this.tickFormatting;
1416 }
1417 else if (scale.tickFormat) {
1418 this.tickFormat = scale.tickFormat.apply(scale, this.tickArguments);
1419 }
1420 else {
1421 this.tickFormat = function (d) {
1422 if (d.constructor.name === 'Date') {
1423 return d.toLocaleDateString();
1424 }
1425 return d.toLocaleString();
1426 };
1427 }
1428 this.adjustedScale = scale.bandwidth
1429 ? function (d) {
1430 return scale(d) + scale.bandwidth() * 0.5;
1431 }
1432 : scale;
1433 if (this.showRefLines && this.referenceLines) {
1434 this.setReferencelines();
1435 }
1436 switch (this.orient) {
1437 case Orientation.Top:
1438 this.transform = function (tick) {
1439 return 'translate(' + this.adjustedScale(tick) + ',0)';
1440 };
1441 this.textAnchor = TextAnchor.Middle;
1442 this.y2 = this.innerTickSize * sign;
1443 this.y1 = this.tickSpacing * sign;
1444 this.dy = sign < 0 ? '0em' : '.71em';
1445 break;
1446 case Orientation.Bottom:
1447 this.transform = function (tick) {
1448 return 'translate(' + this.adjustedScale(tick) + ',0)';
1449 };
1450 this.textAnchor = TextAnchor.Middle;
1451 this.y2 = this.innerTickSize * sign;
1452 this.y1 = this.tickSpacing * sign;
1453 this.dy = sign < 0 ? '0em' : '.71em';
1454 break;
1455 case Orientation.Left:
1456 this.transform = function (tick) {
1457 return 'translate(0,' + this.adjustedScale(tick) + ')';
1458 };
1459 this.textAnchor = TextAnchor.End;
1460 this.x2 = this.innerTickSize * -sign;
1461 this.x1 = this.tickSpacing * -sign;
1462 this.dy = '.32em';
1463 break;
1464 case Orientation.Right:
1465 this.transform = function (tick) {
1466 return 'translate(0,' + this.adjustedScale(tick) + ')';
1467 };
1468 this.textAnchor = TextAnchor.Start;
1469 this.x2 = this.innerTickSize * -sign;
1470 this.x1 = this.tickSpacing * -sign;
1471 this.dy = '.32em';
1472 break;
1473 default:
1474 }
1475 setTimeout(() => this.updateDims());
1476 }
1477 setReferencelines() {
1478 this.refMin = this.adjustedScale(Math.min.apply(null, this.referenceLines.map(item => item.value)));
1479 this.refMax = this.adjustedScale(Math.max.apply(null, this.referenceLines.map(item => item.value)));
1480 this.referenceLineLength = this.referenceLines.length;
1481 this.referenceAreaPath = roundedRect(0, this.refMax, this.gridLineWidth, this.refMin - this.refMax, 0, [
1482 false,
1483 false,
1484 false,
1485 false
1486 ]);
1487 }
1488 getTicks() {
1489 let ticks;
1490 const maxTicks = this.getMaxTicks(20);
1491 const maxScaleTicks = this.getMaxTicks(50);
1492 if (this.tickValues) {
1493 ticks = this.tickValues;
1494 }
1495 else if (this.scale.ticks) {
1496 ticks = this.scale.ticks.apply(this.scale, [maxScaleTicks]);
1497 }
1498 else {
1499 ticks = this.scale.domain();
1500 ticks = reduceTicks(ticks, maxTicks);
1501 }
1502 return ticks;
1503 }
1504 getMaxTicks(tickHeight) {
1505 return Math.floor(this.height / tickHeight);
1506 }
1507 tickTransform(tick) {
1508 return `translate(${this.adjustedScale(tick)},${this.verticalSpacing})`;
1509 }
1510 gridLineTransform() {
1511 return `translate(5,0)`;
1512 }
1513 tickTrim(label) {
1514 return this.trimTicks ? trimLabel(label, this.maxTickLength) : label;
1515 }
1516 getApproximateAxisWidth() {
1517 const maxChars = Math.max(...this.ticks.map(t => this.tickTrim(this.tickFormat(t)).length));
1518 const charWidth = 7;
1519 return maxChars * charWidth;
1520 }
1521}
1522YAxisTicksComponent.decorators = [
1523 { type: Component, args: [{
1524 selector: 'g[ngx-charts-y-axis-ticks]',
1525 template: `
1526 <svg:g #ticksel>
1527 <svg:g *ngFor="let tick of ticks" class="tick" [attr.transform]="transform(tick)">
1528 <title>{{ tickFormat(tick) }}</title>
1529 <svg:text
1530 stroke-width="0.01"
1531 [attr.dy]="dy"
1532 [attr.x]="x1"
1533 [attr.y]="y1"
1534 [attr.text-anchor]="textAnchor"
1535 [style.font-size]="'12px'"
1536 >
1537 {{ tickTrim(tickFormat(tick)) }}
1538 </svg:text>
1539 </svg:g>
1540 </svg:g>
1541
1542 <svg:path
1543 *ngIf="referenceLineLength > 1 && refMax && refMin && showRefLines"
1544 class="reference-area"
1545 [attr.d]="referenceAreaPath"
1546 [attr.transform]="gridLineTransform()"
1547 />
1548 <svg:g *ngFor="let tick of ticks" [attr.transform]="transform(tick)">
1549 <svg:g *ngIf="showGridLines" [attr.transform]="gridLineTransform()">
1550 <svg:line
1551 *ngIf="orient === Orientation.Left"
1552 class="gridline-path gridline-path-horizontal"
1553 x1="0"
1554 [attr.x2]="gridLineWidth"
1555 />
1556 <svg:line
1557 *ngIf="orient === Orientation.Right"
1558 class="gridline-path gridline-path-horizontal"
1559 x1="0"
1560 [attr.x2]="-gridLineWidth"
1561 />
1562 </svg:g>
1563 </svg:g>
1564
1565 <svg:g *ngFor="let refLine of referenceLines">
1566 <svg:g *ngIf="showRefLines" [attr.transform]="transform(refLine.value)">
1567 <svg:line
1568 class="refline-path gridline-path-horizontal"
1569 x1="0"
1570 [attr.x2]="gridLineWidth"
1571 [attr.transform]="gridLineTransform()"
1572 />
1573 <svg:g *ngIf="showRefLabels">
1574 <title>{{ tickTrim(tickFormat(refLine.value)) }}</title>
1575 <svg:text
1576 class="refline-label"
1577 [attr.dy]="dy"
1578 [attr.y]="-6"
1579 [attr.x]="gridLineWidth"
1580 [attr.text-anchor]="textAnchor"
1581 >
1582 {{ refLine.name }}
1583 </svg:text>
1584 </svg:g>
1585 </svg:g>
1586 </svg:g>
1587 `,
1588 changeDetection: ChangeDetectionStrategy.OnPush
1589 },] }
1590];
1591YAxisTicksComponent.ctorParameters = () => [
1592 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
1593];
1594YAxisTicksComponent.propDecorators = {
1595 scale: [{ type: Input }],
1596 orient: [{ type: Input }],
1597 tickArguments: [{ type: Input }],
1598 tickValues: [{ type: Input }],
1599 tickStroke: [{ type: Input }],
1600 trimTicks: [{ type: Input }],
1601 maxTickLength: [{ type: Input }],
1602 tickFormatting: [{ type: Input }],
1603 showGridLines: [{ type: Input }],
1604 gridLineWidth: [{ type: Input }],
1605 height: [{ type: Input }],
1606 referenceLines: [{ type: Input }],
1607 showRefLabels: [{ type: Input }],
1608 showRefLines: [{ type: Input }],
1609 dimensionsChanged: [{ type: Output }],
1610 ticksElement: [{ type: ViewChild, args: ['ticksel',] }]
1611};
1612
1613class YAxisComponent {
1614 constructor() {
1615 this.showGridLines = false;
1616 this.yOrient = Orientation.Left;
1617 this.yAxisOffset = 0;
1618 this.dimensionsChanged = new EventEmitter();
1619 this.yAxisClassName = 'y axis';
1620 this.labelOffset = 15;
1621 this.fill = 'none';
1622 this.stroke = '#CCC';
1623 this.tickStroke = '#CCC';
1624 this.strokeWidth = 1;
1625 this.padding = 5;
1626 }
1627 ngOnChanges(changes) {
1628 this.update();
1629 }
1630 update() {
1631 this.offset = -(this.yAxisOffset + this.padding);
1632 if (this.yOrient === Orientation.Right) {
1633 this.labelOffset = 65;
1634 this.transform = `translate(${this.offset + this.dims.width} , 0)`;
1635 }
1636 else {
1637 this.offset = this.offset;
1638 this.transform = `translate(${this.offset} , 0)`;
1639 }
1640 if (this.yAxisTickCount !== undefined) {
1641 this.tickArguments = [this.yAxisTickCount];
1642 }
1643 }
1644 emitTicksWidth({ width }) {
1645 if (width !== this.labelOffset && this.yOrient === Orientation.Right) {
1646 this.labelOffset = width + this.labelOffset;
1647 setTimeout(() => {
1648 this.dimensionsChanged.emit({ width });
1649 }, 0);
1650 }
1651 else if (width !== this.labelOffset) {
1652 this.labelOffset = width;
1653 setTimeout(() => {
1654 this.dimensionsChanged.emit({ width });
1655 }, 0);
1656 }
1657 }
1658}
1659YAxisComponent.decorators = [
1660 { type: Component, args: [{
1661 selector: 'g[ngx-charts-y-axis]',
1662 template: `
1663 <svg:g [attr.class]="yAxisClassName" [attr.transform]="transform">
1664 <svg:g
1665 ngx-charts-y-axis-ticks
1666 *ngIf="yScale"
1667 [trimTicks]="trimTicks"
1668 [maxTickLength]="maxTickLength"
1669 [tickFormatting]="tickFormatting"
1670 [tickArguments]="tickArguments"
1671 [tickValues]="ticks"
1672 [tickStroke]="tickStroke"
1673 [scale]="yScale"
1674 [orient]="yOrient"
1675 [showGridLines]="showGridLines"
1676 [gridLineWidth]="dims.width"
1677 [referenceLines]="referenceLines"
1678 [showRefLines]="showRefLines"
1679 [showRefLabels]="showRefLabels"
1680 [height]="dims.height"
1681 (dimensionsChanged)="emitTicksWidth($event)"
1682 />
1683
1684 <svg:g
1685 ngx-charts-axis-label
1686 *ngIf="showLabel"
1687 [label]="labelText"
1688 [offset]="labelOffset"
1689 [orient]="yOrient"
1690 [height]="dims.height"
1691 [width]="dims.width"
1692 ></svg:g>
1693 </svg:g>
1694 `,
1695 changeDetection: ChangeDetectionStrategy.OnPush
1696 },] }
1697];
1698YAxisComponent.propDecorators = {
1699 yScale: [{ type: Input }],
1700 dims: [{ type: Input }],
1701 trimTicks: [{ type: Input }],
1702 maxTickLength: [{ type: Input }],
1703 tickFormatting: [{ type: Input }],
1704 ticks: [{ type: Input }],
1705 showGridLines: [{ type: Input }],
1706 showLabel: [{ type: Input }],
1707 labelText: [{ type: Input }],
1708 yAxisTickCount: [{ type: Input }],
1709 yOrient: [{ type: Input }],
1710 referenceLines: [{ type: Input }],
1711 showRefLines: [{ type: Input }],
1712 showRefLabels: [{ type: Input }],
1713 yAxisOffset: [{ type: Input }],
1714 dimensionsChanged: [{ type: Output }],
1715 ticksComponent: [{ type: ViewChild, args: [YAxisTicksComponent,] }]
1716};
1717
1718class AxesModule {
1719}
1720AxesModule.decorators = [
1721 { type: NgModule, args: [{
1722 imports: [CommonModule],
1723 declarations: [AxisLabelComponent, XAxisComponent, XAxisTicksComponent, YAxisComponent, YAxisTicksComponent],
1724 exports: [AxisLabelComponent, XAxisComponent, XAxisTicksComponent, YAxisComponent, YAxisTicksComponent]
1725 },] }
1726];
1727
1728var StyleTypes;
1729(function (StyleTypes) {
1730 StyleTypes["popover"] = "popover";
1731 StyleTypes["tooltip"] = "tooltip";
1732})(StyleTypes || (StyleTypes = {}));
1733
1734var ShowTypes;
1735(function (ShowTypes) {
1736 ShowTypes[ShowTypes["all"] = 'all'] = "all";
1737 ShowTypes[ShowTypes["focus"] = 'focus'] = "focus";
1738 ShowTypes[ShowTypes["mouseover"] = 'mouseover'] = "mouseover";
1739})(ShowTypes || (ShowTypes = {}));
1740
1741class TooltipDirective {
1742 constructor(tooltipService, viewContainerRef, renderer) {
1743 this.tooltipService = tooltipService;
1744 this.viewContainerRef = viewContainerRef;
1745 this.renderer = renderer;
1746 this.tooltipCssClass = '';
1747 this.tooltipAppendToBody = true;
1748 this.tooltipSpacing = 10;
1749 this.tooltipDisabled = false;
1750 this.tooltipShowCaret = true;
1751 this.tooltipPlacement = PlacementTypes.Top;
1752 this.tooltipAlignment = PlacementTypes.Center;
1753 this.tooltipType = StyleTypes.popover;
1754 this.tooltipCloseOnClickOutside = true;
1755 this.tooltipCloseOnMouseLeave = true;
1756 this.tooltipHideTimeout = 300;
1757 this.tooltipShowTimeout = 100;
1758 this.tooltipShowEvent = ShowTypes.all;
1759 this.tooltipImmediateExit = false;
1760 this.show = new EventEmitter();
1761 this.hide = new EventEmitter();
1762 }
1763 get listensForFocus() {
1764 return this.tooltipShowEvent === ShowTypes.all || this.tooltipShowEvent === ShowTypes.focus;
1765 }
1766 get listensForHover() {
1767 return this.tooltipShowEvent === ShowTypes.all || this.tooltipShowEvent === ShowTypes.mouseover;
1768 }
1769 ngOnDestroy() {
1770 this.hideTooltip(true);
1771 }
1772 onFocus() {
1773 if (this.listensForFocus) {
1774 this.showTooltip();
1775 }
1776 }
1777 onBlur() {
1778 if (this.listensForFocus) {
1779 this.hideTooltip(true);
1780 }
1781 }
1782 onMouseEnter() {
1783 if (this.listensForHover) {
1784 this.showTooltip();
1785 }
1786 }
1787 onMouseLeave(target) {
1788 if (this.listensForHover && this.tooltipCloseOnMouseLeave) {
1789 clearTimeout(this.timeout);
1790 if (this.component) {
1791 const contentDom = this.component.instance.element.nativeElement;
1792 const contains = contentDom.contains(target);
1793 if (contains)
1794 return;
1795 }
1796 this.hideTooltip(this.tooltipImmediateExit);
1797 }
1798 }
1799 onMouseClick() {
1800 if (this.listensForHover) {
1801 this.hideTooltip(true);
1802 }
1803 }
1804 showTooltip(immediate) {
1805 if (this.component || this.tooltipDisabled)
1806 return;
1807 const time = immediate
1808 ? 0
1809 : this.tooltipShowTimeout + (navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) ? 300 : 0);
1810 clearTimeout(this.timeout);
1811 this.timeout = setTimeout(() => {
1812 this.tooltipService.destroyAll();
1813 const options = this.createBoundOptions();
1814 this.component = this.tooltipService.create(options);
1815 // add a tiny timeout to avoid event re-triggers
1816 setTimeout(() => {
1817 if (this.component) {
1818 this.addHideListeners(this.component.instance.element.nativeElement);
1819 }
1820 }, 10);
1821 this.show.emit(true);
1822 }, time);
1823 }
1824 addHideListeners(tooltip) {
1825 // on mouse enter, cancel the hide triggered by the leave
1826 this.mouseEnterContentEvent = this.renderer.listen(tooltip, 'mouseenter', () => {
1827 clearTimeout(this.timeout);
1828 });
1829 // content mouse leave listener
1830 if (this.tooltipCloseOnMouseLeave) {
1831 this.mouseLeaveContentEvent = this.renderer.listen(tooltip, 'mouseleave', () => {
1832 this.hideTooltip(this.tooltipImmediateExit);
1833 });
1834 }
1835 // content close on click outside
1836 if (this.tooltipCloseOnClickOutside) {
1837 this.documentClickEvent = this.renderer.listen('window', 'click', event => {
1838 const contains = tooltip.contains(event.target);
1839 if (!contains)
1840 this.hideTooltip();
1841 });
1842 }
1843 }
1844 hideTooltip(immediate = false) {
1845 if (!this.component)
1846 return;
1847 const destroyFn = () => {
1848 // remove events
1849 if (this.mouseLeaveContentEvent)
1850 this.mouseLeaveContentEvent();
1851 if (this.mouseEnterContentEvent)
1852 this.mouseEnterContentEvent();
1853 if (this.documentClickEvent)
1854 this.documentClickEvent();
1855 // emit events
1856 this.hide.emit(true);
1857 // destroy component
1858 this.tooltipService.destroy(this.component);
1859 this.component = undefined;
1860 };
1861 clearTimeout(this.timeout);
1862 if (!immediate) {
1863 this.timeout = setTimeout(destroyFn, this.tooltipHideTimeout);
1864 }
1865 else {
1866 destroyFn();
1867 }
1868 }
1869 createBoundOptions() {
1870 return {
1871 title: this.tooltipTitle,
1872 template: this.tooltipTemplate,
1873 host: this.viewContainerRef.element,
1874 placement: this.tooltipPlacement,
1875 alignment: this.tooltipAlignment,
1876 type: this.tooltipType,
1877 showCaret: this.tooltipShowCaret,
1878 cssClass: this.tooltipCssClass,
1879 spacing: this.tooltipSpacing,
1880 context: this.tooltipContext
1881 };
1882 }
1883}
1884TooltipDirective.decorators = [
1885 { type: Directive, args: [{ selector: '[ngx-tooltip]' },] }
1886];
1887TooltipDirective.ctorParameters = () => [
1888 { type: TooltipService },
1889 { type: ViewContainerRef },
1890 { type: Renderer2 }
1891];
1892TooltipDirective.propDecorators = {
1893 tooltipCssClass: [{ type: Input }],
1894 tooltipTitle: [{ type: Input }],
1895 tooltipAppendToBody: [{ type: Input }],
1896 tooltipSpacing: [{ type: Input }],
1897 tooltipDisabled: [{ type: Input }],
1898 tooltipShowCaret: [{ type: Input }],
1899 tooltipPlacement: [{ type: Input }],
1900 tooltipAlignment: [{ type: Input }],
1901 tooltipType: [{ type: Input }],
1902 tooltipCloseOnClickOutside: [{ type: Input }],
1903 tooltipCloseOnMouseLeave: [{ type: Input }],
1904 tooltipHideTimeout: [{ type: Input }],
1905 tooltipShowTimeout: [{ type: Input }],
1906 tooltipTemplate: [{ type: Input }],
1907 tooltipShowEvent: [{ type: Input }],
1908 tooltipContext: [{ type: Input }],
1909 tooltipImmediateExit: [{ type: Input }],
1910 show: [{ type: Output }],
1911 hide: [{ type: Output }],
1912 onFocus: [{ type: HostListener, args: ['focusin',] }],
1913 onBlur: [{ type: HostListener, args: ['blur',] }],
1914 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
1915 onMouseLeave: [{ type: HostListener, args: ['mouseleave', ['$event.target'],] }],
1916 onMouseClick: [{ type: HostListener, args: ['click',] }]
1917};
1918
1919class TooltipModule {
1920}
1921TooltipModule.decorators = [
1922 { type: NgModule, args: [{
1923 declarations: [TooltipContentComponent, TooltipDirective],
1924 providers: [InjectionService, TooltipService],
1925 exports: [TooltipContentComponent, TooltipDirective],
1926 imports: [CommonModule],
1927 entryComponents: [TooltipContentComponent]
1928 },] }
1929];
1930
1931/**
1932 * Formats a label given a date, number or string.
1933 *
1934 * @export
1935 */
1936function formatLabel(label) {
1937 if (label instanceof Date) {
1938 label = label.toLocaleDateString();
1939 }
1940 else {
1941 label = label.toLocaleString();
1942 }
1943 return label;
1944}
1945/**
1946 * Escapes a label.
1947 *
1948 * @export
1949 */
1950function escapeLabel(label) {
1951 return label.toLocaleString().replace(/[&'`"<>]/g, match => {
1952 return {
1953 '&': '&amp;',
1954 // tslint:disable-next-line: quotemark
1955 "'": '&#x27;',
1956 '`': '&#x60;',
1957 '"': '&quot;',
1958 '<': '&lt;',
1959 '>': '&gt;'
1960 }[match];
1961 });
1962}
1963
1964const cache = {};
1965/**
1966 * Generates a short id.
1967 *
1968 * Description:
1969 * A 4-character alphanumeric sequence (364 = 1.6 million)
1970 * This should only be used for JavaScript specific models.
1971 * http://stackoverflow.com/questions/6248666/how-to-generate-short-uid-like-ax4j9z-in-js
1972 *
1973 * Example: `ebgf`
1974 */
1975function id() {
1976 let newId = ('0000' + ((Math.random() * Math.pow(36, 4)) << 0).toString(36)).slice(-4);
1977 // append a 'a' because neo gets mad
1978 newId = `a${newId}`;
1979 // ensure not already used
1980 if (!cache[newId]) {
1981 cache[newId] = true;
1982 return newId;
1983 }
1984 return id();
1985}
1986
1987var BarOrientation;
1988(function (BarOrientation) {
1989 BarOrientation["Vertical"] = "vertical";
1990 BarOrientation["Horizontal"] = "horizontal";
1991})(BarOrientation || (BarOrientation = {}));
1992
1993var SeriesType;
1994(function (SeriesType) {
1995 SeriesType["Standard"] = "standard";
1996 SeriesType["Stacked"] = "stacked";
1997})(SeriesType || (SeriesType = {}));
1998class CircleSeriesComponent {
1999 constructor() {
2000 this.type = SeriesType.Standard;
2001 this.tooltipDisabled = false;
2002 this.select = new EventEmitter();
2003 this.activate = new EventEmitter();
2004 this.deactivate = new EventEmitter();
2005 this.barVisible = false;
2006 this.barOrientation = BarOrientation;
2007 this.placementTypes = PlacementTypes;
2008 this.styleTypes = StyleTypes;
2009 }
2010 ngOnInit() {
2011 this.gradientId = 'grad' + id().toString();
2012 this.gradientFill = `url(#${this.gradientId})`;
2013 }
2014 ngOnChanges() {
2015 this.update();
2016 }
2017 update() {
2018 this.circle = this.getActiveCircle();
2019 }
2020 getActiveCircle() {
2021 const indexActiveDataPoint = this.data.series.findIndex(d => {
2022 const label = d.name;
2023 return label && this.visibleValue && label.toString() === this.visibleValue.toString() && d.value !== undefined;
2024 });
2025 if (indexActiveDataPoint === -1) {
2026 // No valid point is 'active/hovered over' at this moment.
2027 return undefined;
2028 }
2029 return this.mapDataPointToCircle(this.data.series[indexActiveDataPoint], indexActiveDataPoint);
2030 }
2031 mapDataPointToCircle(d, i) {
2032 const seriesName = this.data.name;
2033 const value = d.value;
2034 const label = d.name;
2035 const tooltipLabel = formatLabel(label);
2036 let cx;
2037 if (this.scaleType === ScaleType.Time) {
2038 cx = this.xScale(label);
2039 }
2040 else if (this.scaleType === ScaleType.Linear) {
2041 cx = this.xScale(Number(label));
2042 }
2043 else {
2044 cx = this.xScale(label);
2045 }
2046 const cy = this.yScale(this.type === SeriesType.Standard ? value : d.d1);
2047 const radius = 5;
2048 const height = this.yScale.range()[0] - cy;
2049 const opacity = 1;
2050 let color;
2051 if (this.colors.scaleType === ScaleType.Linear) {
2052 if (this.type === SeriesType.Standard) {
2053 color = this.colors.getColor(value);
2054 }
2055 else {
2056 color = this.colors.getColor(d.d1);
2057 }
2058 }
2059 else {
2060 color = this.colors.getColor(seriesName);
2061 }
2062 const data = Object.assign({}, d, {
2063 series: seriesName,
2064 value,
2065 name: label
2066 });
2067 return {
2068 classNames: [`circle-data-${i}`],
2069 value,
2070 label,
2071 data,
2072 cx,
2073 cy,
2074 radius,
2075 height,
2076 tooltipLabel,
2077 color,
2078 opacity,
2079 seriesName,
2080 gradientStops: this.getGradientStops(color),
2081 min: d.min,
2082 max: d.max
2083 };
2084 }
2085 getTooltipText({ tooltipLabel, value, seriesName, min, max }) {
2086 return `
2087 <span class="tooltip-label">${escapeLabel(seriesName)}${escapeLabel(tooltipLabel)}</span>
2088 <span class="tooltip-val">${value.toLocaleString()}${this.getTooltipMinMaxText(min, max)}</span>
2089 `;
2090 }
2091 getTooltipMinMaxText(min, max) {
2092 if (min !== undefined || max !== undefined) {
2093 let result = ' (';
2094 if (min !== undefined) {
2095 if (max === undefined) {
2096 result += '≥';
2097 }
2098 result += min.toLocaleString();
2099 if (max !== undefined) {
2100 result += ' - ';
2101 }
2102 }
2103 else if (max !== undefined) {
2104 result += '≤';
2105 }
2106 if (max !== undefined) {
2107 result += max.toLocaleString();
2108 }
2109 result += ')';
2110 return result;
2111 }
2112 else {
2113 return '';
2114 }
2115 }
2116 getGradientStops(color) {
2117 return [
2118 {
2119 offset: 0,
2120 color,
2121 opacity: 0.2
2122 },
2123 {
2124 offset: 100,
2125 color,
2126 opacity: 1
2127 }
2128 ];
2129 }
2130 onClick(data) {
2131 this.select.emit(data);
2132 }
2133 isActive(entry) {
2134 if (!this.activeEntries)
2135 return false;
2136 const item = this.activeEntries.find(d => {
2137 return entry.name === d.name;
2138 });
2139 return item !== undefined;
2140 }
2141 activateCircle() {
2142 this.barVisible = true;
2143 this.activate.emit({ name: this.data.name });
2144 }
2145 deactivateCircle() {
2146 this.barVisible = false;
2147 this.circle.opacity = 0;
2148 this.deactivate.emit({ name: this.data.name });
2149 }
2150}
2151CircleSeriesComponent.decorators = [
2152 { type: Component, args: [{
2153 selector: 'g[ngx-charts-circle-series]',
2154 template: `
2155 <svg:g *ngIf="circle">
2156 <defs>
2157 <svg:g
2158 ngx-charts-svg-linear-gradient
2159 [orientation]="barOrientation.Vertical"
2160 [name]="gradientId"
2161 [stops]="circle.gradientStops"
2162 />
2163 </defs>
2164 <svg:rect
2165 *ngIf="barVisible && type === 'standard'"
2166 [@animationState]="'active'"
2167 [attr.x]="circle.cx - circle.radius"
2168 [attr.y]="circle.cy"
2169 [attr.width]="circle.radius * 2"
2170 [attr.height]="circle.height"
2171 [attr.fill]="gradientFill"
2172 class="tooltip-bar"
2173 />
2174 <svg:g
2175 ngx-charts-circle
2176 class="circle"
2177 [cx]="circle.cx"
2178 [cy]="circle.cy"
2179 [r]="circle.radius"
2180 [fill]="circle.color"
2181 [class.active]="isActive({ name: circle.seriesName })"
2182 [pointerEvents]="circle.value === 0 ? 'none' : 'all'"
2183 [data]="circle.value"
2184 [classNames]="circle.classNames"
2185 (select)="onClick(circle.data)"
2186 (activate)="activateCircle()"
2187 (deactivate)="deactivateCircle()"
2188 ngx-tooltip
2189 [tooltipDisabled]="tooltipDisabled"
2190 [tooltipPlacement]="placementTypes.Top"
2191 [tooltipType]="styleTypes.tooltip"
2192 [tooltipTitle]="tooltipTemplate ? undefined : getTooltipText(circle)"
2193 [tooltipTemplate]="tooltipTemplate"
2194 [tooltipContext]="circle.data"
2195 />
2196 </svg:g>
2197 `,
2198 changeDetection: ChangeDetectionStrategy.OnPush,
2199 animations: [
2200 trigger('animationState', [
2201 transition(':enter', [
2202 style({
2203 opacity: 0
2204 }),
2205 animate(250, style({ opacity: 1 }))
2206 ])
2207 ])
2208 ]
2209 },] }
2210];
2211CircleSeriesComponent.propDecorators = {
2212 data: [{ type: Input }],
2213 type: [{ type: Input }],
2214 xScale: [{ type: Input }],
2215 yScale: [{ type: Input }],
2216 colors: [{ type: Input }],
2217 scaleType: [{ type: Input }],
2218 visibleValue: [{ type: Input }],
2219 activeEntries: [{ type: Input }],
2220 tooltipDisabled: [{ type: Input }],
2221 tooltipTemplate: [{ type: Input }],
2222 select: [{ type: Output }],
2223 activate: [{ type: Output }],
2224 deactivate: [{ type: Output }]
2225};
2226
2227class CircleComponent {
2228 constructor() {
2229 this.select = new EventEmitter();
2230 this.activate = new EventEmitter();
2231 this.deactivate = new EventEmitter();
2232 }
2233 onClick() {
2234 this.select.emit(this.data);
2235 }
2236 onMouseEnter() {
2237 this.activate.emit(this.data);
2238 }
2239 onMouseLeave() {
2240 this.deactivate.emit(this.data);
2241 }
2242 ngOnChanges(changes) {
2243 this.classNames = Array.isArray(this.classNames) ? this.classNames.join(' ') : '';
2244 this.classNames += 'circle';
2245 }
2246}
2247CircleComponent.decorators = [
2248 { type: Component, args: [{
2249 selector: 'g[ngx-charts-circle]',
2250 template: `
2251 <svg:circle
2252 [attr.cx]="cx"
2253 [attr.cy]="cy"
2254 [attr.r]="r"
2255 [attr.fill]="fill"
2256 [attr.stroke]="stroke"
2257 [attr.opacity]="circleOpacity"
2258 [attr.class]="classNames"
2259 [attr.pointer-events]="pointerEvents"
2260 />
2261 `,
2262 changeDetection: ChangeDetectionStrategy.OnPush
2263 },] }
2264];
2265CircleComponent.propDecorators = {
2266 cx: [{ type: Input }],
2267 cy: [{ type: Input }],
2268 r: [{ type: Input }],
2269 fill: [{ type: Input }],
2270 stroke: [{ type: Input }],
2271 data: [{ type: Input }],
2272 classNames: [{ type: Input }],
2273 circleOpacity: [{ type: Input }],
2274 pointerEvents: [{ type: Input }],
2275 select: [{ type: Output }],
2276 activate: [{ type: Output }],
2277 deactivate: [{ type: Output }],
2278 onClick: [{ type: HostListener, args: ['click',] }],
2279 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
2280 onMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
2281};
2282
2283class GridPanelComponent {
2284}
2285GridPanelComponent.decorators = [
2286 { type: Component, args: [{
2287 selector: 'g[ngx-charts-grid-panel]',
2288 template: `
2289 <svg:rect [attr.height]="height" [attr.width]="width" [attr.x]="x" [attr.y]="y" stroke="none" class="gridpanel" />
2290 `,
2291 changeDetection: ChangeDetectionStrategy.OnPush
2292 },] }
2293];
2294GridPanelComponent.propDecorators = {
2295 width: [{ type: Input }],
2296 height: [{ type: Input }],
2297 x: [{ type: Input }],
2298 y: [{ type: Input }]
2299};
2300
2301var ClassEnum;
2302(function (ClassEnum) {
2303 ClassEnum["Odd"] = "odd";
2304 ClassEnum["Even"] = "even";
2305})(ClassEnum || (ClassEnum = {}));
2306class GridPanelSeriesComponent {
2307 ngOnChanges(changes) {
2308 this.update();
2309 }
2310 update() {
2311 this.gridPanels = this.getGridPanels();
2312 }
2313 getGridPanels() {
2314 return this.data.map(d => {
2315 let offset;
2316 let width;
2317 let height;
2318 let x;
2319 let y;
2320 let className = ClassEnum.Odd;
2321 if (this.orient === BarOrientation.Vertical) {
2322 const position = this.xScale(d.name);
2323 const positionIndex = Number.parseInt((position / this.xScale.step()).toString(), 10);
2324 if (positionIndex % 2 === 1) {
2325 className = ClassEnum.Even;
2326 }
2327 offset = this.xScale.bandwidth() * this.xScale.paddingInner();
2328 width = this.xScale.bandwidth() + offset;
2329 height = this.dims.height;
2330 x = this.xScale(d.name) - offset / 2;
2331 y = 0;
2332 }
2333 else if (this.orient === BarOrientation.Horizontal) {
2334 const position = this.yScale(d.name);
2335 const positionIndex = Number.parseInt((position / this.yScale.step()).toString(), 10);
2336 if (positionIndex % 2 === 1) {
2337 className = ClassEnum.Even;
2338 }
2339 offset = this.yScale.bandwidth() * this.yScale.paddingInner();
2340 width = this.dims.width;
2341 height = this.yScale.bandwidth() + offset;
2342 x = 0;
2343 y = this.yScale(d.name) - offset / 2;
2344 }
2345 return {
2346 name: d.name,
2347 class: className,
2348 height,
2349 width,
2350 x,
2351 y
2352 };
2353 });
2354 }
2355}
2356GridPanelSeriesComponent.decorators = [
2357 { type: Component, args: [{
2358 selector: 'g[ngx-charts-grid-panel-series]',
2359 template: `
2360 <svg:g
2361 ngx-charts-grid-panel
2362 *ngFor="let gridPanel of gridPanels"
2363 [height]="gridPanel.height"
2364 [width]="gridPanel.width"
2365 [x]="gridPanel.x"
2366 [y]="gridPanel.y"
2367 [class.grid-panel]="true"
2368 [class.odd]="gridPanel.class === 'odd'"
2369 [class.even]="gridPanel.class === 'even'"
2370 ></svg:g>
2371 `,
2372 changeDetection: ChangeDetectionStrategy.OnPush
2373 },] }
2374];
2375GridPanelSeriesComponent.propDecorators = {
2376 data: [{ type: Input }],
2377 dims: [{ type: Input }],
2378 xScale: [{ type: Input }],
2379 yScale: [{ type: Input }],
2380 orient: [{ type: Input }]
2381};
2382
2383class SvgLinearGradientComponent {
2384 constructor() {
2385 this.orientation = BarOrientation.Vertical;
2386 }
2387 ngOnChanges(changes) {
2388 this.x1 = '0%';
2389 this.x2 = '0%';
2390 this.y1 = '0%';
2391 this.y2 = '0%';
2392 if (this.orientation === BarOrientation.Horizontal) {
2393 this.x2 = '100%';
2394 }
2395 else if (this.orientation === BarOrientation.Vertical) {
2396 this.y1 = '100%';
2397 }
2398 }
2399}
2400SvgLinearGradientComponent.decorators = [
2401 { type: Component, args: [{
2402 selector: 'g[ngx-charts-svg-linear-gradient]',
2403 template: `
2404 <svg:linearGradient [id]="name" [attr.x1]="x1" [attr.y1]="y1" [attr.x2]="x2" [attr.y2]="y2">
2405 <svg:stop
2406 *ngFor="let stop of stops"
2407 [attr.offset]="stop.offset + '%'"
2408 [style.stop-color]="stop.color"
2409 [style.stop-opacity]="stop.opacity"
2410 />
2411 </svg:linearGradient>
2412 `,
2413 changeDetection: ChangeDetectionStrategy.OnPush
2414 },] }
2415];
2416SvgLinearGradientComponent.propDecorators = {
2417 orientation: [{ type: Input }],
2418 name: [{ type: Input }],
2419 stops: [{ type: Input }]
2420};
2421
2422class SvgRadialGradientComponent {
2423 constructor() {
2424 this.endOpacity = 1;
2425 this.cx = 0;
2426 this.cy = 0;
2427 }
2428 get stops() {
2429 return this.stopsInput || this.stopsDefault;
2430 }
2431 set stops(value) {
2432 this.stopsInput = value;
2433 }
2434 ngOnChanges(changes) {
2435 this.r = '30%';
2436 if ('color' in changes || 'startOpacity' in changes || 'endOpacity' in changes) {
2437 this.stopsDefault = [
2438 {
2439 offset: 0,
2440 color: this.color,
2441 opacity: this.startOpacity
2442 },
2443 {
2444 offset: 100,
2445 color: this.color,
2446 opacity: this.endOpacity
2447 }
2448 ];
2449 }
2450 }
2451}
2452SvgRadialGradientComponent.decorators = [
2453 { type: Component, args: [{
2454 selector: 'g[ngx-charts-svg-radial-gradient]',
2455 template: `
2456 <svg:radialGradient [id]="name" [attr.cx]="cx" [attr.cy]="cy" [attr.r]="r" gradientUnits="userSpaceOnUse">
2457 <svg:stop
2458 *ngFor="let stop of stops"
2459 [attr.offset]="stop.offset + '%'"
2460 [style.stop-color]="stop.color"
2461 [style.stop-opacity]="stop.opacity"
2462 />
2463 </svg:radialGradient>
2464 `,
2465 changeDetection: ChangeDetectionStrategy.OnPush
2466 },] }
2467];
2468SvgRadialGradientComponent.propDecorators = {
2469 color: [{ type: Input }],
2470 name: [{ type: Input }],
2471 startOpacity: [{ type: Input }],
2472 endOpacity: [{ type: Input }],
2473 cx: [{ type: Input }],
2474 cy: [{ type: Input }],
2475 stops: [{ type: Input }]
2476};
2477
2478class AreaComponent {
2479 constructor(element) {
2480 this.opacity = 1;
2481 this.startOpacity = 0.5;
2482 this.endOpacity = 1;
2483 this.gradient = false;
2484 this.animations = true;
2485 this.select = new EventEmitter();
2486 this.animationsLoaded = false;
2487 this.hasGradient = false;
2488 this.barOrientation = BarOrientation;
2489 this.element = element.nativeElement;
2490 }
2491 ngOnChanges() {
2492 this.update();
2493 if (!this.animationsLoaded) {
2494 this.loadAnimation();
2495 this.animationsLoaded = true;
2496 }
2497 }
2498 update() {
2499 this.gradientId = 'grad' + id().toString();
2500 this.gradientFill = `url(#${this.gradientId})`;
2501 if (this.gradient || this.stops) {
2502 this.gradientStops = this.getGradient();
2503 this.hasGradient = true;
2504 }
2505 else {
2506 this.hasGradient = false;
2507 }
2508 this.updatePathEl();
2509 }
2510 loadAnimation() {
2511 this.areaPath = this.startingPath;
2512 setTimeout(this.updatePathEl.bind(this), 100);
2513 }
2514 updatePathEl() {
2515 const node = select(this.element).select('.area');
2516 if (this.animations) {
2517 node.transition().duration(750).attr('d', this.path);
2518 }
2519 else {
2520 node.attr('d', this.path);
2521 }
2522 }
2523 getGradient() {
2524 if (this.stops) {
2525 return this.stops;
2526 }
2527 return [
2528 {
2529 offset: 0,
2530 color: this.fill,
2531 opacity: this.startOpacity
2532 },
2533 {
2534 offset: 100,
2535 color: this.fill,
2536 opacity: this.endOpacity
2537 }
2538 ];
2539 }
2540}
2541AreaComponent.decorators = [
2542 { type: Component, args: [{
2543 selector: 'g[ngx-charts-area]',
2544 template: `
2545 <svg:defs *ngIf="gradient">
2546 <svg:g
2547 ngx-charts-svg-linear-gradient
2548 [orientation]="barOrientation.Vertical"
2549 [name]="gradientId"
2550 [stops]="gradientStops"
2551 />
2552 </svg:defs>
2553 <svg:path class="area" [attr.d]="areaPath" [attr.fill]="gradient ? gradientFill : fill" [style.opacity]="opacity" />
2554 `,
2555 changeDetection: ChangeDetectionStrategy.OnPush
2556 },] }
2557];
2558AreaComponent.ctorParameters = () => [
2559 { type: ElementRef }
2560];
2561AreaComponent.propDecorators = {
2562 data: [{ type: Input }],
2563 path: [{ type: Input }],
2564 startingPath: [{ type: Input }],
2565 fill: [{ type: Input }],
2566 opacity: [{ type: Input }],
2567 startOpacity: [{ type: Input }],
2568 endOpacity: [{ type: Input }],
2569 gradient: [{ type: Input }],
2570 stops: [{ type: Input }],
2571 animations: [{ type: Input }],
2572 select: [{ type: Output }]
2573};
2574
2575// Robert Penner's easeOutExpo
2576function easeOutExpo(t, b, c, d) {
2577 return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
2578}
2579/**
2580 * Counts from a number to the end incrementally.
2581 */
2582function count(countFrom, countTo, countDecimals, countDuration, callback) {
2583 const startVal = Number(countFrom);
2584 const endVal = Number(countTo);
2585 const countDown = startVal > endVal;
2586 const decimals = Math.max(0, countDecimals);
2587 const dec = Math.pow(10, decimals);
2588 const duration = Number(countDuration) * 1000;
2589 let startTime;
2590 function runCount(timestamp) {
2591 let frameVal;
2592 const progress = timestamp - startTime;
2593 if (countDown) {
2594 frameVal = startVal - easeOutExpo(progress, 0, startVal - endVal, duration);
2595 }
2596 else {
2597 frameVal = easeOutExpo(progress, startVal, endVal - startVal, duration);
2598 }
2599 if (countDown) {
2600 frameVal = frameVal < endVal ? endVal : frameVal;
2601 }
2602 else {
2603 frameVal = frameVal > endVal ? endVal : frameVal;
2604 }
2605 frameVal = Math.round(frameVal * dec) / dec;
2606 const tick = progress < duration;
2607 callback({
2608 value: frameVal,
2609 progress,
2610 timestamp,
2611 finished: !tick
2612 });
2613 if (tick) {
2614 return requestAnimationFrame(val => runCount(val));
2615 }
2616 }
2617 return requestAnimationFrame(timestamp => {
2618 startTime = timestamp;
2619 return runCount(timestamp);
2620 });
2621}
2622/**
2623 * Determine decimals places
2624 *
2625 * @export
2626 */
2627function decimalChecker(countTo) {
2628 const endVal = Number(countTo);
2629 if (endVal % 1 !== 0 && Math.abs(endVal) <= 10) {
2630 return 2;
2631 }
2632 return 0;
2633}
2634
2635/**
2636 * Count up component
2637 *
2638 * Loosely inspired by:
2639 * - https://github.com/izupet/angular2-counto
2640 * - https://inorganik.github.io/countUp.js/
2641 *
2642 * @export
2643 */
2644class CountUpDirective {
2645 constructor(cd, element) {
2646 this.cd = cd;
2647 this.countDuration = 1;
2648 this.countPrefix = '';
2649 this.countSuffix = '';
2650 this.countChange = new EventEmitter();
2651 this.countFinish = new EventEmitter();
2652 this.value = '';
2653 this._countDecimals = 0;
2654 this._countTo = 0;
2655 this._countFrom = 0;
2656 this.nativeElement = element.nativeElement;
2657 }
2658 set countDecimals(val) {
2659 this._countDecimals = val;
2660 }
2661 get countDecimals() {
2662 if (this._countDecimals)
2663 return this._countDecimals;
2664 return decimalChecker(this.countTo);
2665 }
2666 set countTo(val) {
2667 this._countTo = parseFloat(val);
2668 this.start();
2669 }
2670 get countTo() {
2671 return this._countTo;
2672 }
2673 set countFrom(val) {
2674 this._countFrom = parseFloat(val);
2675 this.start();
2676 }
2677 get countFrom() {
2678 return this._countFrom;
2679 }
2680 ngOnDestroy() {
2681 cancelAnimationFrame(this.animationReq);
2682 }
2683 start() {
2684 cancelAnimationFrame(this.animationReq);
2685 const valueFormatting = this.valueFormatting || (value => `${this.countPrefix}${value.toLocaleString()}${this.countSuffix}`);
2686 const callback = ({ value, progress, finished }) => {
2687 this.value = valueFormatting(value);
2688 this.cd.markForCheck();
2689 if (!finished)
2690 this.countChange.emit({ value: this.value, progress });
2691 if (finished)
2692 this.countFinish.emit({ value: this.value, progress });
2693 };
2694 this.animationReq = count(this.countFrom, this.countTo, this.countDecimals, this.countDuration, callback);
2695 }
2696}
2697CountUpDirective.decorators = [
2698 { type: Component, args: [{
2699 selector: '[ngx-charts-count-up]',
2700 template: ` {{ value }} `
2701 },] }
2702];
2703CountUpDirective.ctorParameters = () => [
2704 { type: ChangeDetectorRef },
2705 { type: ElementRef }
2706];
2707CountUpDirective.propDecorators = {
2708 countDuration: [{ type: Input }],
2709 countPrefix: [{ type: Input }],
2710 countSuffix: [{ type: Input }],
2711 valueFormatting: [{ type: Input }],
2712 countDecimals: [{ type: Input }],
2713 countTo: [{ type: Input }],
2714 countFrom: [{ type: Input }],
2715 countChange: [{ type: Output }],
2716 countFinish: [{ type: Output }]
2717};
2718
2719// If we don't check whether 'window' and 'global' variables are defined,
2720// code will fail in browser/node with 'variable is undefined' error.
2721let root;
2722if (typeof window !== 'undefined') {
2723 root = window;
2724}
2725else if (typeof global !== 'undefined') {
2726 root = global;
2727}
2728// tslint:disable-next-line:variable-name
2729const MouseEvent = root.MouseEvent;
2730function createMouseEvent(name, bubbles = false, cancelable = true) {
2731 // Calling new of an event does not work correctly on IE. The following is a tested workaround
2732 // See https://stackoverflow.com/questions/27176983/dispatchevent-not-working-in-ie11
2733 if (typeof MouseEvent === 'function') {
2734 // Sane browsers
2735 return new MouseEvent(name, { bubbles, cancelable });
2736 }
2737 else {
2738 // IE
2739 const event = document.createEvent('MouseEvent');
2740 event.initEvent(name, bubbles, cancelable);
2741 return event;
2742 }
2743}
2744
2745class TooltipArea {
2746 constructor(platformId) {
2747 this.platformId = platformId;
2748 this.anchorOpacity = 0;
2749 this.anchorPos = -1;
2750 this.anchorValues = [];
2751 this.placementTypes = PlacementTypes;
2752 this.styleTypes = StyleTypes;
2753 this.showPercentage = false;
2754 this.tooltipDisabled = false;
2755 this.hover = new EventEmitter();
2756 }
2757 getValues(xVal) {
2758 const results = [];
2759 for (const group of this.results) {
2760 const item = group.series.find(d => d.name.toString() === xVal.toString());
2761 let groupName = group.name;
2762 if (groupName instanceof Date) {
2763 groupName = groupName.toLocaleDateString();
2764 }
2765 if (item) {
2766 const label = item.name;
2767 let val = item.value;
2768 if (this.showPercentage) {
2769 val = (item.d1 - item.d0).toFixed(2) + '%';
2770 }
2771 let color;
2772 if (this.colors.scaleType === ScaleType.Linear) {
2773 let v = val;
2774 if (item.d1) {
2775 v = item.d1;
2776 }
2777 color = this.colors.getColor(v);
2778 }
2779 else {
2780 color = this.colors.getColor(group.name);
2781 }
2782 const data = Object.assign({}, item, {
2783 value: val,
2784 name: label,
2785 series: groupName,
2786 min: item.min,
2787 max: item.max,
2788 color
2789 });
2790 results.push(data);
2791 }
2792 }
2793 return results;
2794 }
2795 mouseMove(event) {
2796 if (!isPlatformBrowser(this.platformId)) {
2797 return;
2798 }
2799 const xPos = event.pageX - event.target.getBoundingClientRect().left;
2800 const closestIndex = this.findClosestPointIndex(xPos);
2801 const closestPoint = this.xSet[closestIndex];
2802 this.anchorPos = this.xScale(closestPoint);
2803 this.anchorPos = Math.max(0, this.anchorPos);
2804 this.anchorPos = Math.min(this.dims.width, this.anchorPos);
2805 this.anchorValues = this.getValues(closestPoint);
2806 if (this.anchorPos !== this.lastAnchorPos) {
2807 const ev = createMouseEvent('mouseleave');
2808 this.tooltipAnchor.nativeElement.dispatchEvent(ev);
2809 this.anchorOpacity = 0.7;
2810 this.hover.emit({
2811 value: closestPoint
2812 });
2813 this.showTooltip();
2814 this.lastAnchorPos = this.anchorPos;
2815 }
2816 }
2817 findClosestPointIndex(xPos) {
2818 let minIndex = 0;
2819 let maxIndex = this.xSet.length - 1;
2820 let minDiff = Number.MAX_VALUE;
2821 let closestIndex = 0;
2822 while (minIndex <= maxIndex) {
2823 const currentIndex = ((minIndex + maxIndex) / 2) | 0;
2824 const currentElement = this.xScale(this.xSet[currentIndex]);
2825 const curDiff = Math.abs(currentElement - xPos);
2826 if (curDiff < minDiff) {
2827 minDiff = curDiff;
2828 closestIndex = currentIndex;
2829 }
2830 if (currentElement < xPos) {
2831 minIndex = currentIndex + 1;
2832 }
2833 else if (currentElement > xPos) {
2834 maxIndex = currentIndex - 1;
2835 }
2836 else {
2837 minDiff = 0;
2838 closestIndex = currentIndex;
2839 break;
2840 }
2841 }
2842 return closestIndex;
2843 }
2844 showTooltip() {
2845 const event = createMouseEvent('mouseenter');
2846 this.tooltipAnchor.nativeElement.dispatchEvent(event);
2847 }
2848 hideTooltip() {
2849 const event = createMouseEvent('mouseleave');
2850 this.tooltipAnchor.nativeElement.dispatchEvent(event);
2851 this.anchorOpacity = 0;
2852 this.lastAnchorPos = -1;
2853 }
2854 getToolTipText(tooltipItem) {
2855 let result = '';
2856 if (tooltipItem.series !== undefined) {
2857 result += tooltipItem.series;
2858 }
2859 else {
2860 result += '???';
2861 }
2862 result += ': ';
2863 if (tooltipItem.value !== undefined) {
2864 result += tooltipItem.value.toLocaleString();
2865 }
2866 if (tooltipItem.min !== undefined || tooltipItem.max !== undefined) {
2867 result += ' (';
2868 if (tooltipItem.min !== undefined) {
2869 if (tooltipItem.max === undefined) {
2870 result += '≥';
2871 }
2872 result += tooltipItem.min.toLocaleString();
2873 if (tooltipItem.max !== undefined) {
2874 result += ' - ';
2875 }
2876 }
2877 else if (tooltipItem.max !== undefined) {
2878 result += '≤';
2879 }
2880 if (tooltipItem.max !== undefined) {
2881 result += tooltipItem.max.toLocaleString();
2882 }
2883 result += ')';
2884 }
2885 return result;
2886 }
2887}
2888TooltipArea.decorators = [
2889 { type: Component, args: [{
2890 selector: 'g[ngx-charts-tooltip-area]',
2891 template: `
2892 <svg:g>
2893 <svg:rect
2894 class="tooltip-area"
2895 [attr.x]="0"
2896 y="0"
2897 [attr.width]="dims.width"
2898 [attr.height]="dims.height"
2899 style="opacity: 0; cursor: 'auto';"
2900 (mousemove)="mouseMove($event)"
2901 (mouseleave)="hideTooltip()"
2902 />
2903 <ng-template #defaultTooltipTemplate let-model="model">
2904 <xhtml:div class="area-tooltip-container">
2905 <xhtml:div *ngFor="let tooltipItem of model" class="tooltip-item">
2906 <xhtml:span class="tooltip-item-color" [style.background-color]="tooltipItem.color"></xhtml:span>
2907 {{ getToolTipText(tooltipItem) }}
2908 </xhtml:div>
2909 </xhtml:div>
2910 </ng-template>
2911 <svg:rect
2912 #tooltipAnchor
2913 [@animationState]="anchorOpacity !== 0 ? 'active' : 'inactive'"
2914 class="tooltip-anchor"
2915 [attr.x]="anchorPos"
2916 y="0"
2917 [attr.width]="1"
2918 [attr.height]="dims.height"
2919 [style.opacity]="anchorOpacity"
2920 [style.pointer-events]="'none'"
2921 ngx-tooltip
2922 [tooltipDisabled]="tooltipDisabled"
2923 [tooltipPlacement]="placementTypes.Right"
2924 [tooltipType]="styleTypes.tooltip"
2925 [tooltipSpacing]="15"
2926 [tooltipTemplate]="tooltipTemplate ? tooltipTemplate : defaultTooltipTemplate"
2927 [tooltipContext]="anchorValues"
2928 [tooltipImmediateExit]="true"
2929 />
2930 </svg:g>
2931 `,
2932 changeDetection: ChangeDetectionStrategy.OnPush,
2933 animations: [
2934 trigger('animationState', [
2935 transition('inactive => active', [
2936 style({
2937 opacity: 0
2938 }),
2939 animate(250, style({ opacity: 0.7 }))
2940 ]),
2941 transition('active => inactive', [
2942 style({
2943 opacity: 0.7
2944 }),
2945 animate(250, style({ opacity: 0 }))
2946 ])
2947 ])
2948 ]
2949 },] }
2950];
2951TooltipArea.ctorParameters = () => [
2952 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
2953];
2954TooltipArea.propDecorators = {
2955 dims: [{ type: Input }],
2956 xSet: [{ type: Input }],
2957 xScale: [{ type: Input }],
2958 yScale: [{ type: Input }],
2959 results: [{ type: Input }],
2960 colors: [{ type: Input }],
2961 showPercentage: [{ type: Input }],
2962 tooltipDisabled: [{ type: Input }],
2963 tooltipTemplate: [{ type: Input }],
2964 hover: [{ type: Output }],
2965 tooltipAnchor: [{ type: ViewChild, args: ['tooltipAnchor', { static: false },] }]
2966};
2967
2968class Timeline {
2969 constructor(element, cd) {
2970 this.cd = cd;
2971 this.height = 50;
2972 this.select = new EventEmitter();
2973 this.onDomainChange = new EventEmitter();
2974 this.initialized = false;
2975 this.element = element.nativeElement;
2976 }
2977 ngOnChanges(changes) {
2978 this.update();
2979 if (!this.initialized) {
2980 this.addBrush();
2981 this.initialized = true;
2982 }
2983 }
2984 update() {
2985 this.dims = this.getDims();
2986 this.height = this.dims.height;
2987 const offsetY = this.view[1] - this.height;
2988 this.xDomain = this.getXDomain();
2989 this.xScale = this.getXScale();
2990 if (this.brush) {
2991 this.updateBrush();
2992 }
2993 this.transform = `translate(0 , ${offsetY})`;
2994 this.filterId = 'filter' + id().toString();
2995 this.filter = `url(#${this.filterId})`;
2996 this.cd.markForCheck();
2997 }
2998 getXDomain() {
2999 let values = [];
3000 for (const results of this.results) {
3001 for (const d of results.series) {
3002 if (!values.includes(d.name)) {
3003 values.push(d.name);
3004 }
3005 }
3006 }
3007 let domain = [];
3008 if (this.scaleType === ScaleType.Time) {
3009 const min = Math.min(...values);
3010 const max = Math.max(...values);
3011 domain = [min, max];
3012 }
3013 else if (this.scaleType === ScaleType.Linear) {
3014 values = values.map(v => Number(v));
3015 const min = Math.min(...values);
3016 const max = Math.max(...values);
3017 domain = [min, max];
3018 }
3019 else {
3020 domain = values;
3021 }
3022 return domain;
3023 }
3024 getXScale() {
3025 let scale;
3026 if (this.scaleType === ScaleType.Time) {
3027 scale = scaleTime().range([0, this.dims.width]).domain(this.xDomain);
3028 }
3029 else if (this.scaleType === ScaleType.Linear) {
3030 scale = scaleLinear().range([0, this.dims.width]).domain(this.xDomain);
3031 }
3032 else if (this.scaleType === ScaleType.Ordinal) {
3033 scale = scalePoint().range([0, this.dims.width]).padding(0.1).domain(this.xDomain);
3034 }
3035 return scale;
3036 }
3037 addBrush() {
3038 if (this.brush)
3039 return;
3040 const height = this.height;
3041 const width = this.view[0];
3042 this.brush = brushX()
3043 .extent([
3044 [0, 0],
3045 [width, height]
3046 ])
3047 .on('brush end', ({ selection }) => {
3048 const newSelection = selection || this.xScale.range();
3049 const newDomain = newSelection.map(this.xScale.invert);
3050 this.onDomainChange.emit(newDomain);
3051 this.cd.markForCheck();
3052 });
3053 select(this.element).select('.brush').call(this.brush);
3054 }
3055 updateBrush() {
3056 if (!this.brush)
3057 return;
3058 const height = this.height;
3059 const width = this.view[0];
3060 this.brush.extent([
3061 [0, 0],
3062 [width, height]
3063 ]);
3064 select(this.element).select('.brush').call(this.brush);
3065 // clear hardcoded properties so they can be defined by CSS
3066 select(this.element)
3067 .select('.selection')
3068 .attr('fill', undefined)
3069 .attr('stroke', undefined)
3070 .attr('fill-opacity', undefined);
3071 this.cd.markForCheck();
3072 }
3073 getDims() {
3074 const width = this.view[0];
3075 const dims = {
3076 width,
3077 height: this.height
3078 };
3079 return dims;
3080 }
3081}
3082Timeline.decorators = [
3083 { type: Component, args: [{
3084 selector: 'g[ngx-charts-timeline]',
3085 template: `
3086 <svg:g class="timeline" [attr.transform]="transform">
3087 <svg:filter [attr.id]="filterId">
3088 <svg:feColorMatrix
3089 in="SourceGraphic"
3090 type="matrix"
3091 values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"
3092 />
3093 </svg:filter>
3094 <svg:g class="embedded-chart">
3095 <ng-content></ng-content>
3096 </svg:g>
3097 <svg:rect x="0" [attr.width]="view[0]" y="0" [attr.height]="height" class="brush-background" />
3098 <svg:g class="brush"></svg:g>
3099 </svg:g>
3100 `,
3101 encapsulation: ViewEncapsulation.None,
3102 changeDetection: ChangeDetectionStrategy.OnPush,
3103 styles: [".timeline .brush-background{fill:#0000000d}.timeline .brush .selection{fill:#0000001a;stroke-width:1px;stroke:#888}.timeline .brush .handle{fill-opacity:0}.timeline .embedded-chart{opacity:.6}\n"]
3104 },] }
3105];
3106Timeline.ctorParameters = () => [
3107 { type: ElementRef },
3108 { type: ChangeDetectorRef }
3109];
3110Timeline.propDecorators = {
3111 view: [{ type: Input }],
3112 results: [{ type: Input }],
3113 scheme: [{ type: Input }],
3114 customColors: [{ type: Input }],
3115 legend: [{ type: Input }],
3116 autoScale: [{ type: Input }],
3117 scaleType: [{ type: Input }],
3118 height: [{ type: Input }],
3119 select: [{ type: Output }],
3120 onDomainChange: [{ type: Output }]
3121};
3122
3123class LegendComponent {
3124 constructor(cd) {
3125 this.cd = cd;
3126 this.horizontal = false;
3127 this.labelClick = new EventEmitter();
3128 this.labelActivate = new EventEmitter();
3129 this.labelDeactivate = new EventEmitter();
3130 this.legendEntries = [];
3131 }
3132 ngOnChanges(changes) {
3133 this.update();
3134 }
3135 update() {
3136 this.cd.markForCheck();
3137 this.legendEntries = this.getLegendEntries();
3138 }
3139 getLegendEntries() {
3140 const items = [];
3141 for (const label of this.data) {
3142 const formattedLabel = formatLabel(label);
3143 const idx = items.findIndex(i => {
3144 return i.label === formattedLabel;
3145 });
3146 if (idx === -1) {
3147 items.push({
3148 label,
3149 formattedLabel,
3150 color: this.colors.getColor(label)
3151 });
3152 }
3153 }
3154 return items;
3155 }
3156 isActive(entry) {
3157 if (!this.activeEntries)
3158 return false;
3159 const item = this.activeEntries.find(d => {
3160 return entry.label === d.name;
3161 });
3162 return item !== undefined;
3163 }
3164 activate(item) {
3165 this.labelActivate.emit(item);
3166 }
3167 deactivate(item) {
3168 this.labelDeactivate.emit(item);
3169 }
3170 trackBy(index, item) {
3171 return item.label;
3172 }
3173}
3174LegendComponent.decorators = [
3175 { type: Component, args: [{
3176 selector: 'ngx-charts-legend',
3177 template: `
3178 <div [style.width.px]="width">
3179 <header class="legend-title" *ngIf="title?.length > 0">
3180 <span class="legend-title-text">{{ title }}</span>
3181 </header>
3182 <div class="legend-wrap">
3183 <ul class="legend-labels" [class.horizontal-legend]="horizontal" [style.max-height.px]="height - 45">
3184 <li *ngFor="let entry of legendEntries; trackBy: trackBy" class="legend-label">
3185 <ngx-charts-legend-entry
3186 [label]="entry.label"
3187 [formattedLabel]="entry.formattedLabel"
3188 [color]="entry.color"
3189 [isActive]="isActive(entry)"
3190 (select)="labelClick.emit($event)"
3191 (activate)="activate($event)"
3192 (deactivate)="deactivate($event)"
3193 >
3194 </ngx-charts-legend-entry>
3195 </li>
3196 </ul>
3197 </div>
3198 </div>
3199 `,
3200 encapsulation: ViewEncapsulation.None,
3201 changeDetection: ChangeDetectionStrategy.OnPush,
3202 styles: [".chart-legend{display:inline-block;padding:0;width:auto!important}.chart-legend .legend-title{white-space:nowrap;overflow:hidden;margin-left:10px;margin-bottom:5px;font-size:14px;font-weight:bold}.chart-legend ul,.chart-legend li{padding:0;margin:0;list-style:none}.chart-legend .horizontal-legend li{display:inline-block}.chart-legend .legend-wrap{width:calc(100% - 10px)}.chart-legend .legend-labels{line-height:85%;list-style:none;text-align:left;float:left;width:100%;border-radius:3px;overflow-y:auto;overflow-x:hidden;white-space:nowrap;background:rgba(0,0,0,.05)}.chart-legend .legend-label{cursor:pointer;font-size:90%;margin:8px;color:#afb7c8}.chart-legend .legend-label:hover{color:#000;transition:.2s}.chart-legend .legend-label .active .legend-label-text{color:#000}.chart-legend .legend-label-color{display:inline-block;height:15px;width:15px;margin-right:5px;color:#5b646b;border-radius:3px}.chart-legend .legend-label-text{display:inline-block;vertical-align:top;line-height:15px;font-size:12px;width:calc(100% - 20px);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.chart-legend .legend-title-text{vertical-align:bottom;display:inline-block;line-height:16px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"]
3203 },] }
3204];
3205LegendComponent.ctorParameters = () => [
3206 { type: ChangeDetectorRef }
3207];
3208LegendComponent.propDecorators = {
3209 data: [{ type: Input }],
3210 title: [{ type: Input }],
3211 colors: [{ type: Input }],
3212 height: [{ type: Input }],
3213 width: [{ type: Input }],
3214 activeEntries: [{ type: Input }],
3215 horizontal: [{ type: Input }],
3216 labelClick: [{ type: Output }],
3217 labelActivate: [{ type: Output }],
3218 labelDeactivate: [{ type: Output }]
3219};
3220
3221class LegendEntryComponent {
3222 constructor() {
3223 this.isActive = false;
3224 this.select = new EventEmitter();
3225 this.activate = new EventEmitter();
3226 this.deactivate = new EventEmitter();
3227 this.toggle = new EventEmitter();
3228 }
3229 get trimmedLabel() {
3230 return this.formattedLabel || '(empty)';
3231 }
3232 onMouseEnter() {
3233 this.activate.emit({ name: this.label });
3234 }
3235 onMouseLeave() {
3236 this.deactivate.emit({ name: this.label });
3237 }
3238}
3239LegendEntryComponent.decorators = [
3240 { type: Component, args: [{
3241 selector: 'ngx-charts-legend-entry',
3242 template: `
3243 <span [title]="formattedLabel" tabindex="-1" [class.active]="isActive" (click)="select.emit(formattedLabel)">
3244 <span class="legend-label-color" [style.background-color]="color" (click)="toggle.emit(formattedLabel)"> </span>
3245 <span class="legend-label-text">
3246 {{ trimmedLabel }}
3247 </span>
3248 </span>
3249 `,
3250 changeDetection: ChangeDetectionStrategy.OnPush
3251 },] }
3252];
3253LegendEntryComponent.propDecorators = {
3254 color: [{ type: Input }],
3255 label: [{ type: Input }],
3256 formattedLabel: [{ type: Input }],
3257 isActive: [{ type: Input }],
3258 select: [{ type: Output }],
3259 activate: [{ type: Output }],
3260 deactivate: [{ type: Output }],
3261 toggle: [{ type: Output }],
3262 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
3263 onMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
3264};
3265
3266class ScaleLegendComponent {
3267 constructor() {
3268 this.horizontal = false;
3269 }
3270 ngOnChanges(changes) {
3271 const gradientValues = this.gradientString(this.colors.range(), this.colors.domain());
3272 const direction = this.horizontal ? 'right' : 'bottom';
3273 this.gradient = `linear-gradient(to ${direction}, ${gradientValues})`;
3274 }
3275 /**
3276 * Generates the string used in the gradient stylesheet properties
3277 * @param colors array of colors
3278 * @param splits array of splits on a scale of (0, 1)
3279 */
3280 gradientString(colors, splits) {
3281 // add the 100%
3282 splits.push(1);
3283 const pairs = [];
3284 colors.reverse().forEach((c, i) => {
3285 pairs.push(`${c} ${Math.round(splits[i] * 100)}%`);
3286 });
3287 return pairs.join(', ');
3288 }
3289}
3290ScaleLegendComponent.decorators = [
3291 { type: Component, args: [{
3292 selector: 'ngx-charts-scale-legend',
3293 template: `
3294 <div
3295 class="scale-legend"
3296 [class.horizontal-legend]="horizontal"
3297 [style.height.px]="horizontal ? undefined : height"
3298 [style.width.px]="width"
3299 >
3300 <div class="scale-legend-label">
3301 <span>{{ valueRange[1].toLocaleString() }}</span>
3302 </div>
3303 <div class="scale-legend-wrap" [style.background]="gradient"></div>
3304 <div class="scale-legend-label">
3305 <span>{{ valueRange[0].toLocaleString() }}</span>
3306 </div>
3307 </div>
3308 `,
3309 encapsulation: ViewEncapsulation.None,
3310 changeDetection: ChangeDetectionStrategy.OnPush,
3311 styles: [".chart-legend{display:inline-block;padding:0;width:auto!important}.chart-legend .scale-legend{text-align:center;display:flex;flex-direction:column}.chart-legend .scale-legend-wrap{display:inline-block;flex:1;width:30px;border-radius:5px;margin:0 auto}.chart-legend .scale-legend-label{font-size:12px}.chart-legend .horizontal-legend.scale-legend{flex-direction:row}.chart-legend .horizontal-legend .scale-legend-wrap{width:auto;height:30px;margin:0 16px}\n"]
3312 },] }
3313];
3314ScaleLegendComponent.propDecorators = {
3315 valueRange: [{ type: Input }],
3316 colors: [{ type: Input }],
3317 height: [{ type: Input }],
3318 width: [{ type: Input }],
3319 horizontal: [{ type: Input }]
3320};
3321
3322class AdvancedLegendComponent {
3323 constructor() {
3324 this.label = 'Total';
3325 this.animations = true;
3326 this.select = new EventEmitter();
3327 this.activate = new EventEmitter();
3328 this.deactivate = new EventEmitter();
3329 this.legendItems = [];
3330 this.labelFormatting = label => label;
3331 this.percentageFormatting = percentage => percentage;
3332 this.defaultValueFormatting = value => value.toLocaleString();
3333 }
3334 ngOnChanges(changes) {
3335 this.update();
3336 }
3337 getTotal() {
3338 return this.data.map(d => Number(d.value)).reduce((sum, d) => sum + d, 0);
3339 }
3340 update() {
3341 this.total = this.getTotal();
3342 this.roundedTotal = this.total;
3343 this.legendItems = this.getLegendItems();
3344 }
3345 getLegendItems() {
3346 return this.data.map(d => {
3347 const label = formatLabel(d.name);
3348 const value = d.value;
3349 const color = this.colors.getColor(label);
3350 const percentage = this.total > 0 ? (value / this.total) * 100 : 0;
3351 const formattedLabel = typeof this.labelFormatting === 'function' ? this.labelFormatting(label) : label;
3352 return {
3353 _value: value,
3354 data: d,
3355 value,
3356 color,
3357 label: formattedLabel,
3358 displayLabel: trimLabel(formattedLabel, 20),
3359 origialLabel: d.name,
3360 percentage: this.percentageFormatting ? this.percentageFormatting(percentage) : percentage.toLocaleString()
3361 };
3362 });
3363 }
3364 trackBy(index, item) {
3365 return item.label;
3366 }
3367}
3368AdvancedLegendComponent.decorators = [
3369 { type: Component, args: [{
3370 selector: 'ngx-charts-advanced-legend',
3371 template: `
3372 <div class="advanced-pie-legend" [style.width.px]="width">
3373 <div
3374 *ngIf="animations"
3375 class="total-value"
3376 ngx-charts-count-up
3377 [countTo]="roundedTotal"
3378 [valueFormatting]="valueFormatting"
3379 ></div>
3380 <div class="total-value" *ngIf="!animations">
3381 {{ valueFormatting ? valueFormatting(roundedTotal) : defaultValueFormatting(roundedTotal) }}
3382 </div>
3383 <div class="total-label">
3384 {{ label }}
3385 </div>
3386 <div class="legend-items-container">
3387 <div class="legend-items">
3388 <div
3389 *ngFor="let legendItem of legendItems; trackBy: trackBy"
3390 tabindex="-1"
3391 class="legend-item"
3392 (mouseenter)="activate.emit(legendItem.data)"
3393 (mouseleave)="deactivate.emit(legendItem.data)"
3394 (click)="select.emit(legendItem.data)"
3395 >
3396 <div class="item-color" [style.border-left-color]="legendItem.color"></div>
3397 <div
3398 *ngIf="animations"
3399 class="item-value"
3400 ngx-charts-count-up
3401 [countTo]="legendItem._value"
3402 [valueFormatting]="valueFormatting"
3403 ></div>
3404 <div *ngIf="!animations" class="item-value">
3405 {{ valueFormatting ? valueFormatting(legendItem.value) : defaultValueFormatting(legendItem.value) }}
3406 </div>
3407 <div class="item-label">{{ legendItem.displayLabel }}</div>
3408 <div
3409 *ngIf="animations"
3410 class="item-percent"
3411 ngx-charts-count-up
3412 [countTo]="legendItem.percentage"
3413 [countSuffix]="'%'"
3414 ></div>
3415 <div *ngIf="!animations" class="item-percent">{{ legendItem.percentage.toLocaleString() }}%</div>
3416 </div>
3417 </div>
3418 </div>
3419 </div>
3420 `,
3421 encapsulation: ViewEncapsulation.None,
3422 changeDetection: ChangeDetectionStrategy.OnPush,
3423 styles: [".advanced-pie-legend{float:left;position:relative;top:50%;transform:translateY(-50%)}.advanced-pie-legend .total-value{font-size:36px}.advanced-pie-legend .total-label{font-size:24px;margin-bottom:19px}.advanced-pie-legend .legend-items-container{width:100%}.advanced-pie-legend .legend-items-container .legend-items{white-space:nowrap;overflow:auto}.advanced-pie-legend .legend-items-container .legend-items .legend-item{margin-right:20px;display:inline-block;cursor:pointer}.advanced-pie-legend .legend-items-container .legend-items .legend-item:focus{outline:none}.advanced-pie-legend .legend-items-container .legend-items .legend-item:hover{color:#000;transition:.2s}.advanced-pie-legend .legend-items-container .legend-items .legend-item .item-value{font-size:24px;margin-top:-6px;margin-left:11px}.advanced-pie-legend .legend-items-container .legend-items .legend-item .item-label{font-size:14px;opacity:.7;margin-left:11px;margin-top:-6px}.advanced-pie-legend .legend-items-container .legend-items .legend-item .item-percent{font-size:24px;opacity:.7;margin-left:11px}.advanced-pie-legend .legend-items-container .legend-items .legend-item .item-color{border-left:4px solid;width:4px;height:42px;float:left;margin-right:7px}\n"]
3424 },] }
3425];
3426AdvancedLegendComponent.propDecorators = {
3427 width: [{ type: Input }],
3428 data: [{ type: Input }],
3429 colors: [{ type: Input }],
3430 label: [{ type: Input }],
3431 animations: [{ type: Input }],
3432 select: [{ type: Output }],
3433 activate: [{ type: Output }],
3434 deactivate: [{ type: Output }],
3435 valueFormatting: [{ type: Input }],
3436 labelFormatting: [{ type: Input }],
3437 percentageFormatting: [{ type: Input }]
3438};
3439
3440const COMPONENTS = [
3441 AreaComponent,
3442 BaseChartComponent,
3443 CountUpDirective,
3444 TooltipArea,
3445 ChartComponent,
3446 LegendComponent,
3447 LegendEntryComponent,
3448 ScaleLegendComponent,
3449 CircleComponent,
3450 CircleSeriesComponent,
3451 GridPanelComponent,
3452 GridPanelSeriesComponent,
3453 SvgLinearGradientComponent,
3454 SvgRadialGradientComponent,
3455 Timeline,
3456 AdvancedLegendComponent
3457];
3458class ChartCommonModule {
3459}
3460ChartCommonModule.decorators = [
3461 { type: NgModule, args: [{
3462 imports: [CommonModule, AxesModule, TooltipModule],
3463 declarations: [...COMPONENTS, VisibilityObserver],
3464 exports: [CommonModule, AxesModule, TooltipModule, ...COMPONENTS, VisibilityObserver]
3465 },] }
3466];
3467
3468function calculateViewDimensions({ width, height, margins, showXAxis = false, showYAxis = false, xAxisHeight = 0, yAxisWidth = 0, showXLabel = false, showYLabel = false, showLegend = false, legendType = ScaleType.Ordinal, legendPosition = LegendPosition.Right, columns = 12 }) {
3469 let xOffset = margins[3];
3470 let chartWidth = width;
3471 let chartHeight = height - margins[0] - margins[2];
3472 if (showLegend && legendPosition === LegendPosition.Right) {
3473 if (legendType === ScaleType.Ordinal) {
3474 columns -= 2;
3475 }
3476 else {
3477 columns -= 1;
3478 }
3479 }
3480 chartWidth = (chartWidth * columns) / 12;
3481 chartWidth = chartWidth - margins[1] - margins[3];
3482 if (showXAxis) {
3483 chartHeight -= 5;
3484 chartHeight -= xAxisHeight;
3485 if (showXLabel) {
3486 // text height + spacing between axis label and tick labels
3487 const offset = 25 + 5;
3488 chartHeight -= offset;
3489 }
3490 }
3491 if (showYAxis) {
3492 chartWidth -= 5;
3493 chartWidth -= yAxisWidth;
3494 xOffset += yAxisWidth;
3495 xOffset += 10;
3496 if (showYLabel) {
3497 // text height + spacing between axis label and tick labels
3498 const offset = 25 + 5;
3499 chartWidth -= offset;
3500 xOffset += offset;
3501 }
3502 }
3503 chartWidth = Math.max(0, chartWidth);
3504 chartHeight = Math.max(0, chartHeight);
3505 return {
3506 width: Math.floor(chartWidth),
3507 height: Math.floor(chartHeight),
3508 xOffset: Math.floor(xOffset)
3509 };
3510}
3511
3512let colorSets = [
3513 {
3514 name: 'vivid',
3515 selectable: true,
3516 group: ScaleType.Ordinal,
3517 domain: [
3518 '#647c8a',
3519 '#3f51b5',
3520 '#2196f3',
3521 '#00b862',
3522 '#afdf0a',
3523 '#a7b61a',
3524 '#f3e562',
3525 '#ff9800',
3526 '#ff5722',
3527 '#ff4514'
3528 ]
3529 },
3530 {
3531 name: 'natural',
3532 selectable: true,
3533 group: ScaleType.Ordinal,
3534 domain: [
3535 '#bf9d76',
3536 '#e99450',
3537 '#d89f59',
3538 '#f2dfa7',
3539 '#a5d7c6',
3540 '#7794b1',
3541 '#afafaf',
3542 '#707160',
3543 '#ba9383',
3544 '#d9d5c3'
3545 ]
3546 },
3547 {
3548 name: 'cool',
3549 selectable: true,
3550 group: ScaleType.Ordinal,
3551 domain: [
3552 '#a8385d',
3553 '#7aa3e5',
3554 '#a27ea8',
3555 '#aae3f5',
3556 '#adcded',
3557 '#a95963',
3558 '#8796c0',
3559 '#7ed3ed',
3560 '#50abcc',
3561 '#ad6886'
3562 ]
3563 },
3564 {
3565 name: 'fire',
3566 selectable: true,
3567 group: ScaleType.Ordinal,
3568 domain: ['#ff3d00', '#bf360c', '#ff8f00', '#ff6f00', '#ff5722', '#e65100', '#ffca28', '#ffab00']
3569 },
3570 {
3571 name: 'solar',
3572 selectable: true,
3573 group: ScaleType.Linear,
3574 domain: [
3575 '#fff8e1',
3576 '#ffecb3',
3577 '#ffe082',
3578 '#ffd54f',
3579 '#ffca28',
3580 '#ffc107',
3581 '#ffb300',
3582 '#ffa000',
3583 '#ff8f00',
3584 '#ff6f00'
3585 ]
3586 },
3587 {
3588 name: 'air',
3589 selectable: true,
3590 group: ScaleType.Linear,
3591 domain: [
3592 '#e1f5fe',
3593 '#b3e5fc',
3594 '#81d4fa',
3595 '#4fc3f7',
3596 '#29b6f6',
3597 '#03a9f4',
3598 '#039be5',
3599 '#0288d1',
3600 '#0277bd',
3601 '#01579b'
3602 ]
3603 },
3604 {
3605 name: 'aqua',
3606 selectable: true,
3607 group: ScaleType.Linear,
3608 domain: [
3609 '#e0f7fa',
3610 '#b2ebf2',
3611 '#80deea',
3612 '#4dd0e1',
3613 '#26c6da',
3614 '#00bcd4',
3615 '#00acc1',
3616 '#0097a7',
3617 '#00838f',
3618 '#006064'
3619 ]
3620 },
3621 {
3622 name: 'flame',
3623 selectable: false,
3624 group: ScaleType.Ordinal,
3625 domain: [
3626 '#A10A28',
3627 '#D3342D',
3628 '#EF6D49',
3629 '#FAAD67',
3630 '#FDDE90',
3631 '#DBED91',
3632 '#A9D770',
3633 '#6CBA67',
3634 '#2C9653',
3635 '#146738'
3636 ]
3637 },
3638 {
3639 name: 'ocean',
3640 selectable: false,
3641 group: ScaleType.Ordinal,
3642 domain: [
3643 '#1D68FB',
3644 '#33C0FC',
3645 '#4AFFFE',
3646 '#AFFFFF',
3647 '#FFFC63',
3648 '#FDBD2D',
3649 '#FC8A25',
3650 '#FA4F1E',
3651 '#FA141B',
3652 '#BA38D1'
3653 ]
3654 },
3655 {
3656 name: 'forest',
3657 selectable: false,
3658 group: ScaleType.Ordinal,
3659 domain: [
3660 '#55C22D',
3661 '#C1F33D',
3662 '#3CC099',
3663 '#AFFFFF',
3664 '#8CFC9D',
3665 '#76CFFA',
3666 '#BA60FB',
3667 '#EE6490',
3668 '#C42A1C',
3669 '#FC9F32'
3670 ]
3671 },
3672 {
3673 name: 'horizon',
3674 selectable: false,
3675 group: ScaleType.Ordinal,
3676 domain: [
3677 '#2597FB',
3678 '#65EBFD',
3679 '#99FDD0',
3680 '#FCEE4B',
3681 '#FEFCFA',
3682 '#FDD6E3',
3683 '#FCB1A8',
3684 '#EF6F7B',
3685 '#CB96E8',
3686 '#EFDEE0'
3687 ]
3688 },
3689 {
3690 name: 'neons',
3691 selectable: false,
3692 group: ScaleType.Ordinal,
3693 domain: [
3694 '#FF3333',
3695 '#FF33FF',
3696 '#CC33FF',
3697 '#0000FF',
3698 '#33CCFF',
3699 '#33FFFF',
3700 '#33FF66',
3701 '#CCFF33',
3702 '#FFCC00',
3703 '#FF6600'
3704 ]
3705 },
3706 {
3707 name: 'picnic',
3708 selectable: false,
3709 group: ScaleType.Ordinal,
3710 domain: [
3711 '#FAC51D',
3712 '#66BD6D',
3713 '#FAA026',
3714 '#29BB9C',
3715 '#E96B56',
3716 '#55ACD2',
3717 '#B7332F',
3718 '#2C83C9',
3719 '#9166B8',
3720 '#92E7E8'
3721 ]
3722 },
3723 {
3724 name: 'night',
3725 selectable: false,
3726 group: ScaleType.Ordinal,
3727 domain: [
3728 '#2B1B5A',
3729 '#501356',
3730 '#183356',
3731 '#28203F',
3732 '#391B3C',
3733 '#1E2B3C',
3734 '#120634',
3735 '#2D0432',
3736 '#051932',
3737 '#453080',
3738 '#75267D',
3739 '#2C507D',
3740 '#4B3880',
3741 '#752F7D',
3742 '#35547D'
3743 ]
3744 },
3745 {
3746 name: 'nightLights',
3747 selectable: false,
3748 group: ScaleType.Ordinal,
3749 domain: [
3750 '#4e31a5',
3751 '#9c25a7',
3752 '#3065ab',
3753 '#57468b',
3754 '#904497',
3755 '#46648b',
3756 '#32118d',
3757 '#a00fb3',
3758 '#1052a2',
3759 '#6e51bd',
3760 '#b63cc3',
3761 '#6c97cb',
3762 '#8671c1',
3763 '#b455be',
3764 '#7496c3'
3765 ]
3766 }
3767];
3768
3769class ColorHelper {
3770 constructor(scheme, type, domain, customColors) {
3771 if (typeof scheme === 'string') {
3772 scheme = colorSets.find(cs => {
3773 return cs.name === scheme;
3774 });
3775 }
3776 this.colorDomain = scheme.domain;
3777 this.scaleType = type;
3778 this.domain = domain;
3779 this.customColors = customColors;
3780 this.scale = this.generateColorScheme(scheme, type, this.domain);
3781 }
3782 generateColorScheme(scheme, type, domain) {
3783 if (typeof scheme === 'string') {
3784 scheme = colorSets.find(cs => {
3785 return cs.name === scheme;
3786 });
3787 }
3788 let colorScale;
3789 switch (type) {
3790 case ScaleType.Quantile:
3791 colorScale = scaleQuantile()
3792 .range(scheme.domain)
3793 .domain(domain);
3794 break;
3795 case ScaleType.Ordinal:
3796 colorScale = scaleOrdinal()
3797 .range(scheme.domain)
3798 .domain(domain);
3799 break;
3800 case ScaleType.Linear:
3801 {
3802 const colorDomain = [...scheme.domain];
3803 if (colorDomain.length === 1) {
3804 colorDomain.push(colorDomain[0]);
3805 this.colorDomain = colorDomain;
3806 }
3807 const points = range(0, 1, 1.0 / colorDomain.length);
3808 colorScale = scaleLinear()
3809 .range(colorDomain)
3810 .domain(points);
3811 }
3812 break;
3813 default:
3814 break;
3815 }
3816 return colorScale;
3817 }
3818 getColor(value) {
3819 if (value === undefined || value === null) {
3820 throw new Error('Value can not be null');
3821 }
3822 if (this.scaleType === ScaleType.Linear) {
3823 const valueScale = scaleLinear()
3824 .domain(this.domain)
3825 .range([0, 1]);
3826 return this.scale(valueScale(value));
3827 }
3828 else {
3829 if (typeof this.customColors === 'function') {
3830 return this.customColors(value);
3831 }
3832 const formattedValue = value.toString();
3833 let found; // todo type customColors
3834 if (this.customColors && this.customColors.length > 0) {
3835 found = this.customColors.find(mapping => {
3836 return mapping.name.toLowerCase() === formattedValue.toLowerCase();
3837 });
3838 }
3839 if (found) {
3840 return found.value;
3841 }
3842 else {
3843 return this.scale(value);
3844 }
3845 }
3846 }
3847 getLinearGradientStops(value, start) {
3848 if (start === undefined) {
3849 start = this.domain[0];
3850 }
3851 const valueScale = scaleLinear()
3852 .domain(this.domain)
3853 .range([0, 1]);
3854 const colorValueScale = scaleBand().domain(this.colorDomain).range([0, 1]);
3855 const endColor = this.getColor(value);
3856 // generate the stops
3857 const startVal = valueScale(start);
3858 const startColor = this.getColor(start);
3859 const endVal = valueScale(value);
3860 let i = 1;
3861 let currentVal = startVal;
3862 const stops = [];
3863 stops.push({
3864 color: startColor,
3865 offset: startVal,
3866 originalOffset: startVal,
3867 opacity: 1
3868 });
3869 while (currentVal < endVal && i < this.colorDomain.length) {
3870 const color = this.colorDomain[i];
3871 const offset = colorValueScale(color);
3872 if (offset <= startVal) {
3873 i++;
3874 continue;
3875 }
3876 if (offset.toFixed(4) >= (endVal - colorValueScale.bandwidth()).toFixed(4)) {
3877 break;
3878 }
3879 stops.push({
3880 color,
3881 offset,
3882 opacity: 1
3883 });
3884 currentVal = offset;
3885 i++;
3886 }
3887 if (stops[stops.length - 1].offset < 100) {
3888 stops.push({
3889 color: endColor,
3890 offset: endVal,
3891 opacity: 1
3892 });
3893 }
3894 if (endVal === startVal) {
3895 stops[0].offset = 0;
3896 stops[1].offset = 100;
3897 }
3898 else {
3899 // normalize the offsets into percentages
3900 if (stops[stops.length - 1].offset !== 100) {
3901 for (const s of stops) {
3902 s.offset = ((s.offset - startVal) / (endVal - startVal)) * 100;
3903 }
3904 }
3905 }
3906 return stops;
3907 }
3908}
3909
3910/**
3911 * Based on the data, return an array with unique values.
3912 *
3913 * @export
3914 * @returns array
3915 */
3916function getUniqueXDomainValues(results) {
3917 const valueSet = new Set();
3918 for (const result of results) {
3919 for (const d of result.series) {
3920 valueSet.add(d.name);
3921 }
3922 }
3923 return Array.from(valueSet);
3924}
3925/**
3926 * Get the scaleType of enumerable of values.
3927 * @returns 'time', 'linear' or 'ordinal'
3928 */
3929function getScaleType(values, checkDateType = true) {
3930 if (checkDateType) {
3931 const allDates = values.every(value => value instanceof Date);
3932 if (allDates) {
3933 return ScaleType.Time;
3934 }
3935 }
3936 const allNumbers = values.every(value => typeof value === 'number');
3937 if (allNumbers) {
3938 return ScaleType.Linear;
3939 }
3940 return ScaleType.Ordinal;
3941}
3942function getXDomainArray(values, xScaleMin, xScaleMax) {
3943 const scaleType = getScaleType(values);
3944 let xSet = [];
3945 let domain = [];
3946 if (scaleType === ScaleType.Linear) {
3947 values = values.map(v => Number(v));
3948 }
3949 let min;
3950 let max;
3951 if (scaleType === ScaleType.Time || scaleType === ScaleType.Linear) {
3952 const mappedValues = values.map(v => Number(v));
3953 min = xScaleMin ? xScaleMin : Math.min(...mappedValues);
3954 max = xScaleMax ? xScaleMax : Math.max(...mappedValues);
3955 }
3956 if (scaleType === ScaleType.Time) {
3957 domain = [new Date(min), new Date(max)];
3958 xSet = [...values].sort((a, b) => {
3959 const aDate = a.getTime();
3960 const bDate = b.getTime();
3961 if (aDate > bDate)
3962 return 1;
3963 if (bDate > aDate)
3964 return -1;
3965 return 0;
3966 });
3967 }
3968 else if (scaleType === ScaleType.Linear) {
3969 domain = [min, max];
3970 // Use compare function to sort numbers numerically
3971 xSet = [...values].sort((a, b) => a - b);
3972 }
3973 else {
3974 domain = values;
3975 xSet = values;
3976 }
3977 return { domain, xSet, scaleType };
3978}
3979
3980class AreaChartComponent extends BaseChartComponent {
3981 constructor() {
3982 super(...arguments);
3983 this.legend = false;
3984 this.legendTitle = 'Legend';
3985 this.legendPosition = LegendPosition.Right;
3986 this.xAxis = false;
3987 this.yAxis = false;
3988 this.baseValue = 'auto';
3989 this.autoScale = false;
3990 this.timeline = false;
3991 this.showGridLines = true;
3992 this.curve = curveLinear;
3993 this.activeEntries = [];
3994 this.trimXAxisTicks = true;
3995 this.trimYAxisTicks = true;
3996 this.rotateXAxisTicks = true;
3997 this.maxXAxisTickLength = 16;
3998 this.maxYAxisTickLength = 16;
3999 this.roundDomains = false;
4000 this.tooltipDisabled = false;
4001 this.activate = new EventEmitter();
4002 this.deactivate = new EventEmitter();
4003 this.margin = [10, 20, 10, 20];
4004 this.xAxisHeight = 0;
4005 this.yAxisWidth = 0;
4006 this.timelineHeight = 50;
4007 this.timelinePadding = 10;
4008 this.trackBy = (index, item) => {
4009 return item.name;
4010 };
4011 }
4012 update() {
4013 super.update();
4014 this.dims = calculateViewDimensions({
4015 width: this.width,
4016 height: this.height,
4017 margins: this.margin,
4018 showXAxis: this.xAxis,
4019 showYAxis: this.yAxis,
4020 xAxisHeight: this.xAxisHeight,
4021 yAxisWidth: this.yAxisWidth,
4022 showXLabel: this.showXAxisLabel,
4023 showYLabel: this.showYAxisLabel,
4024 showLegend: this.legend,
4025 legendType: this.schemeType,
4026 legendPosition: this.legendPosition
4027 });
4028 if (this.timeline) {
4029 this.dims.height -= this.timelineHeight + this.margin[2] + this.timelinePadding;
4030 }
4031 this.xDomain = this.getXDomain();
4032 if (this.filteredDomain) {
4033 this.xDomain = this.filteredDomain;
4034 }
4035 this.yDomain = this.getYDomain();
4036 this.seriesDomain = this.getSeriesDomain();
4037 this.xScale = this.getXScale(this.xDomain, this.dims.width);
4038 this.yScale = this.getYScale(this.yDomain, this.dims.height);
4039 this.updateTimeline();
4040 this.setColors();
4041 this.legendOptions = this.getLegendOptions();
4042 this.transform = `translate(${this.dims.xOffset}, ${this.margin[0]})`;
4043 this.clipPathId = 'clip' + id().toString();
4044 this.clipPath = `url(#${this.clipPathId})`;
4045 }
4046 updateTimeline() {
4047 if (this.timeline) {
4048 this.timelineWidth = this.dims.width;
4049 this.timelineXDomain = this.getXDomain();
4050 this.timelineXScale = this.getXScale(this.timelineXDomain, this.timelineWidth);
4051 this.timelineYScale = this.getYScale(this.yDomain, this.timelineHeight);
4052 this.timelineTransform = `translate(${this.dims.xOffset}, ${-this.margin[2]})`;
4053 }
4054 }
4055 getXDomain() {
4056 let values = getUniqueXDomainValues(this.results);
4057 this.scaleType = getScaleType(values);
4058 let domain = [];
4059 if (this.scaleType === ScaleType.Linear) {
4060 values = values.map(v => Number(v));
4061 }
4062 let min;
4063 let max;
4064 if (this.scaleType === ScaleType.Time || this.scaleType === ScaleType.Linear) {
4065 min = this.xScaleMin ? this.xScaleMin : Math.min(...values);
4066 max = this.xScaleMax ? this.xScaleMax : Math.max(...values);
4067 }
4068 if (this.scaleType === ScaleType.Time) {
4069 domain = [new Date(min), new Date(max)];
4070 this.xSet = [...values].sort((a, b) => {
4071 const aDate = a.getTime();
4072 const bDate = b.getTime();
4073 if (aDate > bDate)
4074 return 1;
4075 if (bDate > aDate)
4076 return -1;
4077 return 0;
4078 });
4079 }
4080 else if (this.scaleType === ScaleType.Linear) {
4081 domain = [min, max];
4082 // Use compare function to sort numbers numerically
4083 this.xSet = [...values].sort((a, b) => a - b);
4084 }
4085 else {
4086 domain = values;
4087 this.xSet = values;
4088 }
4089 return domain;
4090 }
4091 getYDomain() {
4092 const domain = [];
4093 for (const results of this.results) {
4094 for (const d of results.series) {
4095 if (!domain.includes(d.value)) {
4096 domain.push(d.value);
4097 }
4098 }
4099 }
4100 const values = [...domain];
4101 if (!this.autoScale) {
4102 values.push(0);
4103 }
4104 if (this.baseValue !== 'auto') {
4105 values.push(this.baseValue);
4106 }
4107 const min = this.yScaleMin ? this.yScaleMin : Math.min(...values);
4108 const max = this.yScaleMax ? this.yScaleMax : Math.max(...values);
4109 return [min, max];
4110 }
4111 getSeriesDomain() {
4112 return this.results.map(d => d.name);
4113 }
4114 getXScale(domain, width) {
4115 let scale;
4116 if (this.scaleType === ScaleType.Time) {
4117 scale = scaleTime();
4118 }
4119 else if (this.scaleType === ScaleType.Linear) {
4120 scale = scaleLinear();
4121 }
4122 else if (this.scaleType === ScaleType.Ordinal) {
4123 scale = scalePoint().padding(0.1);
4124 }
4125 scale.range([0, width]).domain(domain);
4126 return this.roundDomains ? scale.nice() : scale;
4127 }
4128 getYScale(domain, height) {
4129 const scale = scaleLinear().range([height, 0]).domain(domain);
4130 return this.roundDomains ? scale.nice() : scale;
4131 }
4132 getScaleType(values) {
4133 let date = true;
4134 let num = true;
4135 for (const value of values) {
4136 if (isDate(value)) {
4137 date = false;
4138 }
4139 if (isNumber(value)) {
4140 num = false;
4141 }
4142 }
4143 if (date) {
4144 return ScaleType.Time;
4145 }
4146 if (num) {
4147 return ScaleType.Linear;
4148 }
4149 return ScaleType.Ordinal;
4150 }
4151 updateDomain(domain) {
4152 this.filteredDomain = domain;
4153 this.xDomain = this.filteredDomain;
4154 this.xScale = this.getXScale(this.xDomain, this.dims.width);
4155 }
4156 updateHoveredVertical(item) {
4157 this.hoveredVertical = item.value;
4158 this.deactivateAll();
4159 }
4160 hideCircles() {
4161 this.hoveredVertical = null;
4162 this.deactivateAll();
4163 }
4164 onClick(data, series) {
4165 if (series) {
4166 data.series = series.name;
4167 }
4168 this.select.emit(data);
4169 }
4170 setColors() {
4171 let domain;
4172 if (this.schemeType === ScaleType.Ordinal) {
4173 domain = this.seriesDomain;
4174 }
4175 else {
4176 domain = this.yDomain;
4177 }
4178 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
4179 }
4180 getLegendOptions() {
4181 const opts = {
4182 scaleType: this.schemeType,
4183 colors: undefined,
4184 domain: [],
4185 title: undefined,
4186 position: this.legendPosition
4187 };
4188 if (opts.scaleType === ScaleType.Ordinal) {
4189 opts.domain = this.seriesDomain;
4190 opts.colors = this.colors;
4191 opts.title = this.legendTitle;
4192 }
4193 else {
4194 opts.domain = this.yDomain;
4195 opts.colors = this.colors.scale;
4196 }
4197 return opts;
4198 }
4199 updateYAxisWidth({ width }) {
4200 this.yAxisWidth = width;
4201 this.update();
4202 }
4203 updateXAxisHeight({ height }) {
4204 this.xAxisHeight = height;
4205 this.update();
4206 }
4207 onActivate(item) {
4208 const idx = this.activeEntries.findIndex(d => {
4209 return d.name === item.name && d.value === item.value;
4210 });
4211 if (idx > -1) {
4212 return;
4213 }
4214 this.activeEntries = [item, ...this.activeEntries];
4215 this.activate.emit({ value: item, entries: this.activeEntries });
4216 }
4217 onDeactivate(item) {
4218 const idx = this.activeEntries.findIndex(d => {
4219 return d.name === item.name && d.value === item.value;
4220 });
4221 this.activeEntries.splice(idx, 1);
4222 this.activeEntries = [...this.activeEntries];
4223 this.deactivate.emit({ value: item, entries: this.activeEntries });
4224 }
4225 deactivateAll() {
4226 this.activeEntries = [...this.activeEntries];
4227 for (const entry of this.activeEntries) {
4228 this.deactivate.emit({ value: entry, entries: [] });
4229 }
4230 this.activeEntries = [];
4231 }
4232}
4233AreaChartComponent.decorators = [
4234 { type: Component, args: [{
4235 selector: 'ngx-charts-area-chart',
4236 template: `
4237 <ngx-charts-chart
4238 [view]="[width, height]"
4239 [showLegend]="legend"
4240 [legendOptions]="legendOptions"
4241 [activeEntries]="activeEntries"
4242 [animations]="animations"
4243 (legendLabelClick)="onClick($event)"
4244 (legendLabelActivate)="onActivate($event)"
4245 (legendLabelDeactivate)="onDeactivate($event)"
4246 >
4247 <svg:defs>
4248 <svg:clipPath [attr.id]="clipPathId">
4249 <svg:rect
4250 [attr.width]="dims.width + 10"
4251 [attr.height]="dims.height + 10"
4252 [attr.transform]="'translate(-5, -5)'"
4253 />
4254 </svg:clipPath>
4255 </svg:defs>
4256 <svg:g [attr.transform]="transform" class="area-chart chart">
4257 <svg:g
4258 ngx-charts-x-axis
4259 *ngIf="xAxis"
4260 [xScale]="xScale"
4261 [dims]="dims"
4262 [showGridLines]="showGridLines"
4263 [showLabel]="showXAxisLabel"
4264 [labelText]="xAxisLabel"
4265 [trimTicks]="trimXAxisTicks"
4266 [rotateTicks]="rotateXAxisTicks"
4267 [maxTickLength]="maxXAxisTickLength"
4268 [tickFormatting]="xAxisTickFormatting"
4269 [ticks]="xAxisTicks"
4270 (dimensionsChanged)="updateXAxisHeight($event)"
4271 ></svg:g>
4272 <svg:g
4273 ngx-charts-y-axis
4274 *ngIf="yAxis"
4275 [yScale]="yScale"
4276 [dims]="dims"
4277 [showGridLines]="showGridLines"
4278 [showLabel]="showYAxisLabel"
4279 [labelText]="yAxisLabel"
4280 [trimTicks]="trimYAxisTicks"
4281 [maxTickLength]="maxYAxisTickLength"
4282 [tickFormatting]="yAxisTickFormatting"
4283 [ticks]="yAxisTicks"
4284 (dimensionsChanged)="updateYAxisWidth($event)"
4285 ></svg:g>
4286 <svg:g [attr.clip-path]="clipPath">
4287 <svg:g *ngFor="let series of results; trackBy: trackBy">
4288 <svg:g
4289 ngx-charts-area-series
4290 [xScale]="xScale"
4291 [yScale]="yScale"
4292 [baseValue]="baseValue"
4293 [colors]="colors"
4294 [data]="series"
4295 [activeEntries]="activeEntries"
4296 [scaleType]="scaleType"
4297 [gradient]="gradient"
4298 [curve]="curve"
4299 [animations]="animations"
4300 />
4301 </svg:g>
4302
4303 <svg:g *ngIf="!tooltipDisabled" (mouseleave)="hideCircles()">
4304 <svg:g
4305 ngx-charts-tooltip-area
4306 [dims]="dims"
4307 [xSet]="xSet"
4308 [xScale]="xScale"
4309 [yScale]="yScale"
4310 [results]="results"
4311 [colors]="colors"
4312 [tooltipDisabled]="tooltipDisabled"
4313 [tooltipTemplate]="seriesTooltipTemplate"
4314 (hover)="updateHoveredVertical($event)"
4315 />
4316
4317 <svg:g *ngFor="let series of results">
4318 <svg:g
4319 ngx-charts-circle-series
4320 [xScale]="xScale"
4321 [yScale]="yScale"
4322 [colors]="colors"
4323 [activeEntries]="activeEntries"
4324 [data]="series"
4325 [scaleType]="scaleType"
4326 [visibleValue]="hoveredVertical"
4327 [tooltipDisabled]="tooltipDisabled"
4328 [tooltipTemplate]="tooltipTemplate"
4329 (select)="onClick($event, series)"
4330 (activate)="onActivate($event)"
4331 (deactivate)="onDeactivate($event)"
4332 />
4333 </svg:g>
4334 </svg:g>
4335 </svg:g>
4336 </svg:g>
4337 <svg:g
4338 ngx-charts-timeline
4339 *ngIf="timeline && scaleType != 'ordinal'"
4340 [attr.transform]="timelineTransform"
4341 [results]="results"
4342 [view]="[timelineWidth, height]"
4343 [height]="timelineHeight"
4344 [scheme]="scheme"
4345 [customColors]="customColors"
4346 [legend]="legend"
4347 [scaleType]="scaleType"
4348 (onDomainChange)="updateDomain($event)"
4349 >
4350 <svg:g *ngFor="let series of results; trackBy: trackBy">
4351 <svg:g
4352 ngx-charts-area-series
4353 [xScale]="timelineXScale"
4354 [yScale]="timelineYScale"
4355 [baseValue]="baseValue"
4356 [colors]="colors"
4357 [data]="series"
4358 [scaleType]="scaleType"
4359 [gradient]="gradient"
4360 [curve]="curve"
4361 [animations]="animations"
4362 />
4363 </svg:g>
4364 </svg:g>
4365 </ngx-charts-chart>
4366 `,
4367 changeDetection: ChangeDetectionStrategy.OnPush,
4368 encapsulation: ViewEncapsulation.None,
4369 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
4370 },] }
4371];
4372AreaChartComponent.propDecorators = {
4373 legend: [{ type: Input }],
4374 legendTitle: [{ type: Input }],
4375 legendPosition: [{ type: Input }],
4376 xAxis: [{ type: Input }],
4377 yAxis: [{ type: Input }],
4378 baseValue: [{ type: Input }],
4379 autoScale: [{ type: Input }],
4380 showXAxisLabel: [{ type: Input }],
4381 showYAxisLabel: [{ type: Input }],
4382 xAxisLabel: [{ type: Input }],
4383 yAxisLabel: [{ type: Input }],
4384 timeline: [{ type: Input }],
4385 gradient: [{ type: Input }],
4386 showGridLines: [{ type: Input }],
4387 curve: [{ type: Input }],
4388 activeEntries: [{ type: Input }],
4389 schemeType: [{ type: Input }],
4390 trimXAxisTicks: [{ type: Input }],
4391 trimYAxisTicks: [{ type: Input }],
4392 rotateXAxisTicks: [{ type: Input }],
4393 maxXAxisTickLength: [{ type: Input }],
4394 maxYAxisTickLength: [{ type: Input }],
4395 xAxisTickFormatting: [{ type: Input }],
4396 yAxisTickFormatting: [{ type: Input }],
4397 xAxisTicks: [{ type: Input }],
4398 yAxisTicks: [{ type: Input }],
4399 roundDomains: [{ type: Input }],
4400 tooltipDisabled: [{ type: Input }],
4401 xScaleMin: [{ type: Input }],
4402 xScaleMax: [{ type: Input }],
4403 yScaleMin: [{ type: Input }],
4404 yScaleMax: [{ type: Input }],
4405 activate: [{ type: Output }],
4406 deactivate: [{ type: Output }],
4407 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
4408 seriesTooltipTemplate: [{ type: ContentChild, args: ['seriesTooltipTemplate',] }],
4409 hideCircles: [{ type: HostListener, args: ['mouseleave',] }]
4410};
4411
4412class AreaChartNormalizedComponent extends BaseChartComponent {
4413 constructor() {
4414 super(...arguments);
4415 this.legend = false;
4416 this.legendTitle = 'Legend';
4417 this.legendPosition = LegendPosition.Right;
4418 this.showXAxisLabel = false;
4419 this.showYAxisLabel = false;
4420 this.showGridLines = true;
4421 this.curve = curveLinear;
4422 this.activeEntries = [];
4423 this.trimXAxisTicks = true;
4424 this.trimYAxisTicks = true;
4425 this.rotateXAxisTicks = true;
4426 this.maxXAxisTickLength = 16;
4427 this.maxYAxisTickLength = 16;
4428 this.roundDomains = false;
4429 this.tooltipDisabled = false;
4430 this.activate = new EventEmitter();
4431 this.deactivate = new EventEmitter();
4432 this.yDomain = [0, 100];
4433 this.margin = [10, 20, 10, 20];
4434 this.xAxisHeight = 0;
4435 this.yAxisWidth = 0;
4436 this.seriesType = SeriesType;
4437 this.timelineHeight = 50;
4438 this.timelinePadding = 10;
4439 this.trackBy = (index, item) => {
4440 return item.name;
4441 };
4442 }
4443 update() {
4444 super.update();
4445 this.dims = calculateViewDimensions({
4446 width: this.width,
4447 height: this.height,
4448 margins: this.margin,
4449 showXAxis: this.xAxis,
4450 showYAxis: this.yAxis,
4451 xAxisHeight: this.xAxisHeight,
4452 yAxisWidth: this.yAxisWidth,
4453 showXLabel: this.showXAxisLabel,
4454 showYLabel: this.showYAxisLabel,
4455 showLegend: this.legend,
4456 legendType: this.schemeType,
4457 legendPosition: this.legendPosition
4458 });
4459 if (this.timeline) {
4460 this.dims.height -= this.timelineHeight + this.margin[2] + this.timelinePadding;
4461 }
4462 this.xDomain = this.getXDomain();
4463 if (this.filteredDomain) {
4464 this.xDomain = this.filteredDomain;
4465 }
4466 this.seriesDomain = this.getSeriesDomain();
4467 this.xScale = this.getXScale(this.xDomain, this.dims.width);
4468 this.yScale = this.getYScale(this.yDomain, this.dims.height);
4469 for (let i = 0; i < this.xSet.length; i++) {
4470 const val = this.xSet[i];
4471 let d0 = 0;
4472 let total = 0;
4473 for (const group of this.results) {
4474 const d = group.series.find(item => {
4475 let a = item.name;
4476 let b = val;
4477 if (this.scaleType === ScaleType.Time) {
4478 a = a.valueOf();
4479 b = b.valueOf();
4480 }
4481 return a === b;
4482 });
4483 if (d) {
4484 total += d.value;
4485 }
4486 }
4487 for (const group of this.results) {
4488 let d = group.series.find(item => {
4489 let a = item.name;
4490 let b = val;
4491 if (this.scaleType === ScaleType.Time) {
4492 a = a.valueOf();
4493 b = b.valueOf();
4494 }
4495 return a === b;
4496 });
4497 if (d) {
4498 d.d0 = d0;
4499 d.d1 = d0 + d.value;
4500 d0 += d.value;
4501 }
4502 else {
4503 d = {
4504 name: val,
4505 value: 0,
4506 d0,
4507 d1: d0
4508 };
4509 group.series.push(d);
4510 }
4511 if (total > 0) {
4512 d.d0 = (d.d0 * 100) / total;
4513 d.d1 = (d.d1 * 100) / total;
4514 }
4515 else {
4516 d.d0 = 0;
4517 d.d1 = 0;
4518 }
4519 }
4520 }
4521 this.updateTimeline();
4522 this.setColors();
4523 this.legendOptions = this.getLegendOptions();
4524 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
4525 this.clipPathId = 'clip' + id().toString();
4526 this.clipPath = `url(#${this.clipPathId})`;
4527 }
4528 updateTimeline() {
4529 if (this.timeline) {
4530 this.timelineWidth = this.dims.width;
4531 this.timelineXDomain = this.getXDomain();
4532 this.timelineXScale = this.getXScale(this.timelineXDomain, this.timelineWidth);
4533 this.timelineYScale = this.getYScale(this.yDomain, this.timelineHeight);
4534 this.timelineTransform = `translate(${this.dims.xOffset}, ${-this.margin[2]})`;
4535 }
4536 }
4537 getXDomain() {
4538 let values = getUniqueXDomainValues(this.results);
4539 this.scaleType = getScaleType(values);
4540 let domain = [];
4541 if (this.scaleType === ScaleType.Time) {
4542 const min = Math.min(...values);
4543 const max = Math.max(...values);
4544 domain = [new Date(min), new Date(max)];
4545 this.xSet = [...values].sort((a, b) => {
4546 const aDate = a.getTime();
4547 const bDate = b.getTime();
4548 if (aDate > bDate)
4549 return 1;
4550 if (bDate > aDate)
4551 return -1;
4552 return 0;
4553 });
4554 }
4555 else if (this.scaleType === ScaleType.Linear) {
4556 values = values.map(v => Number(v));
4557 const min = Math.min(...values);
4558 const max = Math.max(...values);
4559 domain = [min, max];
4560 // Use compare function to sort numbers numerically
4561 this.xSet = [...values].sort((a, b) => a - b);
4562 }
4563 else {
4564 domain = values;
4565 this.xSet = values;
4566 }
4567 return domain;
4568 }
4569 getSeriesDomain() {
4570 return this.results.map(d => d.name);
4571 }
4572 getXScale(domain, width) {
4573 let scale;
4574 if (this.scaleType === ScaleType.Time) {
4575 scale = scaleTime();
4576 }
4577 else if (this.scaleType === ScaleType.Linear) {
4578 scale = scaleLinear();
4579 }
4580 else if (this.scaleType === ScaleType.Ordinal) {
4581 scale = scalePoint().padding(0.1);
4582 }
4583 scale.range([0, width]).domain(domain);
4584 return this.roundDomains ? scale.nice() : scale;
4585 }
4586 getYScale(domain, height) {
4587 const scale = scaleLinear().range([height, 0]).domain(domain);
4588 return this.roundDomains ? scale.nice() : scale;
4589 }
4590 updateDomain(domain) {
4591 this.filteredDomain = domain;
4592 this.xDomain = this.filteredDomain;
4593 this.xScale = this.getXScale(this.xDomain, this.dims.width);
4594 }
4595 updateHoveredVertical(item) {
4596 this.hoveredVertical = item.value;
4597 this.deactivateAll();
4598 }
4599 hideCircles() {
4600 this.hoveredVertical = null;
4601 this.deactivateAll();
4602 }
4603 onClick(data, series) {
4604 if (series) {
4605 data.series = series.name;
4606 }
4607 this.select.emit(data);
4608 }
4609 setColors() {
4610 let domain;
4611 if (this.schemeType === ScaleType.Ordinal) {
4612 domain = this.seriesDomain;
4613 }
4614 else {
4615 domain = this.yDomain;
4616 }
4617 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
4618 }
4619 getLegendOptions() {
4620 const opts = {
4621 scaleType: this.schemeType,
4622 colors: undefined,
4623 domain: [],
4624 title: undefined,
4625 position: this.legendPosition
4626 };
4627 if (opts.scaleType === ScaleType.Ordinal) {
4628 opts.domain = this.seriesDomain;
4629 opts.colors = this.colors;
4630 opts.title = this.legendTitle;
4631 }
4632 else {
4633 opts.domain = this.yDomain;
4634 opts.colors = this.colors.scale;
4635 }
4636 return opts;
4637 }
4638 updateYAxisWidth({ width }) {
4639 this.yAxisWidth = width;
4640 this.update();
4641 }
4642 updateXAxisHeight({ height }) {
4643 this.xAxisHeight = height;
4644 this.update();
4645 }
4646 onActivate(item) {
4647 const idx = this.activeEntries.findIndex(d => {
4648 return d.name === item.name && d.value === item.value;
4649 });
4650 if (idx > -1) {
4651 return;
4652 }
4653 this.activeEntries = [item, ...this.activeEntries];
4654 this.activate.emit({ value: item, entries: this.activeEntries });
4655 }
4656 onDeactivate(item) {
4657 const idx = this.activeEntries.findIndex(d => {
4658 return d.name === item.name && d.value === item.value;
4659 });
4660 this.activeEntries.splice(idx, 1);
4661 this.activeEntries = [...this.activeEntries];
4662 this.deactivate.emit({ value: item, entries: this.activeEntries });
4663 }
4664 deactivateAll() {
4665 this.activeEntries = [...this.activeEntries];
4666 for (const entry of this.activeEntries) {
4667 this.deactivate.emit({ value: entry, entries: [] });
4668 }
4669 this.activeEntries = [];
4670 }
4671}
4672AreaChartNormalizedComponent.decorators = [
4673 { type: Component, args: [{
4674 selector: 'ngx-charts-area-chart-normalized',
4675 template: `
4676 <ngx-charts-chart
4677 [view]="[width, height]"
4678 [showLegend]="legend"
4679 [legendOptions]="legendOptions"
4680 [activeEntries]="activeEntries"
4681 [animations]="animations"
4682 (legendLabelClick)="onClick($event)"
4683 (legendLabelActivate)="onActivate($event)"
4684 (legendLabelDeactivate)="onDeactivate($event)"
4685 >
4686 <svg:defs>
4687 <svg:clipPath [attr.id]="clipPathId">
4688 <svg:rect
4689 [attr.width]="dims.width + 10"
4690 [attr.height]="dims.height + 10"
4691 [attr.transform]="'translate(-5, -5)'"
4692 />
4693 </svg:clipPath>
4694 </svg:defs>
4695 <svg:g [attr.transform]="transform" class="area-chart chart">
4696 <svg:g
4697 ngx-charts-x-axis
4698 *ngIf="xAxis"
4699 [xScale]="xScale"
4700 [dims]="dims"
4701 [showGridLines]="showGridLines"
4702 [showLabel]="showXAxisLabel"
4703 [labelText]="xAxisLabel"
4704 [trimTicks]="trimXAxisTicks"
4705 [rotateTicks]="rotateXAxisTicks"
4706 [maxTickLength]="maxXAxisTickLength"
4707 [tickFormatting]="xAxisTickFormatting"
4708 [ticks]="xAxisTicks"
4709 (dimensionsChanged)="updateXAxisHeight($event)"
4710 ></svg:g>
4711 <svg:g
4712 ngx-charts-y-axis
4713 *ngIf="yAxis"
4714 [yScale]="yScale"
4715 [dims]="dims"
4716 [showGridLines]="showGridLines"
4717 [showLabel]="showYAxisLabel"
4718 [labelText]="yAxisLabel"
4719 [trimTicks]="trimYAxisTicks"
4720 [maxTickLength]="maxYAxisTickLength"
4721 [tickFormatting]="yAxisTickFormatting"
4722 [ticks]="yAxisTicks"
4723 (dimensionsChanged)="updateYAxisWidth($event)"
4724 ></svg:g>
4725 <svg:g [attr.clip-path]="clipPath">
4726 <svg:g *ngFor="let series of results; trackBy: trackBy">
4727 <svg:g
4728 ngx-charts-area-series
4729 [xScale]="xScale"
4730 [yScale]="yScale"
4731 [colors]="colors"
4732 [data]="series"
4733 [scaleType]="scaleType"
4734 [activeEntries]="activeEntries"
4735 [gradient]="gradient"
4736 [normalized]="true"
4737 [curve]="curve"
4738 [animations]="animations"
4739 />
4740 </svg:g>
4741
4742 <svg:g *ngIf="!tooltipDisabled" (mouseleave)="hideCircles()">
4743 <svg:g
4744 ngx-charts-tooltip-area
4745 [dims]="dims"
4746 [xSet]="xSet"
4747 [xScale]="xScale"
4748 [yScale]="yScale"
4749 [results]="results"
4750 [colors]="colors"
4751 [showPercentage]="true"
4752 [tooltipDisabled]="tooltipDisabled"
4753 [tooltipTemplate]="seriesTooltipTemplate"
4754 (hover)="updateHoveredVertical($event)"
4755 />
4756
4757 <svg:g *ngFor="let series of results">
4758 <svg:g
4759 ngx-charts-circle-series
4760 [type]="seriesType.Stacked"
4761 [xScale]="xScale"
4762 [yScale]="yScale"
4763 [colors]="colors"
4764 [activeEntries]="activeEntries"
4765 [data]="series"
4766 [scaleType]="scaleType"
4767 [visibleValue]="hoveredVertical"
4768 [tooltipDisabled]="tooltipDisabled"
4769 [tooltipTemplate]="tooltipTemplate"
4770 (select)="onClick($event, series)"
4771 (activate)="onActivate($event)"
4772 (deactivate)="onDeactivate($event)"
4773 />
4774 </svg:g>
4775 </svg:g>
4776 </svg:g>
4777 </svg:g>
4778 <svg:g
4779 ngx-charts-timeline
4780 *ngIf="timeline && scaleType != 'ordinal'"
4781 [attr.transform]="timelineTransform"
4782 [results]="results"
4783 [view]="[timelineWidth, height]"
4784 [height]="timelineHeight"
4785 [scheme]="scheme"
4786 [customColors]="customColors"
4787 [legend]="legend"
4788 [scaleType]="scaleType"
4789 (onDomainChange)="updateDomain($event)"
4790 >
4791 <svg:g *ngFor="let series of results; trackBy: trackBy">
4792 <svg:g
4793 ngx-charts-area-series
4794 [xScale]="timelineXScale"
4795 [yScale]="timelineYScale"
4796 [colors]="colors"
4797 [data]="series"
4798 [scaleType]="scaleType"
4799 [gradient]="gradient"
4800 [normalized]="true"
4801 [curve]="curve"
4802 [animations]="animations"
4803 />
4804 </svg:g>
4805 </svg:g>
4806 </ngx-charts-chart>
4807 `,
4808 changeDetection: ChangeDetectionStrategy.OnPush,
4809 encapsulation: ViewEncapsulation.None,
4810 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
4811 },] }
4812];
4813AreaChartNormalizedComponent.propDecorators = {
4814 legend: [{ type: Input }],
4815 legendTitle: [{ type: Input }],
4816 legendPosition: [{ type: Input }],
4817 xAxis: [{ type: Input }],
4818 yAxis: [{ type: Input }],
4819 showXAxisLabel: [{ type: Input }],
4820 showYAxisLabel: [{ type: Input }],
4821 xAxisLabel: [{ type: Input }],
4822 yAxisLabel: [{ type: Input }],
4823 timeline: [{ type: Input }],
4824 gradient: [{ type: Input }],
4825 showGridLines: [{ type: Input }],
4826 curve: [{ type: Input }],
4827 activeEntries: [{ type: Input }],
4828 schemeType: [{ type: Input }],
4829 trimXAxisTicks: [{ type: Input }],
4830 trimYAxisTicks: [{ type: Input }],
4831 rotateXAxisTicks: [{ type: Input }],
4832 maxXAxisTickLength: [{ type: Input }],
4833 maxYAxisTickLength: [{ type: Input }],
4834 xAxisTickFormatting: [{ type: Input }],
4835 yAxisTickFormatting: [{ type: Input }],
4836 xAxisTicks: [{ type: Input }],
4837 yAxisTicks: [{ type: Input }],
4838 roundDomains: [{ type: Input }],
4839 tooltipDisabled: [{ type: Input }],
4840 activate: [{ type: Output }],
4841 deactivate: [{ type: Output }],
4842 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
4843 seriesTooltipTemplate: [{ type: ContentChild, args: ['seriesTooltipTemplate',] }],
4844 hideCircles: [{ type: HostListener, args: ['mouseleave',] }]
4845};
4846
4847class AreaChartStackedComponent extends BaseChartComponent {
4848 constructor() {
4849 super(...arguments);
4850 this.legend = false;
4851 this.legendTitle = 'Legend';
4852 this.legendPosition = LegendPosition.Right;
4853 this.xAxis = false;
4854 this.yAxis = false;
4855 this.timeline = false;
4856 this.showGridLines = true;
4857 this.curve = curveLinear;
4858 this.activeEntries = [];
4859 this.trimXAxisTicks = true;
4860 this.trimYAxisTicks = true;
4861 this.rotateXAxisTicks = true;
4862 this.maxXAxisTickLength = 16;
4863 this.maxYAxisTickLength = 16;
4864 this.roundDomains = false;
4865 this.tooltipDisabled = false;
4866 this.activate = new EventEmitter();
4867 this.deactivate = new EventEmitter();
4868 this.margin = [10, 20, 10, 20];
4869 this.xAxisHeight = 0;
4870 this.yAxisWidth = 0;
4871 this.timelineHeight = 50;
4872 this.timelinePadding = 10;
4873 this.seriesType = SeriesType;
4874 }
4875 update() {
4876 super.update();
4877 this.dims = calculateViewDimensions({
4878 width: this.width,
4879 height: this.height,
4880 margins: this.margin,
4881 showXAxis: this.xAxis,
4882 showYAxis: this.yAxis,
4883 xAxisHeight: this.xAxisHeight,
4884 yAxisWidth: this.yAxisWidth,
4885 showXLabel: this.showXAxisLabel,
4886 showYLabel: this.showYAxisLabel,
4887 showLegend: this.legend,
4888 legendType: this.schemeType,
4889 legendPosition: this.legendPosition
4890 });
4891 if (this.timeline) {
4892 this.dims.height -= this.timelineHeight + this.margin[2] + this.timelinePadding;
4893 }
4894 this.xDomain = this.getXDomain();
4895 if (this.filteredDomain) {
4896 this.xDomain = this.filteredDomain;
4897 }
4898 this.yDomain = this.getYDomain();
4899 this.seriesDomain = this.getSeriesDomain();
4900 this.xScale = this.getXScale(this.xDomain, this.dims.width);
4901 this.yScale = this.getYScale(this.yDomain, this.dims.height);
4902 for (let i = 0; i < this.xSet.length; i++) {
4903 const val = this.xSet[i];
4904 let d0 = 0;
4905 for (const group of this.results) {
4906 let d = group.series.find(item => {
4907 let a = item.name;
4908 let b = val;
4909 if (this.scaleType === ScaleType.Time) {
4910 a = a.valueOf();
4911 b = b.valueOf();
4912 }
4913 return a === b;
4914 });
4915 if (d) {
4916 d.d0 = d0;
4917 d.d1 = d0 + d.value;
4918 d0 += d.value;
4919 }
4920 else {
4921 d = {
4922 name: val,
4923 value: 0,
4924 d0,
4925 d1: d0
4926 };
4927 group.series.push(d);
4928 }
4929 }
4930 }
4931 this.updateTimeline();
4932 this.setColors();
4933 this.legendOptions = this.getLegendOptions();
4934 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
4935 this.clipPathId = 'clip' + id().toString();
4936 this.clipPath = `url(#${this.clipPathId})`;
4937 }
4938 updateTimeline() {
4939 if (this.timeline) {
4940 this.timelineWidth = this.dims.width;
4941 this.timelineXDomain = this.getXDomain();
4942 this.timelineXScale = this.getXScale(this.timelineXDomain, this.timelineWidth);
4943 this.timelineYScale = this.getYScale(this.yDomain, this.timelineHeight);
4944 this.timelineTransform = `translate(${this.dims.xOffset}, ${-this.margin[2]})`;
4945 }
4946 }
4947 getXDomain() {
4948 let values = getUniqueXDomainValues(this.results);
4949 this.scaleType = getScaleType(values);
4950 let domain = [];
4951 if (this.scaleType === ScaleType.Linear) {
4952 values = values.map(v => Number(v));
4953 }
4954 let min;
4955 let max;
4956 if (this.scaleType === ScaleType.Time || this.scaleType === ScaleType.Linear) {
4957 min = this.xScaleMin ? this.xScaleMin : Math.min(...values);
4958 max = this.xScaleMax ? this.xScaleMax : Math.max(...values);
4959 }
4960 if (this.scaleType === ScaleType.Time) {
4961 domain = [new Date(min), new Date(max)];
4962 this.xSet = [...values].sort((a, b) => {
4963 const aDate = a.getTime();
4964 const bDate = b.getTime();
4965 if (aDate > bDate)
4966 return 1;
4967 if (bDate > aDate)
4968 return -1;
4969 return 0;
4970 });
4971 }
4972 else if (this.scaleType === ScaleType.Linear) {
4973 domain = [min, max];
4974 // Use compare function to sort numbers numerically
4975 this.xSet = [...values].sort((a, b) => a - b);
4976 }
4977 else {
4978 domain = values;
4979 this.xSet = values;
4980 }
4981 return domain;
4982 }
4983 getYDomain() {
4984 const domain = [];
4985 for (let i = 0; i < this.xSet.length; i++) {
4986 const val = this.xSet[i];
4987 let sum = 0;
4988 for (const group of this.results) {
4989 const d = group.series.find(item => {
4990 let a = item.name;
4991 let b = val;
4992 if (this.scaleType === ScaleType.Time) {
4993 a = a.valueOf();
4994 b = b.valueOf();
4995 }
4996 return a === b;
4997 });
4998 if (d) {
4999 sum += d.value;
5000 }
5001 }
5002 domain.push(sum);
5003 }
5004 const min = this.yScaleMin ? this.yScaleMin : Math.min(0, ...domain);
5005 const max = this.yScaleMax ? this.yScaleMax : Math.max(...domain);
5006 return [min, max];
5007 }
5008 getSeriesDomain() {
5009 return this.results.map(d => d.name);
5010 }
5011 getXScale(domain, width) {
5012 let scale;
5013 if (this.scaleType === ScaleType.Time) {
5014 scale = scaleTime();
5015 }
5016 else if (this.scaleType === ScaleType.Linear) {
5017 scale = scaleLinear();
5018 }
5019 else if (this.scaleType === ScaleType.Ordinal) {
5020 scale = scalePoint().padding(0.1);
5021 }
5022 scale.range([0, width]).domain(domain);
5023 return this.roundDomains ? scale.nice() : scale;
5024 }
5025 getYScale(domain, height) {
5026 const scale = scaleLinear().range([height, 0]).domain(domain);
5027 return this.roundDomains ? scale.nice() : scale;
5028 }
5029 updateDomain(domain) {
5030 this.filteredDomain = domain;
5031 this.xDomain = this.filteredDomain;
5032 this.xScale = this.getXScale(this.xDomain, this.dims.width);
5033 }
5034 updateHoveredVertical(item) {
5035 this.hoveredVertical = item.value;
5036 this.deactivateAll();
5037 }
5038 hideCircles() {
5039 this.hoveredVertical = null;
5040 this.deactivateAll();
5041 }
5042 onClick(data, series) {
5043 if (series) {
5044 data.series = series.name;
5045 }
5046 this.select.emit(data);
5047 }
5048 trackBy(index, item) {
5049 return `${item.name}`;
5050 }
5051 setColors() {
5052 let domain;
5053 if (this.schemeType === ScaleType.Ordinal) {
5054 domain = this.seriesDomain;
5055 }
5056 else {
5057 domain = this.yDomain;
5058 }
5059 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
5060 }
5061 getLegendOptions() {
5062 const opts = {
5063 scaleType: this.schemeType,
5064 colors: undefined,
5065 domain: [],
5066 title: undefined,
5067 position: this.legendPosition
5068 };
5069 if (opts.scaleType === ScaleType.Ordinal) {
5070 opts.domain = this.seriesDomain;
5071 opts.colors = this.colors;
5072 opts.title = this.legendTitle;
5073 }
5074 else {
5075 opts.domain = this.yDomain;
5076 opts.colors = this.colors.scale;
5077 }
5078 return opts;
5079 }
5080 updateYAxisWidth({ width }) {
5081 this.yAxisWidth = width;
5082 this.update();
5083 }
5084 updateXAxisHeight({ height }) {
5085 this.xAxisHeight = height;
5086 this.update();
5087 }
5088 onActivate(item) {
5089 const idx = this.activeEntries.findIndex(d => {
5090 return d.name === item.name && d.value === item.value;
5091 });
5092 if (idx > -1) {
5093 return;
5094 }
5095 this.activeEntries = [item, ...this.activeEntries];
5096 this.activate.emit({ value: item, entries: this.activeEntries });
5097 }
5098 onDeactivate(item) {
5099 const idx = this.activeEntries.findIndex(d => {
5100 return d.name === item.name && d.value === item.value;
5101 });
5102 this.activeEntries.splice(idx, 1);
5103 this.activeEntries = [...this.activeEntries];
5104 this.deactivate.emit({ value: item, entries: this.activeEntries });
5105 }
5106 deactivateAll() {
5107 this.activeEntries = [...this.activeEntries];
5108 for (const entry of this.activeEntries) {
5109 this.deactivate.emit({ value: entry, entries: [] });
5110 }
5111 this.activeEntries = [];
5112 }
5113}
5114AreaChartStackedComponent.decorators = [
5115 { type: Component, args: [{
5116 selector: 'ngx-charts-area-chart-stacked',
5117 template: `
5118 <ngx-charts-chart
5119 [view]="[width, height]"
5120 [showLegend]="legend"
5121 [legendOptions]="legendOptions"
5122 [activeEntries]="activeEntries"
5123 [animations]="animations"
5124 (legendLabelClick)="onClick($event)"
5125 (legendLabelActivate)="onActivate($event)"
5126 (legendLabelDeactivate)="onDeactivate($event)"
5127 >
5128 <svg:defs>
5129 <svg:clipPath [attr.id]="clipPathId">
5130 <svg:rect
5131 [attr.width]="dims.width + 10"
5132 [attr.height]="dims.height + 10"
5133 [attr.transform]="'translate(-5, -5)'"
5134 />
5135 </svg:clipPath>
5136 </svg:defs>
5137 <svg:g [attr.transform]="transform" class="area-chart chart">
5138 <svg:g
5139 ngx-charts-x-axis
5140 *ngIf="xAxis"
5141 [xScale]="xScale"
5142 [dims]="dims"
5143 [showGridLines]="showGridLines"
5144 [showLabel]="showXAxisLabel"
5145 [labelText]="xAxisLabel"
5146 [trimTicks]="trimXAxisTicks"
5147 [rotateTicks]="rotateXAxisTicks"
5148 [maxTickLength]="maxXAxisTickLength"
5149 [tickFormatting]="xAxisTickFormatting"
5150 [ticks]="xAxisTicks"
5151 (dimensionsChanged)="updateXAxisHeight($event)"
5152 ></svg:g>
5153 <svg:g
5154 ngx-charts-y-axis
5155 *ngIf="yAxis"
5156 [yScale]="yScale"
5157 [dims]="dims"
5158 [showGridLines]="showGridLines"
5159 [showLabel]="showYAxisLabel"
5160 [labelText]="yAxisLabel"
5161 [trimTicks]="trimYAxisTicks"
5162 [maxTickLength]="maxYAxisTickLength"
5163 [tickFormatting]="yAxisTickFormatting"
5164 [ticks]="yAxisTicks"
5165 (dimensionsChanged)="updateYAxisWidth($event)"
5166 ></svg:g>
5167 <svg:g [attr.clip-path]="clipPath">
5168 <svg:g *ngFor="let series of results; trackBy: trackBy">
5169 <svg:g
5170 ngx-charts-area-series
5171 [xScale]="xScale"
5172 [yScale]="yScale"
5173 [colors]="colors"
5174 [data]="series"
5175 [scaleType]="scaleType"
5176 [gradient]="gradient"
5177 [activeEntries]="activeEntries"
5178 [stacked]="true"
5179 [curve]="curve"
5180 [animations]="animations"
5181 />
5182 </svg:g>
5183
5184 <svg:g *ngIf="!tooltipDisabled" (mouseleave)="hideCircles()">
5185 <svg:g
5186 ngx-charts-tooltip-area
5187 [dims]="dims"
5188 [xSet]="xSet"
5189 [xScale]="xScale"
5190 [yScale]="yScale"
5191 [results]="results"
5192 [colors]="colors"
5193 [tooltipDisabled]="tooltipDisabled"
5194 [tooltipTemplate]="seriesTooltipTemplate"
5195 (hover)="updateHoveredVertical($event)"
5196 />
5197
5198 <svg:g *ngFor="let series of results; trackBy: trackBy">
5199 <svg:g
5200 ngx-charts-circle-series
5201 [type]="seriesType.Stacked"
5202 [xScale]="xScale"
5203 [yScale]="yScale"
5204 [colors]="colors"
5205 [activeEntries]="activeEntries"
5206 [data]="series"
5207 [scaleType]="scaleType"
5208 [visibleValue]="hoveredVertical"
5209 [tooltipDisabled]="tooltipDisabled"
5210 [tooltipTemplate]="tooltipTemplate"
5211 (select)="onClick($event, series)"
5212 (activate)="onActivate($event)"
5213 (deactivate)="onDeactivate($event)"
5214 />
5215 </svg:g>
5216 </svg:g>
5217 </svg:g>
5218 </svg:g>
5219 <svg:g
5220 ngx-charts-timeline
5221 *ngIf="timeline && scaleType != 'ordinal'"
5222 [attr.transform]="timelineTransform"
5223 [results]="results"
5224 [view]="[timelineWidth, height]"
5225 [height]="timelineHeight"
5226 [scheme]="scheme"
5227 [customColors]="customColors"
5228 [legend]="legend"
5229 [scaleType]="scaleType"
5230 (onDomainChange)="updateDomain($event)"
5231 >
5232 <svg:g *ngFor="let series of results; trackBy: trackBy">
5233 <svg:g
5234 ngx-charts-area-series
5235 [xScale]="timelineXScale"
5236 [yScale]="timelineYScale"
5237 [colors]="colors"
5238 [data]="series"
5239 [scaleType]="scaleType"
5240 [gradient]="gradient"
5241 [stacked]="true"
5242 [curve]="curve"
5243 [animations]="animations"
5244 />
5245 </svg:g>
5246 </svg:g>
5247 </ngx-charts-chart>
5248 `,
5249 changeDetection: ChangeDetectionStrategy.OnPush,
5250 encapsulation: ViewEncapsulation.None,
5251 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
5252 },] }
5253];
5254AreaChartStackedComponent.propDecorators = {
5255 legend: [{ type: Input }],
5256 legendTitle: [{ type: Input }],
5257 legendPosition: [{ type: Input }],
5258 xAxis: [{ type: Input }],
5259 yAxis: [{ type: Input }],
5260 showXAxisLabel: [{ type: Input }],
5261 showYAxisLabel: [{ type: Input }],
5262 xAxisLabel: [{ type: Input }],
5263 yAxisLabel: [{ type: Input }],
5264 timeline: [{ type: Input }],
5265 gradient: [{ type: Input }],
5266 showGridLines: [{ type: Input }],
5267 curve: [{ type: Input }],
5268 activeEntries: [{ type: Input }],
5269 schemeType: [{ type: Input }],
5270 trimXAxisTicks: [{ type: Input }],
5271 trimYAxisTicks: [{ type: Input }],
5272 rotateXAxisTicks: [{ type: Input }],
5273 maxXAxisTickLength: [{ type: Input }],
5274 maxYAxisTickLength: [{ type: Input }],
5275 xAxisTickFormatting: [{ type: Input }],
5276 yAxisTickFormatting: [{ type: Input }],
5277 xAxisTicks: [{ type: Input }],
5278 yAxisTicks: [{ type: Input }],
5279 roundDomains: [{ type: Input }],
5280 tooltipDisabled: [{ type: Input }],
5281 xScaleMin: [{ type: Input }],
5282 xScaleMax: [{ type: Input }],
5283 yScaleMin: [{ type: Input }],
5284 yScaleMax: [{ type: Input }],
5285 activate: [{ type: Output }],
5286 deactivate: [{ type: Output }],
5287 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
5288 seriesTooltipTemplate: [{ type: ContentChild, args: ['seriesTooltipTemplate',] }],
5289 hideCircles: [{ type: HostListener, args: ['mouseleave',] }]
5290};
5291
5292function sortLinear(data, property, direction = 'asc') {
5293 return data.sort((a, b) => {
5294 if (direction === 'asc') {
5295 return a[property] - b[property];
5296 }
5297 else {
5298 return b[property] - a[property];
5299 }
5300 });
5301}
5302function sortByDomain(data, property, direction = 'asc', domain) {
5303 return data.sort((a, b) => {
5304 const aVal = a[property];
5305 const bVal = b[property];
5306 const aIdx = domain.indexOf(aVal);
5307 const bIdx = domain.indexOf(bVal);
5308 if (direction === 'asc') {
5309 return aIdx - bIdx;
5310 }
5311 else {
5312 return bIdx - aIdx;
5313 }
5314 });
5315}
5316function sortByTime(data, property, direction = 'asc') {
5317 return data.sort((a, b) => {
5318 const aDate = a[property].getTime();
5319 const bDate = b[property].getTime();
5320 if (direction === 'asc') {
5321 if (aDate > bDate)
5322 return 1;
5323 if (bDate > aDate)
5324 return -1;
5325 return 0;
5326 }
5327 else {
5328 if (aDate > bDate)
5329 return -1;
5330 if (bDate > aDate)
5331 return 1;
5332 return 0;
5333 }
5334 });
5335}
5336
5337class AreaSeriesComponent {
5338 constructor() {
5339 this.baseValue = 'auto';
5340 this.stacked = false;
5341 this.normalized = false;
5342 this.animations = true;
5343 this.select = new EventEmitter();
5344 }
5345 ngOnChanges(changes) {
5346 this.update();
5347 }
5348 update() {
5349 this.updateGradient();
5350 let currentArea;
5351 let startingArea;
5352 const xProperty = d => {
5353 const label = d.name;
5354 return this.xScale(label);
5355 };
5356 if (this.stacked || this.normalized) {
5357 currentArea = area()
5358 .x(xProperty)
5359 .y0((d, i) => this.yScale(d.d0))
5360 .y1((d, i) => this.yScale(d.d1));
5361 startingArea = area()
5362 .x(xProperty)
5363 .y0(d => this.yScale.range()[0])
5364 .y1(d => this.yScale.range()[0]);
5365 }
5366 else {
5367 currentArea = area()
5368 .x(xProperty)
5369 .y0(() => (this.baseValue === 'auto' ? this.yScale.range()[0] : this.yScale(this.baseValue)))
5370 .y1(d => this.yScale(d.value));
5371 startingArea = area()
5372 .x(xProperty)
5373 .y0(d => (this.baseValue === 'auto' ? this.yScale.range()[0] : this.yScale(this.baseValue)))
5374 .y1(d => (this.baseValue === 'auto' ? this.yScale.range()[0] : this.yScale(this.baseValue)));
5375 }
5376 currentArea.curve(this.curve);
5377 startingArea.curve(this.curve);
5378 this.opacity = 0.8;
5379 let data = this.data.series;
5380 if (this.scaleType === ScaleType.Linear) {
5381 data = sortLinear(data, 'name');
5382 }
5383 else if (this.scaleType === ScaleType.Time) {
5384 data = sortByTime(data, 'name');
5385 }
5386 else {
5387 data = sortByDomain(data, 'name', 'asc', this.xScale.domain());
5388 }
5389 this.path = currentArea(data);
5390 this.startingPath = startingArea(data);
5391 }
5392 updateGradient() {
5393 if (this.colors.scaleType === ScaleType.Linear) {
5394 this.hasGradient = true;
5395 if (this.stacked || this.normalized) {
5396 const d0values = this.data.series.map(d => d.d0);
5397 const d1values = this.data.series.map(d => d.d1);
5398 const max = Math.max(...d1values);
5399 const min = Math.min(...d0values);
5400 this.gradientStops = this.colors.getLinearGradientStops(max, min);
5401 }
5402 else {
5403 const values = this.data.series.map(d => d.value);
5404 const max = Math.max(...values);
5405 this.gradientStops = this.colors.getLinearGradientStops(max);
5406 }
5407 }
5408 else {
5409 this.hasGradient = false;
5410 this.gradientStops = undefined;
5411 }
5412 }
5413 isActive(entry) {
5414 if (!this.activeEntries)
5415 return false;
5416 const item = this.activeEntries.find(d => {
5417 return entry.name === d.name;
5418 });
5419 return item !== undefined;
5420 }
5421 isInactive(entry) {
5422 if (!this.activeEntries || this.activeEntries.length === 0)
5423 return false;
5424 const item = this.activeEntries.find(d => {
5425 return entry.name === d.name;
5426 });
5427 return item === undefined;
5428 }
5429}
5430AreaSeriesComponent.decorators = [
5431 { type: Component, args: [{
5432 selector: 'g[ngx-charts-area-series]',
5433 template: `
5434 <svg:g
5435 ngx-charts-area
5436 class="area-series"
5437 [data]="data"
5438 [path]="path"
5439 [fill]="colors.getColor(data.name)"
5440 [stops]="gradientStops"
5441 [startingPath]="startingPath"
5442 [opacity]="opacity"
5443 [gradient]="gradient || hasGradient"
5444 [animations]="animations"
5445 [class.active]="isActive(data)"
5446 [class.inactive]="isInactive(data)"
5447 />
5448 `,
5449 changeDetection: ChangeDetectionStrategy.OnPush
5450 },] }
5451];
5452AreaSeriesComponent.propDecorators = {
5453 data: [{ type: Input }],
5454 xScale: [{ type: Input }],
5455 yScale: [{ type: Input }],
5456 baseValue: [{ type: Input }],
5457 colors: [{ type: Input }],
5458 scaleType: [{ type: Input }],
5459 stacked: [{ type: Input }],
5460 normalized: [{ type: Input }],
5461 gradient: [{ type: Input }],
5462 curve: [{ type: Input }],
5463 activeEntries: [{ type: Input }],
5464 animations: [{ type: Input }],
5465 select: [{ type: Output }]
5466};
5467
5468class AreaChartModule {
5469}
5470AreaChartModule.decorators = [
5471 { type: NgModule, args: [{
5472 imports: [ChartCommonModule],
5473 declarations: [AreaChartComponent, AreaChartNormalizedComponent, AreaChartStackedComponent, AreaSeriesComponent],
5474 exports: [AreaChartComponent, AreaChartNormalizedComponent, AreaChartStackedComponent, AreaSeriesComponent]
5475 },] }
5476];
5477
5478class BarComponent {
5479 constructor(element) {
5480 this.roundEdges = true;
5481 this.gradient = false;
5482 this.offset = 0;
5483 this.isActive = false;
5484 this.animations = true;
5485 this.noBarWhenZero = true;
5486 this.select = new EventEmitter();
5487 this.activate = new EventEmitter();
5488 this.deactivate = new EventEmitter();
5489 this.hasGradient = false;
5490 this.hideBar = false;
5491 this.element = element.nativeElement;
5492 }
5493 ngOnChanges(changes) {
5494 if (changes.roundEdges) {
5495 this.loadAnimation();
5496 }
5497 this.update();
5498 }
5499 update() {
5500 this.gradientId = 'grad' + id().toString();
5501 this.gradientFill = `url(#${this.gradientId})`;
5502 if (this.gradient || this.stops) {
5503 this.gradientStops = this.getGradient();
5504 this.hasGradient = true;
5505 }
5506 else {
5507 this.hasGradient = false;
5508 }
5509 this.updatePathEl();
5510 this.checkToHideBar();
5511 }
5512 loadAnimation() {
5513 this.path = this.getStartingPath();
5514 setTimeout(this.update.bind(this), 100);
5515 }
5516 updatePathEl() {
5517 const node = select(this.element).select('.bar');
5518 const path = this.getPath();
5519 if (this.animations) {
5520 node.transition().duration(500).attr('d', path);
5521 }
5522 else {
5523 node.attr('d', path);
5524 }
5525 }
5526 getGradient() {
5527 if (this.stops) {
5528 return this.stops;
5529 }
5530 return [
5531 {
5532 offset: 0,
5533 color: this.fill,
5534 opacity: this.getStartOpacity()
5535 },
5536 {
5537 offset: 100,
5538 color: this.fill,
5539 opacity: 1
5540 }
5541 ];
5542 }
5543 getStartingPath() {
5544 if (!this.animations) {
5545 return this.getPath();
5546 }
5547 let radius = this.getRadius();
5548 let path;
5549 if (this.roundEdges) {
5550 if (this.orientation === BarOrientation.Vertical) {
5551 radius = Math.min(this.height, radius);
5552 path = roundedRect(this.x, this.y + this.height, this.width, 1, 0, this.edges);
5553 }
5554 else if (this.orientation === BarOrientation.Horizontal) {
5555 radius = Math.min(this.width, radius);
5556 path = roundedRect(this.x, this.y, 1, this.height, 0, this.edges);
5557 }
5558 }
5559 else {
5560 if (this.orientation === BarOrientation.Vertical) {
5561 path = roundedRect(this.x, this.y + this.height, this.width, 1, 0, this.edges);
5562 }
5563 else if (this.orientation === BarOrientation.Horizontal) {
5564 path = roundedRect(this.x, this.y, 1, this.height, 0, this.edges);
5565 }
5566 }
5567 return path;
5568 }
5569 getPath() {
5570 let radius = this.getRadius();
5571 let path;
5572 if (this.roundEdges) {
5573 if (this.orientation === BarOrientation.Vertical) {
5574 radius = Math.min(this.height, radius);
5575 path = roundedRect(this.x, this.y, this.width, this.height, radius, this.edges);
5576 }
5577 else if (this.orientation === BarOrientation.Horizontal) {
5578 radius = Math.min(this.width, radius);
5579 path = roundedRect(this.x, this.y, this.width, this.height, radius, this.edges);
5580 }
5581 }
5582 else {
5583 path = roundedRect(this.x, this.y, this.width, this.height, radius, this.edges);
5584 }
5585 return path;
5586 }
5587 getRadius() {
5588 let radius = 0;
5589 if (this.roundEdges && this.height > 5 && this.width > 5) {
5590 radius = Math.floor(Math.min(5, this.height / 2, this.width / 2));
5591 }
5592 return radius;
5593 }
5594 getStartOpacity() {
5595 if (this.roundEdges) {
5596 return 0.2;
5597 }
5598 else {
5599 return 0.5;
5600 }
5601 }
5602 get edges() {
5603 let edges = [false, false, false, false];
5604 if (this.roundEdges) {
5605 if (this.orientation === BarOrientation.Vertical) {
5606 if (this.data.value > 0) {
5607 edges = [true, true, false, false];
5608 }
5609 else {
5610 edges = [false, false, true, true];
5611 }
5612 }
5613 else if (this.orientation === BarOrientation.Horizontal) {
5614 if (this.data.value > 0) {
5615 edges = [false, true, false, true];
5616 }
5617 else {
5618 edges = [true, false, true, false];
5619 }
5620 }
5621 }
5622 return edges;
5623 }
5624 onMouseEnter() {
5625 this.activate.emit(this.data);
5626 }
5627 onMouseLeave() {
5628 this.deactivate.emit(this.data);
5629 }
5630 checkToHideBar() {
5631 this.hideBar =
5632 this.noBarWhenZero &&
5633 ((this.orientation === BarOrientation.Vertical && this.height === 0) ||
5634 (this.orientation === BarOrientation.Horizontal && this.width === 0));
5635 }
5636}
5637BarComponent.decorators = [
5638 { type: Component, args: [{
5639 selector: 'g[ngx-charts-bar]',
5640 template: `
5641 <svg:defs *ngIf="hasGradient">
5642 <svg:g ngx-charts-svg-linear-gradient [orientation]="orientation" [name]="gradientId" [stops]="gradientStops" />
5643 </svg:defs>
5644 <svg:path
5645 class="bar"
5646 stroke="none"
5647 role="img"
5648 tabIndex="-1"
5649 [class.active]="isActive"
5650 [class.hidden]="hideBar"
5651 [attr.d]="path"
5652 [attr.aria-label]="ariaLabel"
5653 [attr.fill]="hasGradient ? gradientFill : fill"
5654 (click)="select.emit(data)"
5655 />
5656 `,
5657 changeDetection: ChangeDetectionStrategy.OnPush
5658 },] }
5659];
5660BarComponent.ctorParameters = () => [
5661 { type: ElementRef }
5662];
5663BarComponent.propDecorators = {
5664 fill: [{ type: Input }],
5665 data: [{ type: Input }],
5666 width: [{ type: Input }],
5667 height: [{ type: Input }],
5668 x: [{ type: Input }],
5669 y: [{ type: Input }],
5670 orientation: [{ type: Input }],
5671 roundEdges: [{ type: Input }],
5672 gradient: [{ type: Input }],
5673 offset: [{ type: Input }],
5674 isActive: [{ type: Input }],
5675 stops: [{ type: Input }],
5676 animations: [{ type: Input }],
5677 ariaLabel: [{ type: Input }],
5678 noBarWhenZero: [{ type: Input }],
5679 select: [{ type: Output }],
5680 activate: [{ type: Output }],
5681 deactivate: [{ type: Output }],
5682 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
5683 onMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
5684};
5685
5686class BarHorizontalComponent extends BaseChartComponent {
5687 constructor() {
5688 super(...arguments);
5689 this.legend = false;
5690 this.legendTitle = 'Legend';
5691 this.legendPosition = LegendPosition.Right;
5692 this.tooltipDisabled = false;
5693 this.showGridLines = true;
5694 this.activeEntries = [];
5695 this.trimXAxisTicks = true;
5696 this.trimYAxisTicks = true;
5697 this.rotateXAxisTicks = true;
5698 this.maxXAxisTickLength = 16;
5699 this.maxYAxisTickLength = 16;
5700 this.barPadding = 8;
5701 this.roundDomains = false;
5702 this.roundEdges = true;
5703 this.showDataLabel = false;
5704 this.noBarWhenZero = true;
5705 this.activate = new EventEmitter();
5706 this.deactivate = new EventEmitter();
5707 this.margin = [10, 20, 10, 20];
5708 this.xAxisHeight = 0;
5709 this.yAxisWidth = 0;
5710 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
5711 }
5712 update() {
5713 super.update();
5714 if (!this.showDataLabel) {
5715 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
5716 }
5717 this.margin = [10, 20 + this.dataLabelMaxWidth.positive, 10, 20 + this.dataLabelMaxWidth.negative];
5718 this.dims = calculateViewDimensions({
5719 width: this.width,
5720 height: this.height,
5721 margins: this.margin,
5722 showXAxis: this.xAxis,
5723 showYAxis: this.yAxis,
5724 xAxisHeight: this.xAxisHeight,
5725 yAxisWidth: this.yAxisWidth,
5726 showXLabel: this.showXAxisLabel,
5727 showYLabel: this.showYAxisLabel,
5728 showLegend: this.legend,
5729 legendType: this.schemeType,
5730 legendPosition: this.legendPosition
5731 });
5732 this.formatDates();
5733 this.xScale = this.getXScale();
5734 this.yScale = this.getYScale();
5735 this.setColors();
5736 this.legendOptions = this.getLegendOptions();
5737 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
5738 }
5739 getXScale() {
5740 this.xDomain = this.getXDomain();
5741 const scale = scaleLinear().range([0, this.dims.width]).domain(this.xDomain);
5742 return this.roundDomains ? scale.nice() : scale;
5743 }
5744 getYScale() {
5745 this.yDomain = this.getYDomain();
5746 const spacing = this.yDomain.length / (this.dims.height / this.barPadding + 1);
5747 return scaleBand().rangeRound([0, this.dims.height]).paddingInner(spacing).domain(this.yDomain);
5748 }
5749 getXDomain() {
5750 const values = this.results.map(d => d.value);
5751 const min = this.xScaleMin ? Math.min(this.xScaleMin, ...values) : Math.min(0, ...values);
5752 const max = this.xScaleMax ? Math.max(this.xScaleMax, ...values) : Math.max(0, ...values);
5753 return [min, max];
5754 }
5755 getYDomain() {
5756 return this.results.map(d => d.label);
5757 }
5758 onClick(data) {
5759 this.select.emit(data);
5760 }
5761 setColors() {
5762 let domain;
5763 if (this.schemeType === ScaleType.Ordinal) {
5764 domain = this.yDomain;
5765 }
5766 else {
5767 domain = this.xDomain;
5768 }
5769 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
5770 }
5771 getLegendOptions() {
5772 const opts = {
5773 scaleType: this.schemeType,
5774 colors: undefined,
5775 domain: [],
5776 title: undefined,
5777 position: this.legendPosition
5778 };
5779 if (opts.scaleType === 'ordinal') {
5780 opts.domain = this.yDomain;
5781 opts.colors = this.colors;
5782 opts.title = this.legendTitle;
5783 }
5784 else {
5785 opts.domain = this.xDomain;
5786 opts.colors = this.colors.scale;
5787 }
5788 return opts;
5789 }
5790 updateYAxisWidth({ width }) {
5791 this.yAxisWidth = width;
5792 this.update();
5793 }
5794 updateXAxisHeight({ height }) {
5795 this.xAxisHeight = height;
5796 this.update();
5797 }
5798 onDataLabelMaxWidthChanged(event) {
5799 if (event.size.negative) {
5800 this.dataLabelMaxWidth.negative = Math.max(this.dataLabelMaxWidth.negative, event.size.width);
5801 }
5802 else {
5803 this.dataLabelMaxWidth.positive = Math.max(this.dataLabelMaxWidth.positive, event.size.width);
5804 }
5805 if (event.index === this.results.length - 1) {
5806 setTimeout(() => this.update());
5807 }
5808 }
5809 onActivate(item, fromLegend = false) {
5810 item = this.results.find(d => {
5811 if (fromLegend) {
5812 return d.label === item.name;
5813 }
5814 else {
5815 return d.name === item.name;
5816 }
5817 });
5818 const idx = this.activeEntries.findIndex(d => {
5819 return d.name === item.name && d.value === item.value && d.series === item.series;
5820 });
5821 if (idx > -1) {
5822 return;
5823 }
5824 this.activeEntries = [item, ...this.activeEntries];
5825 this.activate.emit({ value: item, entries: this.activeEntries });
5826 }
5827 onDeactivate(item, fromLegend = false) {
5828 item = this.results.find(d => {
5829 if (fromLegend) {
5830 return d.label === item.name;
5831 }
5832 else {
5833 return d.name === item.name;
5834 }
5835 });
5836 const idx = this.activeEntries.findIndex(d => {
5837 return d.name === item.name && d.value === item.value && d.series === item.series;
5838 });
5839 this.activeEntries.splice(idx, 1);
5840 this.activeEntries = [...this.activeEntries];
5841 this.deactivate.emit({ value: item, entries: this.activeEntries });
5842 }
5843}
5844BarHorizontalComponent.decorators = [
5845 { type: Component, args: [{
5846 selector: 'ngx-charts-bar-horizontal',
5847 template: `
5848 <ngx-charts-chart
5849 [view]="[width, height]"
5850 [showLegend]="legend"
5851 [legendOptions]="legendOptions"
5852 [activeEntries]="activeEntries"
5853 [animations]="animations"
5854 (legendLabelClick)="onClick($event)"
5855 (legendLabelActivate)="onActivate($event, true)"
5856 (legendLabelDeactivate)="onDeactivate($event, true)"
5857 >
5858 <svg:g [attr.transform]="transform" class="bar-chart chart">
5859 <svg:g
5860 ngx-charts-x-axis
5861 *ngIf="xAxis"
5862 [xScale]="xScale"
5863 [dims]="dims"
5864 [showGridLines]="showGridLines"
5865 [showLabel]="showXAxisLabel"
5866 [labelText]="xAxisLabel"
5867 [trimTicks]="trimXAxisTicks"
5868 [rotateTicks]="rotateXAxisTicks"
5869 [maxTickLength]="maxXAxisTickLength"
5870 [tickFormatting]="xAxisTickFormatting"
5871 [ticks]="xAxisTicks"
5872 (dimensionsChanged)="updateXAxisHeight($event)"
5873 ></svg:g>
5874 <svg:g
5875 ngx-charts-y-axis
5876 *ngIf="yAxis"
5877 [yScale]="yScale"
5878 [dims]="dims"
5879 [showLabel]="showYAxisLabel"
5880 [labelText]="yAxisLabel"
5881 [trimTicks]="trimYAxisTicks"
5882 [maxTickLength]="maxYAxisTickLength"
5883 [tickFormatting]="yAxisTickFormatting"
5884 [ticks]="yAxisTicks"
5885 [yAxisOffset]="dataLabelMaxWidth.negative"
5886 (dimensionsChanged)="updateYAxisWidth($event)"
5887 ></svg:g>
5888 <svg:g
5889 ngx-charts-series-horizontal
5890 [xScale]="xScale"
5891 [yScale]="yScale"
5892 [colors]="colors"
5893 [series]="results"
5894 [dims]="dims"
5895 [gradient]="gradient"
5896 [tooltipDisabled]="tooltipDisabled"
5897 [tooltipTemplate]="tooltipTemplate"
5898 [activeEntries]="activeEntries"
5899 [roundEdges]="roundEdges"
5900 [animations]="animations"
5901 [showDataLabel]="showDataLabel"
5902 [dataLabelFormatting]="dataLabelFormatting"
5903 [noBarWhenZero]="noBarWhenZero"
5904 (select)="onClick($event)"
5905 (activate)="onActivate($event)"
5906 (deactivate)="onDeactivate($event)"
5907 (dataLabelWidthChanged)="onDataLabelMaxWidthChanged($event)"
5908 ></svg:g>
5909 </svg:g>
5910 </ngx-charts-chart>
5911 `,
5912 changeDetection: ChangeDetectionStrategy.OnPush,
5913 encapsulation: ViewEncapsulation.None,
5914 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
5915 },] }
5916];
5917BarHorizontalComponent.propDecorators = {
5918 legend: [{ type: Input }],
5919 legendTitle: [{ type: Input }],
5920 legendPosition: [{ type: Input }],
5921 xAxis: [{ type: Input }],
5922 yAxis: [{ type: Input }],
5923 showXAxisLabel: [{ type: Input }],
5924 showYAxisLabel: [{ type: Input }],
5925 xAxisLabel: [{ type: Input }],
5926 yAxisLabel: [{ type: Input }],
5927 tooltipDisabled: [{ type: Input }],
5928 gradient: [{ type: Input }],
5929 showGridLines: [{ type: Input }],
5930 activeEntries: [{ type: Input }],
5931 schemeType: [{ type: Input }],
5932 trimXAxisTicks: [{ type: Input }],
5933 trimYAxisTicks: [{ type: Input }],
5934 rotateXAxisTicks: [{ type: Input }],
5935 maxXAxisTickLength: [{ type: Input }],
5936 maxYAxisTickLength: [{ type: Input }],
5937 xAxisTickFormatting: [{ type: Input }],
5938 yAxisTickFormatting: [{ type: Input }],
5939 xAxisTicks: [{ type: Input }],
5940 yAxisTicks: [{ type: Input }],
5941 barPadding: [{ type: Input }],
5942 roundDomains: [{ type: Input }],
5943 roundEdges: [{ type: Input }],
5944 xScaleMax: [{ type: Input }],
5945 xScaleMin: [{ type: Input }],
5946 showDataLabel: [{ type: Input }],
5947 dataLabelFormatting: [{ type: Input }],
5948 noBarWhenZero: [{ type: Input }],
5949 activate: [{ type: Output }],
5950 deactivate: [{ type: Output }],
5951 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
5952};
5953
5954class BarHorizontal2DComponent extends BaseChartComponent {
5955 constructor() {
5956 super(...arguments);
5957 this.legend = false;
5958 this.legendTitle = 'Legend';
5959 this.legendPosition = LegendPosition.Right;
5960 this.tooltipDisabled = false;
5961 this.showGridLines = true;
5962 this.activeEntries = [];
5963 this.trimXAxisTicks = true;
5964 this.trimYAxisTicks = true;
5965 this.rotateXAxisTicks = true;
5966 this.maxXAxisTickLength = 16;
5967 this.maxYAxisTickLength = 16;
5968 this.groupPadding = 16;
5969 this.barPadding = 8;
5970 this.roundDomains = false;
5971 this.roundEdges = true;
5972 this.showDataLabel = false;
5973 this.noBarWhenZero = true;
5974 this.activate = new EventEmitter();
5975 this.deactivate = new EventEmitter();
5976 this.margin = [10, 20, 10, 20];
5977 this.xAxisHeight = 0;
5978 this.yAxisWidth = 0;
5979 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
5980 this.barOrientation = BarOrientation;
5981 this.trackBy = (index, item) => {
5982 return item.name;
5983 };
5984 }
5985 update() {
5986 super.update();
5987 if (!this.showDataLabel) {
5988 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
5989 }
5990 this.margin = [10, 20 + this.dataLabelMaxWidth.positive, 10, 20 + this.dataLabelMaxWidth.negative];
5991 this.dims = calculateViewDimensions({
5992 width: this.width,
5993 height: this.height,
5994 margins: this.margin,
5995 showXAxis: this.xAxis,
5996 showYAxis: this.yAxis,
5997 xAxisHeight: this.xAxisHeight,
5998 yAxisWidth: this.yAxisWidth,
5999 showXLabel: this.showXAxisLabel,
6000 showYLabel: this.showYAxisLabel,
6001 showLegend: this.legend,
6002 legendType: this.schemeType,
6003 legendPosition: this.legendPosition
6004 });
6005 this.formatDates();
6006 this.groupDomain = this.getGroupDomain();
6007 this.innerDomain = this.getInnerDomain();
6008 this.valueDomain = this.getValueDomain();
6009 this.groupScale = this.getGroupScale();
6010 this.innerScale = this.getInnerScale();
6011 this.valueScale = this.getValueScale();
6012 this.setColors();
6013 this.legendOptions = this.getLegendOptions();
6014 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
6015 }
6016 getGroupScale() {
6017 const spacing = this.groupDomain.length / (this.dims.height / this.groupPadding + 1);
6018 return scaleBand()
6019 .rangeRound([0, this.dims.height])
6020 .paddingInner(spacing)
6021 .paddingOuter(spacing / 2)
6022 .domain(this.groupDomain);
6023 }
6024 getInnerScale() {
6025 const height = this.groupScale.bandwidth();
6026 const spacing = this.innerDomain.length / (height / this.barPadding + 1);
6027 return scaleBand().rangeRound([0, height]).paddingInner(spacing).domain(this.innerDomain);
6028 }
6029 getValueScale() {
6030 const scale = scaleLinear().range([0, this.dims.width]).domain(this.valueDomain);
6031 return this.roundDomains ? scale.nice() : scale;
6032 }
6033 getGroupDomain() {
6034 const domain = [];
6035 for (const group of this.results) {
6036 if (!domain.includes(group.label)) {
6037 domain.push(group.label);
6038 }
6039 }
6040 return domain;
6041 }
6042 getInnerDomain() {
6043 const domain = [];
6044 for (const group of this.results) {
6045 for (const d of group.series) {
6046 if (!domain.includes(d.label)) {
6047 domain.push(d.label);
6048 }
6049 }
6050 }
6051 return domain;
6052 }
6053 getValueDomain() {
6054 const domain = [];
6055 for (const group of this.results) {
6056 for (const d of group.series) {
6057 if (!domain.includes(d.value)) {
6058 domain.push(d.value);
6059 }
6060 }
6061 }
6062 const min = Math.min(0, ...domain);
6063 const max = this.xScaleMax ? Math.max(this.xScaleMax, ...domain) : Math.max(0, ...domain);
6064 return [min, max];
6065 }
6066 groupTransform(group) {
6067 return `translate(0, ${this.groupScale(group.label)})`;
6068 }
6069 onClick(data, group) {
6070 if (group) {
6071 data.series = group.name;
6072 }
6073 this.select.emit(data);
6074 }
6075 setColors() {
6076 let domain;
6077 if (this.schemeType === ScaleType.Ordinal) {
6078 domain = this.innerDomain;
6079 }
6080 else {
6081 domain = this.valueDomain;
6082 }
6083 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
6084 }
6085 getLegendOptions() {
6086 const opts = {
6087 scaleType: this.schemeType,
6088 colors: undefined,
6089 domain: [],
6090 title: undefined,
6091 position: this.legendPosition
6092 };
6093 if (opts.scaleType === ScaleType.Ordinal) {
6094 opts.domain = this.innerDomain;
6095 opts.colors = this.colors;
6096 opts.title = this.legendTitle;
6097 }
6098 else {
6099 opts.domain = this.valueDomain;
6100 opts.colors = this.colors.scale;
6101 }
6102 return opts;
6103 }
6104 updateYAxisWidth({ width }) {
6105 this.yAxisWidth = width;
6106 this.update();
6107 }
6108 updateXAxisHeight({ height }) {
6109 this.xAxisHeight = height;
6110 this.update();
6111 }
6112 onDataLabelMaxWidthChanged(event, groupIndex) {
6113 if (event.size.negative) {
6114 this.dataLabelMaxWidth.negative = Math.max(this.dataLabelMaxWidth.negative, event.size.width);
6115 }
6116 else {
6117 this.dataLabelMaxWidth.positive = Math.max(this.dataLabelMaxWidth.positive, event.size.width);
6118 }
6119 if (groupIndex === this.results.length - 1) {
6120 setTimeout(() => this.update());
6121 }
6122 }
6123 onActivate(event, group, fromLegend = false) {
6124 const item = Object.assign({}, event);
6125 if (group) {
6126 item.series = group.name;
6127 }
6128 const items = this.results
6129 .map(g => g.series)
6130 .flat()
6131 .filter(i => {
6132 if (fromLegend) {
6133 return i.label === item.name;
6134 }
6135 else {
6136 return i.name === item.name && i.series === item.series;
6137 }
6138 });
6139 this.activeEntries = [...items];
6140 this.activate.emit({ value: item, entries: this.activeEntries });
6141 }
6142 onDeactivate(event, group, fromLegend = false) {
6143 const item = Object.assign({}, event);
6144 if (group) {
6145 item.series = group.name;
6146 }
6147 this.activeEntries = this.activeEntries.filter(i => {
6148 if (fromLegend) {
6149 return i.label !== item.name;
6150 }
6151 else {
6152 return !(i.name === item.name && i.series === item.series);
6153 }
6154 });
6155 this.deactivate.emit({ value: item, entries: this.activeEntries });
6156 }
6157}
6158BarHorizontal2DComponent.decorators = [
6159 { type: Component, args: [{
6160 selector: 'ngx-charts-bar-horizontal-2d',
6161 template: `
6162 <ngx-charts-chart
6163 [view]="[width, height]"
6164 [showLegend]="legend"
6165 [legendOptions]="legendOptions"
6166 [activeEntries]="activeEntries"
6167 [animations]="animations"
6168 (legendLabelActivate)="onActivate($event, undefined, true)"
6169 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
6170 (legendLabelClick)="onClick($event)"
6171 >
6172 <svg:g [attr.transform]="transform" class="bar-chart chart">
6173 <svg:g
6174 ngx-charts-grid-panel-series
6175 [xScale]="valueScale"
6176 [yScale]="groupScale"
6177 [data]="results"
6178 [dims]="dims"
6179 [orient]="barOrientation.Horizontal"
6180 ></svg:g>
6181 <svg:g
6182 ngx-charts-x-axis
6183 *ngIf="xAxis"
6184 [xScale]="valueScale"
6185 [dims]="dims"
6186 [showGridLines]="showGridLines"
6187 [showLabel]="showXAxisLabel"
6188 [labelText]="xAxisLabel"
6189 [trimTicks]="trimXAxisTicks"
6190 [rotateTicks]="rotateXAxisTicks"
6191 [maxTickLength]="maxXAxisTickLength"
6192 [tickFormatting]="xAxisTickFormatting"
6193 [ticks]="xAxisTicks"
6194 (dimensionsChanged)="updateXAxisHeight($event)"
6195 ></svg:g>
6196 <svg:g
6197 ngx-charts-y-axis
6198 *ngIf="yAxis"
6199 [yScale]="groupScale"
6200 [dims]="dims"
6201 [showLabel]="showYAxisLabel"
6202 [labelText]="yAxisLabel"
6203 [trimTicks]="trimYAxisTicks"
6204 [maxTickLength]="maxYAxisTickLength"
6205 [tickFormatting]="yAxisTickFormatting"
6206 [ticks]="yAxisTicks"
6207 [yAxisOffset]="dataLabelMaxWidth.negative"
6208 (dimensionsChanged)="updateYAxisWidth($event)"
6209 ></svg:g>
6210 <svg:g
6211 *ngFor="let group of results; let index = index; trackBy: trackBy"
6212 [@animationState]="'active'"
6213 [attr.transform]="groupTransform(group)"
6214 >
6215 <svg:g
6216 ngx-charts-series-horizontal
6217 [xScale]="valueScale"
6218 [activeEntries]="activeEntries"
6219 [yScale]="innerScale"
6220 [colors]="colors"
6221 [series]="group.series"
6222 [dims]="dims"
6223 [gradient]="gradient"
6224 [tooltipDisabled]="tooltipDisabled"
6225 [tooltipTemplate]="tooltipTemplate"
6226 [seriesName]="group.name"
6227 [roundEdges]="roundEdges"
6228 [animations]="animations"
6229 [showDataLabel]="showDataLabel"
6230 [dataLabelFormatting]="dataLabelFormatting"
6231 [noBarWhenZero]="noBarWhenZero"
6232 (select)="onClick($event, group)"
6233 (activate)="onActivate($event, group)"
6234 (deactivate)="onDeactivate($event, group)"
6235 (dataLabelWidthChanged)="onDataLabelMaxWidthChanged($event, index)"
6236 />
6237 </svg:g>
6238 </svg:g>
6239 </ngx-charts-chart>
6240 `,
6241 changeDetection: ChangeDetectionStrategy.OnPush,
6242 encapsulation: ViewEncapsulation.None,
6243 animations: [
6244 trigger('animationState', [
6245 transition(':leave', [
6246 style({
6247 opacity: 1,
6248 transform: '*'
6249 }),
6250 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
6251 ])
6252 ])
6253 ],
6254 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
6255 },] }
6256];
6257BarHorizontal2DComponent.propDecorators = {
6258 legend: [{ type: Input }],
6259 legendTitle: [{ type: Input }],
6260 legendPosition: [{ type: Input }],
6261 xAxis: [{ type: Input }],
6262 yAxis: [{ type: Input }],
6263 showXAxisLabel: [{ type: Input }],
6264 showYAxisLabel: [{ type: Input }],
6265 xAxisLabel: [{ type: Input }],
6266 yAxisLabel: [{ type: Input }],
6267 tooltipDisabled: [{ type: Input }],
6268 gradient: [{ type: Input }],
6269 showGridLines: [{ type: Input }],
6270 activeEntries: [{ type: Input }],
6271 schemeType: [{ type: Input }],
6272 trimXAxisTicks: [{ type: Input }],
6273 trimYAxisTicks: [{ type: Input }],
6274 rotateXAxisTicks: [{ type: Input }],
6275 maxXAxisTickLength: [{ type: Input }],
6276 maxYAxisTickLength: [{ type: Input }],
6277 xAxisTickFormatting: [{ type: Input }],
6278 yAxisTickFormatting: [{ type: Input }],
6279 xAxisTicks: [{ type: Input }],
6280 yAxisTicks: [{ type: Input }],
6281 groupPadding: [{ type: Input }],
6282 barPadding: [{ type: Input }],
6283 roundDomains: [{ type: Input }],
6284 roundEdges: [{ type: Input }],
6285 xScaleMax: [{ type: Input }],
6286 showDataLabel: [{ type: Input }],
6287 dataLabelFormatting: [{ type: Input }],
6288 noBarWhenZero: [{ type: Input }],
6289 activate: [{ type: Output }],
6290 deactivate: [{ type: Output }],
6291 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
6292};
6293
6294var BarChartType;
6295(function (BarChartType) {
6296 BarChartType["Standard"] = "standard";
6297 BarChartType["Normalized"] = "normalized";
6298 BarChartType["Stacked"] = "stacked";
6299})(BarChartType || (BarChartType = {}));
6300
6301class BarHorizontalNormalizedComponent extends BaseChartComponent {
6302 constructor() {
6303 super(...arguments);
6304 this.legend = false;
6305 this.legendTitle = 'Legend';
6306 this.legendPosition = LegendPosition.Right;
6307 this.tooltipDisabled = false;
6308 this.showGridLines = true;
6309 this.activeEntries = [];
6310 this.trimXAxisTicks = true;
6311 this.trimYAxisTicks = true;
6312 this.rotateXAxisTicks = true;
6313 this.maxXAxisTickLength = 16;
6314 this.maxYAxisTickLength = 16;
6315 this.barPadding = 8;
6316 this.roundDomains = false;
6317 this.noBarWhenZero = true;
6318 this.activate = new EventEmitter();
6319 this.deactivate = new EventEmitter();
6320 this.valueDomain = [0, 100];
6321 this.margin = [10, 20, 10, 20];
6322 this.xAxisHeight = 0;
6323 this.yAxisWidth = 0;
6324 this.barChartType = BarChartType;
6325 this.trackBy = (index, item) => {
6326 return item.name;
6327 };
6328 }
6329 update() {
6330 super.update();
6331 this.dims = calculateViewDimensions({
6332 width: this.width,
6333 height: this.height,
6334 margins: this.margin,
6335 showXAxis: this.xAxis,
6336 showYAxis: this.yAxis,
6337 xAxisHeight: this.xAxisHeight,
6338 yAxisWidth: this.yAxisWidth,
6339 showXLabel: this.showXAxisLabel,
6340 showYLabel: this.showYAxisLabel,
6341 showLegend: this.legend,
6342 legendType: this.schemeType,
6343 legendPosition: this.legendPosition
6344 });
6345 this.formatDates();
6346 this.groupDomain = this.getGroupDomain();
6347 this.innerDomain = this.getInnerDomain();
6348 this.xScale = this.getXScale();
6349 this.yScale = this.getYScale();
6350 this.setColors();
6351 this.legendOptions = this.getLegendOptions();
6352 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
6353 }
6354 getGroupDomain() {
6355 const domain = [];
6356 for (const group of this.results) {
6357 if (!domain.includes(group.label)) {
6358 domain.push(group.label);
6359 }
6360 }
6361 return domain;
6362 }
6363 getInnerDomain() {
6364 const domain = [];
6365 for (const group of this.results) {
6366 for (const d of group.series) {
6367 if (!domain.includes(d.label)) {
6368 domain.push(d.label);
6369 }
6370 }
6371 }
6372 return domain;
6373 }
6374 getYScale() {
6375 const spacing = this.groupDomain.length / (this.dims.height / this.barPadding + 1);
6376 return scaleBand().rangeRound([0, this.dims.height]).paddingInner(spacing).domain(this.groupDomain);
6377 }
6378 getXScale() {
6379 const scale = scaleLinear().range([0, this.dims.width]).domain(this.valueDomain);
6380 return this.roundDomains ? scale.nice() : scale;
6381 }
6382 groupTransform(group) {
6383 return `translate(0, ${this.yScale(group.name)})`;
6384 }
6385 onClick(data, group) {
6386 if (group) {
6387 data.series = group.name;
6388 }
6389 this.select.emit(data);
6390 }
6391 setColors() {
6392 let domain;
6393 if (this.schemeType === ScaleType.Ordinal) {
6394 domain = this.innerDomain;
6395 }
6396 else {
6397 domain = this.valueDomain;
6398 }
6399 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
6400 }
6401 getLegendOptions() {
6402 const opts = {
6403 scaleType: this.schemeType,
6404 colors: undefined,
6405 domain: [],
6406 title: undefined,
6407 position: this.legendPosition
6408 };
6409 if (opts.scaleType === ScaleType.Ordinal) {
6410 opts.domain = this.innerDomain;
6411 opts.colors = this.colors;
6412 opts.title = this.legendTitle;
6413 }
6414 else {
6415 opts.domain = this.valueDomain;
6416 opts.colors = this.colors.scale;
6417 }
6418 return opts;
6419 }
6420 updateYAxisWidth({ width }) {
6421 this.yAxisWidth = width;
6422 this.update();
6423 }
6424 updateXAxisHeight({ height }) {
6425 this.xAxisHeight = height;
6426 this.update();
6427 }
6428 onActivate(event, group, fromLegend = false) {
6429 const item = Object.assign({}, event);
6430 if (group) {
6431 item.series = group.name;
6432 }
6433 const items = this.results
6434 .map(g => g.series)
6435 .flat()
6436 .filter(i => {
6437 if (fromLegend) {
6438 return i.label === item.name;
6439 }
6440 else {
6441 return i.name === item.name && i.series === item.series;
6442 }
6443 });
6444 this.activeEntries = [...items];
6445 this.activate.emit({ value: item, entries: this.activeEntries });
6446 }
6447 onDeactivate(event, group, fromLegend = false) {
6448 const item = Object.assign({}, event);
6449 if (group) {
6450 item.series = group.name;
6451 }
6452 this.activeEntries = this.activeEntries.filter(i => {
6453 if (fromLegend) {
6454 return i.label !== item.name;
6455 }
6456 else {
6457 return !(i.name === item.name && i.series === item.series);
6458 }
6459 });
6460 this.deactivate.emit({ value: item, entries: this.activeEntries });
6461 }
6462}
6463BarHorizontalNormalizedComponent.decorators = [
6464 { type: Component, args: [{
6465 selector: 'ngx-charts-bar-horizontal-normalized',
6466 template: `
6467 <ngx-charts-chart
6468 [view]="[width, height]"
6469 [showLegend]="legend"
6470 [legendOptions]="legendOptions"
6471 [activeEntries]="activeEntries"
6472 [animations]="animations"
6473 (legendLabelActivate)="onActivate($event, undefined, true)"
6474 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
6475 (legendLabelClick)="onClick($event)"
6476 >
6477 <svg:g [attr.transform]="transform" class="bar-chart chart">
6478 <svg:g
6479 ngx-charts-x-axis
6480 *ngIf="xAxis"
6481 [xScale]="xScale"
6482 [dims]="dims"
6483 [showGridLines]="showGridLines"
6484 [showLabel]="showXAxisLabel"
6485 [labelText]="xAxisLabel"
6486 [trimTicks]="trimXAxisTicks"
6487 [rotateTicks]="rotateXAxisTicks"
6488 [maxTickLength]="maxXAxisTickLength"
6489 [tickFormatting]="xAxisTickFormatting"
6490 [ticks]="xAxisTicks"
6491 (dimensionsChanged)="updateXAxisHeight($event)"
6492 ></svg:g>
6493 <svg:g
6494 ngx-charts-y-axis
6495 *ngIf="yAxis"
6496 [yScale]="yScale"
6497 [dims]="dims"
6498 [showLabel]="showYAxisLabel"
6499 [labelText]="yAxisLabel"
6500 [trimTicks]="trimYAxisTicks"
6501 [maxTickLength]="maxYAxisTickLength"
6502 [tickFormatting]="yAxisTickFormatting"
6503 [ticks]="yAxisTicks"
6504 (dimensionsChanged)="updateYAxisWidth($event)"
6505 ></svg:g>
6506 <svg:g
6507 *ngFor="let group of results; trackBy: trackBy"
6508 [@animationState]="'active'"
6509 [attr.transform]="groupTransform(group)"
6510 >
6511 <svg:g
6512 ngx-charts-series-horizontal
6513 [type]="barChartType.Normalized"
6514 [xScale]="xScale"
6515 [yScale]="yScale"
6516 [activeEntries]="activeEntries"
6517 [colors]="colors"
6518 [series]="group.series"
6519 [dims]="dims"
6520 [gradient]="gradient"
6521 [tooltipDisabled]="tooltipDisabled"
6522 [tooltipTemplate]="tooltipTemplate"
6523 [seriesName]="group.name"
6524 [animations]="animations"
6525 (select)="onClick($event, group)"
6526 (activate)="onActivate($event, group)"
6527 (deactivate)="onDeactivate($event, group)"
6528 [noBarWhenZero]="noBarWhenZero"
6529 />
6530 </svg:g>
6531 </svg:g>
6532 </ngx-charts-chart>
6533 `,
6534 changeDetection: ChangeDetectionStrategy.OnPush,
6535 encapsulation: ViewEncapsulation.None,
6536 animations: [
6537 trigger('animationState', [
6538 transition(':leave', [
6539 style({
6540 opacity: 1,
6541 transform: '*'
6542 }),
6543 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
6544 ])
6545 ])
6546 ],
6547 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
6548 },] }
6549];
6550BarHorizontalNormalizedComponent.propDecorators = {
6551 legend: [{ type: Input }],
6552 legendTitle: [{ type: Input }],
6553 legendPosition: [{ type: Input }],
6554 xAxis: [{ type: Input }],
6555 yAxis: [{ type: Input }],
6556 showXAxisLabel: [{ type: Input }],
6557 showYAxisLabel: [{ type: Input }],
6558 xAxisLabel: [{ type: Input }],
6559 yAxisLabel: [{ type: Input }],
6560 tooltipDisabled: [{ type: Input }],
6561 gradient: [{ type: Input }],
6562 showGridLines: [{ type: Input }],
6563 activeEntries: [{ type: Input }],
6564 schemeType: [{ type: Input }],
6565 trimXAxisTicks: [{ type: Input }],
6566 trimYAxisTicks: [{ type: Input }],
6567 rotateXAxisTicks: [{ type: Input }],
6568 maxXAxisTickLength: [{ type: Input }],
6569 maxYAxisTickLength: [{ type: Input }],
6570 xAxisTickFormatting: [{ type: Input }],
6571 yAxisTickFormatting: [{ type: Input }],
6572 xAxisTicks: [{ type: Input }],
6573 yAxisTicks: [{ type: Input }],
6574 barPadding: [{ type: Input }],
6575 roundDomains: [{ type: Input }],
6576 noBarWhenZero: [{ type: Input }],
6577 activate: [{ type: Output }],
6578 deactivate: [{ type: Output }],
6579 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
6580};
6581
6582class BarHorizontalStackedComponent extends BaseChartComponent {
6583 constructor() {
6584 super(...arguments);
6585 this.legend = false;
6586 this.legendTitle = 'Legend';
6587 this.legendPosition = LegendPosition.Right;
6588 this.tooltipDisabled = false;
6589 this.showGridLines = true;
6590 this.activeEntries = [];
6591 this.trimXAxisTicks = true;
6592 this.trimYAxisTicks = true;
6593 this.rotateXAxisTicks = true;
6594 this.maxXAxisTickLength = 16;
6595 this.maxYAxisTickLength = 16;
6596 this.barPadding = 8;
6597 this.roundDomains = false;
6598 this.showDataLabel = false;
6599 this.noBarWhenZero = true;
6600 this.activate = new EventEmitter();
6601 this.deactivate = new EventEmitter();
6602 this.margin = [10, 20, 10, 20];
6603 this.xAxisHeight = 0;
6604 this.yAxisWidth = 0;
6605 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
6606 this.barChartType = BarChartType;
6607 this.trackBy = (index, item) => {
6608 return item.name;
6609 };
6610 }
6611 update() {
6612 super.update();
6613 if (!this.showDataLabel) {
6614 this.dataLabelMaxWidth = { negative: 0, positive: 0 };
6615 }
6616 this.margin = [10, 20 + this.dataLabelMaxWidth.positive, 10, 20 + this.dataLabelMaxWidth.negative];
6617 this.dims = calculateViewDimensions({
6618 width: this.width,
6619 height: this.height,
6620 margins: this.margin,
6621 showXAxis: this.xAxis,
6622 showYAxis: this.yAxis,
6623 xAxisHeight: this.xAxisHeight,
6624 yAxisWidth: this.yAxisWidth,
6625 showXLabel: this.showXAxisLabel,
6626 showYLabel: this.showYAxisLabel,
6627 showLegend: this.legend,
6628 legendType: this.schemeType,
6629 legendPosition: this.legendPosition
6630 });
6631 this.formatDates();
6632 this.groupDomain = this.getGroupDomain();
6633 this.innerDomain = this.getInnerDomain();
6634 this.valueDomain = this.getValueDomain();
6635 this.xScale = this.getXScale();
6636 this.yScale = this.getYScale();
6637 this.setColors();
6638 this.legendOptions = this.getLegendOptions();
6639 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
6640 }
6641 getGroupDomain() {
6642 const domain = [];
6643 for (const group of this.results) {
6644 if (!domain.includes(group.label)) {
6645 domain.push(group.label);
6646 }
6647 }
6648 return domain;
6649 }
6650 getInnerDomain() {
6651 const domain = [];
6652 for (const group of this.results) {
6653 for (const d of group.series) {
6654 if (!domain.includes(d.label)) {
6655 domain.push(d.label);
6656 }
6657 }
6658 }
6659 return domain;
6660 }
6661 getValueDomain() {
6662 const domain = [];
6663 let smallest = 0;
6664 let biggest = 0;
6665 for (const group of this.results) {
6666 let smallestSum = 0;
6667 let biggestSum = 0;
6668 for (const d of group.series) {
6669 if (d.value < 0) {
6670 smallestSum += d.value;
6671 }
6672 else {
6673 biggestSum += d.value;
6674 }
6675 smallest = d.value < smallest ? d.value : smallest;
6676 biggest = d.value > biggest ? d.value : biggest;
6677 }
6678 domain.push(smallestSum);
6679 domain.push(biggestSum);
6680 }
6681 domain.push(smallest);
6682 domain.push(biggest);
6683 const min = Math.min(0, ...domain);
6684 const max = this.xScaleMax ? Math.max(this.xScaleMax, ...domain) : Math.max(...domain);
6685 return [min, max];
6686 }
6687 getYScale() {
6688 const spacing = this.groupDomain.length / (this.dims.height / this.barPadding + 1);
6689 return scaleBand().rangeRound([0, this.dims.height]).paddingInner(spacing).domain(this.groupDomain);
6690 }
6691 getXScale() {
6692 const scale = scaleLinear().range([0, this.dims.width]).domain(this.valueDomain);
6693 return this.roundDomains ? scale.nice() : scale;
6694 }
6695 groupTransform(group) {
6696 return `translate(0, ${this.yScale(group.name)})`;
6697 }
6698 onClick(data, group) {
6699 if (group) {
6700 data.series = group.name;
6701 }
6702 this.select.emit(data);
6703 }
6704 setColors() {
6705 let domain;
6706 if (this.schemeType === ScaleType.Ordinal) {
6707 domain = this.innerDomain;
6708 }
6709 else {
6710 domain = this.valueDomain;
6711 }
6712 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
6713 }
6714 getLegendOptions() {
6715 const opts = {
6716 scaleType: this.schemeType,
6717 colors: undefined,
6718 domain: [],
6719 title: undefined,
6720 position: this.legendPosition
6721 };
6722 if (opts.scaleType === ScaleType.Ordinal) {
6723 opts.domain = this.innerDomain;
6724 opts.colors = this.colors;
6725 opts.title = this.legendTitle;
6726 }
6727 else {
6728 opts.domain = this.valueDomain;
6729 opts.colors = this.colors.scale;
6730 }
6731 return opts;
6732 }
6733 updateYAxisWidth({ width }) {
6734 this.yAxisWidth = width;
6735 this.update();
6736 }
6737 updateXAxisHeight({ height }) {
6738 this.xAxisHeight = height;
6739 this.update();
6740 }
6741 onDataLabelMaxWidthChanged(event, groupIndex) {
6742 if (event.size.negative) {
6743 this.dataLabelMaxWidth.negative = Math.max(this.dataLabelMaxWidth.negative, event.size.width);
6744 }
6745 else {
6746 this.dataLabelMaxWidth.positive = Math.max(this.dataLabelMaxWidth.positive, event.size.width);
6747 }
6748 if (groupIndex === this.results.length - 1) {
6749 setTimeout(() => this.update());
6750 }
6751 }
6752 onActivate(event, group, fromLegend = false) {
6753 const item = Object.assign({}, event);
6754 if (group) {
6755 item.series = group.name;
6756 }
6757 const items = this.results
6758 .map(g => g.series)
6759 .flat()
6760 .filter(i => {
6761 if (fromLegend) {
6762 return i.label === item.name;
6763 }
6764 else {
6765 return i.name === item.name && i.series === item.series;
6766 }
6767 });
6768 this.activeEntries = [...items];
6769 this.activate.emit({ value: item, entries: this.activeEntries });
6770 }
6771 onDeactivate(event, group, fromLegend = false) {
6772 const item = Object.assign({}, event);
6773 if (group) {
6774 item.series = group.name;
6775 }
6776 this.activeEntries = this.activeEntries.filter(i => {
6777 if (fromLegend) {
6778 return i.label !== item.name;
6779 }
6780 else {
6781 return !(i.name === item.name && i.series === item.series);
6782 }
6783 });
6784 this.deactivate.emit({ value: item, entries: this.activeEntries });
6785 }
6786}
6787BarHorizontalStackedComponent.decorators = [
6788 { type: Component, args: [{
6789 selector: 'ngx-charts-bar-horizontal-stacked',
6790 template: `
6791 <ngx-charts-chart
6792 [view]="[width, height]"
6793 [showLegend]="legend"
6794 [legendOptions]="legendOptions"
6795 [activeEntries]="activeEntries"
6796 [animations]="animations"
6797 (legendLabelActivate)="onActivate($event, undefined, true)"
6798 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
6799 (legendLabelClick)="onClick($event)"
6800 >
6801 <svg:g [attr.transform]="transform" class="bar-chart chart">
6802 <svg:g
6803 ngx-charts-x-axis
6804 *ngIf="xAxis"
6805 [xScale]="xScale"
6806 [dims]="dims"
6807 [showGridLines]="showGridLines"
6808 [showLabel]="showXAxisLabel"
6809 [labelText]="xAxisLabel"
6810 [trimTicks]="trimXAxisTicks"
6811 [rotateTicks]="rotateXAxisTicks"
6812 [maxTickLength]="maxXAxisTickLength"
6813 [tickFormatting]="xAxisTickFormatting"
6814 [ticks]="xAxisTicks"
6815 (dimensionsChanged)="updateXAxisHeight($event)"
6816 ></svg:g>
6817 <svg:g
6818 ngx-charts-y-axis
6819 *ngIf="yAxis"
6820 [yScale]="yScale"
6821 [dims]="dims"
6822 [showLabel]="showYAxisLabel"
6823 [labelText]="yAxisLabel"
6824 [trimTicks]="trimYAxisTicks"
6825 [maxTickLength]="maxYAxisTickLength"
6826 [tickFormatting]="yAxisTickFormatting"
6827 [ticks]="yAxisTicks"
6828 [yAxisOffset]="dataLabelMaxWidth.negative"
6829 (dimensionsChanged)="updateYAxisWidth($event)"
6830 ></svg:g>
6831 <svg:g
6832 *ngFor="let group of results; let index = index; trackBy: trackBy"
6833 [@animationState]="'active'"
6834 [attr.transform]="groupTransform(group)"
6835 >
6836 <svg:g
6837 ngx-charts-series-horizontal
6838 [type]="barChartType.Stacked"
6839 [xScale]="xScale"
6840 [yScale]="yScale"
6841 [colors]="colors"
6842 [series]="group.series"
6843 [activeEntries]="activeEntries"
6844 [dims]="dims"
6845 [gradient]="gradient"
6846 [tooltipDisabled]="tooltipDisabled"
6847 [tooltipTemplate]="tooltipTemplate"
6848 [seriesName]="group.name"
6849 [animations]="animations"
6850 [showDataLabel]="showDataLabel"
6851 [dataLabelFormatting]="dataLabelFormatting"
6852 [noBarWhenZero]="noBarWhenZero"
6853 (select)="onClick($event, group)"
6854 (activate)="onActivate($event, group)"
6855 (deactivate)="onDeactivate($event, group)"
6856 (dataLabelWidthChanged)="onDataLabelMaxWidthChanged($event, index)"
6857 />
6858 </svg:g>
6859 </svg:g>
6860 </ngx-charts-chart>
6861 `,
6862 changeDetection: ChangeDetectionStrategy.OnPush,
6863 encapsulation: ViewEncapsulation.None,
6864 animations: [
6865 trigger('animationState', [
6866 transition(':leave', [
6867 style({
6868 opacity: 1,
6869 transform: '*'
6870 }),
6871 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
6872 ])
6873 ])
6874 ],
6875 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
6876 },] }
6877];
6878BarHorizontalStackedComponent.propDecorators = {
6879 legend: [{ type: Input }],
6880 legendTitle: [{ type: Input }],
6881 legendPosition: [{ type: Input }],
6882 xAxis: [{ type: Input }],
6883 yAxis: [{ type: Input }],
6884 showXAxisLabel: [{ type: Input }],
6885 showYAxisLabel: [{ type: Input }],
6886 xAxisLabel: [{ type: Input }],
6887 yAxisLabel: [{ type: Input }],
6888 tooltipDisabled: [{ type: Input }],
6889 gradient: [{ type: Input }],
6890 showGridLines: [{ type: Input }],
6891 activeEntries: [{ type: Input }],
6892 schemeType: [{ type: Input }],
6893 trimXAxisTicks: [{ type: Input }],
6894 trimYAxisTicks: [{ type: Input }],
6895 rotateXAxisTicks: [{ type: Input }],
6896 maxXAxisTickLength: [{ type: Input }],
6897 maxYAxisTickLength: [{ type: Input }],
6898 xAxisTickFormatting: [{ type: Input }],
6899 yAxisTickFormatting: [{ type: Input }],
6900 xAxisTicks: [{ type: Input }],
6901 yAxisTicks: [{ type: Input }],
6902 barPadding: [{ type: Input }],
6903 roundDomains: [{ type: Input }],
6904 xScaleMax: [{ type: Input }],
6905 showDataLabel: [{ type: Input }],
6906 dataLabelFormatting: [{ type: Input }],
6907 noBarWhenZero: [{ type: Input }],
6908 activate: [{ type: Output }],
6909 deactivate: [{ type: Output }],
6910 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
6911};
6912
6913class BarVerticalComponent extends BaseChartComponent {
6914 constructor() {
6915 super(...arguments);
6916 this.legend = false;
6917 this.legendTitle = 'Legend';
6918 this.legendPosition = LegendPosition.Right;
6919 this.tooltipDisabled = false;
6920 this.showGridLines = true;
6921 this.activeEntries = [];
6922 this.trimXAxisTicks = true;
6923 this.trimYAxisTicks = true;
6924 this.rotateXAxisTicks = true;
6925 this.maxXAxisTickLength = 16;
6926 this.maxYAxisTickLength = 16;
6927 this.barPadding = 8;
6928 this.roundDomains = false;
6929 this.roundEdges = true;
6930 this.showDataLabel = false;
6931 this.noBarWhenZero = true;
6932 this.activate = new EventEmitter();
6933 this.deactivate = new EventEmitter();
6934 this.margin = [10, 20, 10, 20];
6935 this.xAxisHeight = 0;
6936 this.yAxisWidth = 0;
6937 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
6938 }
6939 update() {
6940 super.update();
6941 if (!this.showDataLabel) {
6942 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
6943 }
6944 this.margin = [10 + this.dataLabelMaxHeight.positive, 20, 10 + this.dataLabelMaxHeight.negative, 20];
6945 this.dims = calculateViewDimensions({
6946 width: this.width,
6947 height: this.height,
6948 margins: this.margin,
6949 showXAxis: this.xAxis,
6950 showYAxis: this.yAxis,
6951 xAxisHeight: this.xAxisHeight,
6952 yAxisWidth: this.yAxisWidth,
6953 showXLabel: this.showXAxisLabel,
6954 showYLabel: this.showYAxisLabel,
6955 showLegend: this.legend,
6956 legendType: this.schemeType,
6957 legendPosition: this.legendPosition
6958 });
6959 this.formatDates();
6960 if (this.showDataLabel) {
6961 this.dims.height -= this.dataLabelMaxHeight.negative;
6962 }
6963 this.xScale = this.getXScale();
6964 this.yScale = this.getYScale();
6965 this.setColors();
6966 this.legendOptions = this.getLegendOptions();
6967 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0] + this.dataLabelMaxHeight.negative})`;
6968 }
6969 getXScale() {
6970 this.xDomain = this.getXDomain();
6971 const spacing = this.xDomain.length / (this.dims.width / this.barPadding + 1);
6972 return scaleBand().range([0, this.dims.width]).paddingInner(spacing).domain(this.xDomain);
6973 }
6974 getYScale() {
6975 this.yDomain = this.getYDomain();
6976 const scale = scaleLinear().range([this.dims.height, 0]).domain(this.yDomain);
6977 return this.roundDomains ? scale.nice() : scale;
6978 }
6979 getXDomain() {
6980 return this.results.map(d => d.label);
6981 }
6982 getYDomain() {
6983 const values = this.results.map(d => d.value);
6984 let min = this.yScaleMin ? Math.min(this.yScaleMin, ...values) : Math.min(0, ...values);
6985 if (this.yAxisTicks && !this.yAxisTicks.some(isNaN)) {
6986 min = Math.min(min, ...this.yAxisTicks);
6987 }
6988 let max = this.yScaleMax ? Math.max(this.yScaleMax, ...values) : Math.max(0, ...values);
6989 if (this.yAxisTicks && !this.yAxisTicks.some(isNaN)) {
6990 max = Math.max(max, ...this.yAxisTicks);
6991 }
6992 return [min, max];
6993 }
6994 onClick(data) {
6995 this.select.emit(data);
6996 }
6997 setColors() {
6998 let domain;
6999 if (this.schemeType === ScaleType.Ordinal) {
7000 domain = this.xDomain;
7001 }
7002 else {
7003 domain = this.yDomain;
7004 }
7005 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
7006 }
7007 getLegendOptions() {
7008 const opts = {
7009 scaleType: this.schemeType,
7010 colors: undefined,
7011 domain: [],
7012 title: undefined,
7013 position: this.legendPosition
7014 };
7015 if (opts.scaleType === ScaleType.Ordinal) {
7016 opts.domain = this.xDomain;
7017 opts.colors = this.colors;
7018 opts.title = this.legendTitle;
7019 }
7020 else {
7021 opts.domain = this.yDomain;
7022 opts.colors = this.colors.scale;
7023 }
7024 return opts;
7025 }
7026 updateYAxisWidth({ width }) {
7027 this.yAxisWidth = width;
7028 this.update();
7029 }
7030 updateXAxisHeight({ height }) {
7031 this.xAxisHeight = height;
7032 this.update();
7033 }
7034 onDataLabelMaxHeightChanged(event) {
7035 if (event.size.negative) {
7036 this.dataLabelMaxHeight.negative = Math.max(this.dataLabelMaxHeight.negative, event.size.height);
7037 }
7038 else {
7039 this.dataLabelMaxHeight.positive = Math.max(this.dataLabelMaxHeight.positive, event.size.height);
7040 }
7041 if (event.index === this.results.length - 1) {
7042 setTimeout(() => this.update());
7043 }
7044 }
7045 onActivate(item, fromLegend = false) {
7046 item = this.results.find(d => {
7047 if (fromLegend) {
7048 return d.label === item.name;
7049 }
7050 else {
7051 return d.name === item.name;
7052 }
7053 });
7054 const idx = this.activeEntries.findIndex(d => {
7055 return d.name === item.name && d.value === item.value && d.series === item.series;
7056 });
7057 if (idx > -1) {
7058 return;
7059 }
7060 this.activeEntries = [item, ...this.activeEntries];
7061 this.activate.emit({ value: item, entries: this.activeEntries });
7062 }
7063 onDeactivate(item, fromLegend = false) {
7064 item = this.results.find(d => {
7065 if (fromLegend) {
7066 return d.label === item.name;
7067 }
7068 else {
7069 return d.name === item.name;
7070 }
7071 });
7072 const idx = this.activeEntries.findIndex(d => {
7073 return d.name === item.name && d.value === item.value && d.series === item.series;
7074 });
7075 this.activeEntries.splice(idx, 1);
7076 this.activeEntries = [...this.activeEntries];
7077 this.deactivate.emit({ value: item, entries: this.activeEntries });
7078 }
7079}
7080BarVerticalComponent.decorators = [
7081 { type: Component, args: [{
7082 selector: 'ngx-charts-bar-vertical',
7083 template: `
7084 <ngx-charts-chart
7085 [view]="[width, height]"
7086 [showLegend]="legend"
7087 [legendOptions]="legendOptions"
7088 [activeEntries]="activeEntries"
7089 [animations]="animations"
7090 (legendLabelClick)="onClick($event)"
7091 (legendLabelActivate)="onActivate($event, true)"
7092 (legendLabelDeactivate)="onDeactivate($event, true)"
7093 >
7094 <svg:g [attr.transform]="transform" class="bar-chart chart">
7095 <svg:g
7096 ngx-charts-x-axis
7097 *ngIf="xAxis"
7098 [xScale]="xScale"
7099 [dims]="dims"
7100 [showGridLines]="showGridLines"
7101 [showLabel]="showXAxisLabel"
7102 [labelText]="xAxisLabel"
7103 [trimTicks]="trimXAxisTicks"
7104 [rotateTicks]="rotateXAxisTicks"
7105 [maxTickLength]="maxXAxisTickLength"
7106 [tickFormatting]="xAxisTickFormatting"
7107 [ticks]="xAxisTicks"
7108 [xAxisOffset]="dataLabelMaxHeight.negative"
7109 (dimensionsChanged)="updateXAxisHeight($event)"
7110 ></svg:g>
7111 <svg:g
7112 ngx-charts-y-axis
7113 *ngIf="yAxis"
7114 [yScale]="yScale"
7115 [dims]="dims"
7116 [showGridLines]="showGridLines"
7117 [showLabel]="showYAxisLabel"
7118 [labelText]="yAxisLabel"
7119 [trimTicks]="trimYAxisTicks"
7120 [maxTickLength]="maxYAxisTickLength"
7121 [tickFormatting]="yAxisTickFormatting"
7122 [ticks]="yAxisTicks"
7123 (dimensionsChanged)="updateYAxisWidth($event)"
7124 ></svg:g>
7125 <svg:g
7126 ngx-charts-series-vertical
7127 [xScale]="xScale"
7128 [yScale]="yScale"
7129 [colors]="colors"
7130 [series]="results"
7131 [dims]="dims"
7132 [gradient]="gradient"
7133 [tooltipDisabled]="tooltipDisabled"
7134 [tooltipTemplate]="tooltipTemplate"
7135 [showDataLabel]="showDataLabel"
7136 [dataLabelFormatting]="dataLabelFormatting"
7137 [activeEntries]="activeEntries"
7138 [roundEdges]="roundEdges"
7139 [animations]="animations"
7140 [noBarWhenZero]="noBarWhenZero"
7141 (activate)="onActivate($event)"
7142 (deactivate)="onDeactivate($event)"
7143 (select)="onClick($event)"
7144 (dataLabelHeightChanged)="onDataLabelMaxHeightChanged($event)"
7145 ></svg:g>
7146 </svg:g>
7147 </ngx-charts-chart>
7148 `,
7149 changeDetection: ChangeDetectionStrategy.OnPush,
7150 encapsulation: ViewEncapsulation.None,
7151 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
7152 },] }
7153];
7154BarVerticalComponent.propDecorators = {
7155 legend: [{ type: Input }],
7156 legendTitle: [{ type: Input }],
7157 legendPosition: [{ type: Input }],
7158 xAxis: [{ type: Input }],
7159 yAxis: [{ type: Input }],
7160 showXAxisLabel: [{ type: Input }],
7161 showYAxisLabel: [{ type: Input }],
7162 xAxisLabel: [{ type: Input }],
7163 yAxisLabel: [{ type: Input }],
7164 tooltipDisabled: [{ type: Input }],
7165 gradient: [{ type: Input }],
7166 showGridLines: [{ type: Input }],
7167 activeEntries: [{ type: Input }],
7168 schemeType: [{ type: Input }],
7169 trimXAxisTicks: [{ type: Input }],
7170 trimYAxisTicks: [{ type: Input }],
7171 rotateXAxisTicks: [{ type: Input }],
7172 maxXAxisTickLength: [{ type: Input }],
7173 maxYAxisTickLength: [{ type: Input }],
7174 xAxisTickFormatting: [{ type: Input }],
7175 yAxisTickFormatting: [{ type: Input }],
7176 xAxisTicks: [{ type: Input }],
7177 yAxisTicks: [{ type: Input }],
7178 barPadding: [{ type: Input }],
7179 roundDomains: [{ type: Input }],
7180 roundEdges: [{ type: Input }],
7181 yScaleMax: [{ type: Input }],
7182 yScaleMin: [{ type: Input }],
7183 showDataLabel: [{ type: Input }],
7184 dataLabelFormatting: [{ type: Input }],
7185 noBarWhenZero: [{ type: Input }],
7186 activate: [{ type: Output }],
7187 deactivate: [{ type: Output }],
7188 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
7189};
7190
7191class BarVertical2DComponent extends BaseChartComponent {
7192 constructor() {
7193 super(...arguments);
7194 this.legend = false;
7195 this.legendTitle = 'Legend';
7196 this.legendPosition = LegendPosition.Right;
7197 this.tooltipDisabled = false;
7198 this.scaleType = ScaleType.Ordinal;
7199 this.showGridLines = true;
7200 this.activeEntries = [];
7201 this.trimXAxisTicks = true;
7202 this.trimYAxisTicks = true;
7203 this.rotateXAxisTicks = true;
7204 this.maxXAxisTickLength = 16;
7205 this.maxYAxisTickLength = 16;
7206 this.groupPadding = 16;
7207 this.barPadding = 8;
7208 this.roundDomains = false;
7209 this.roundEdges = true;
7210 this.showDataLabel = false;
7211 this.noBarWhenZero = true;
7212 this.activate = new EventEmitter();
7213 this.deactivate = new EventEmitter();
7214 this.margin = [10, 20, 10, 20];
7215 this.xAxisHeight = 0;
7216 this.yAxisWidth = 0;
7217 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
7218 this.barOrientation = BarOrientation;
7219 this.trackBy = (index, item) => {
7220 return item.name;
7221 };
7222 }
7223 update() {
7224 super.update();
7225 if (!this.showDataLabel) {
7226 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
7227 }
7228 this.margin = [10 + this.dataLabelMaxHeight.positive, 20, 10 + this.dataLabelMaxHeight.negative, 20];
7229 this.dims = calculateViewDimensions({
7230 width: this.width,
7231 height: this.height,
7232 margins: this.margin,
7233 showXAxis: this.xAxis,
7234 showYAxis: this.yAxis,
7235 xAxisHeight: this.xAxisHeight,
7236 yAxisWidth: this.yAxisWidth,
7237 showXLabel: this.showXAxisLabel,
7238 showYLabel: this.showYAxisLabel,
7239 showLegend: this.legend,
7240 legendType: this.schemeType,
7241 legendPosition: this.legendPosition
7242 });
7243 if (this.showDataLabel) {
7244 this.dims.height -= this.dataLabelMaxHeight.negative;
7245 }
7246 this.formatDates();
7247 this.groupDomain = this.getGroupDomain();
7248 this.innerDomain = this.getInnerDomain();
7249 this.valueDomain = this.getValueDomain();
7250 this.groupScale = this.getGroupScale();
7251 this.innerScale = this.getInnerScale();
7252 this.valueScale = this.getValueScale();
7253 this.setColors();
7254 this.legendOptions = this.getLegendOptions();
7255 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0] + this.dataLabelMaxHeight.negative})`;
7256 }
7257 onDataLabelMaxHeightChanged(event, groupIndex) {
7258 if (event.size.negative) {
7259 this.dataLabelMaxHeight.negative = Math.max(this.dataLabelMaxHeight.negative, event.size.height);
7260 }
7261 else {
7262 this.dataLabelMaxHeight.positive = Math.max(this.dataLabelMaxHeight.positive, event.size.height);
7263 }
7264 if (groupIndex === this.results.length - 1) {
7265 setTimeout(() => this.update());
7266 }
7267 }
7268 getGroupScale() {
7269 const spacing = this.groupDomain.length / (this.dims.height / this.groupPadding + 1);
7270 return scaleBand()
7271 .rangeRound([0, this.dims.width])
7272 .paddingInner(spacing)
7273 .paddingOuter(spacing / 2)
7274 .domain(this.groupDomain);
7275 }
7276 getInnerScale() {
7277 const width = this.groupScale.bandwidth();
7278 const spacing = this.innerDomain.length / (width / this.barPadding + 1);
7279 return scaleBand().rangeRound([0, width]).paddingInner(spacing).domain(this.innerDomain);
7280 }
7281 getValueScale() {
7282 const scale = scaleLinear().range([this.dims.height, 0]).domain(this.valueDomain);
7283 return this.roundDomains ? scale.nice() : scale;
7284 }
7285 getGroupDomain() {
7286 const domain = [];
7287 for (const group of this.results) {
7288 if (!domain.includes(group.label)) {
7289 domain.push(group.label);
7290 }
7291 }
7292 return domain;
7293 }
7294 getInnerDomain() {
7295 const domain = [];
7296 for (const group of this.results) {
7297 for (const d of group.series) {
7298 if (!domain.includes(d.label)) {
7299 domain.push(d.label);
7300 }
7301 }
7302 }
7303 return domain;
7304 }
7305 getValueDomain() {
7306 const domain = [];
7307 for (const group of this.results) {
7308 for (const d of group.series) {
7309 if (!domain.includes(d.value)) {
7310 domain.push(d.value);
7311 }
7312 }
7313 }
7314 const min = Math.min(0, ...domain);
7315 const max = this.yScaleMax ? Math.max(this.yScaleMax, ...domain) : Math.max(0, ...domain);
7316 return [min, max];
7317 }
7318 groupTransform(group) {
7319 return `translate(${this.groupScale(group.label)}, 0)`;
7320 }
7321 onClick(data, group) {
7322 if (group) {
7323 data.series = group.name;
7324 }
7325 this.select.emit(data);
7326 }
7327 setColors() {
7328 let domain;
7329 if (this.schemeType === ScaleType.Ordinal) {
7330 domain = this.innerDomain;
7331 }
7332 else {
7333 domain = this.valueDomain;
7334 }
7335 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
7336 }
7337 getLegendOptions() {
7338 const opts = {
7339 scaleType: this.schemeType,
7340 colors: undefined,
7341 domain: [],
7342 title: undefined,
7343 position: this.legendPosition
7344 };
7345 if (opts.scaleType === ScaleType.Ordinal) {
7346 opts.domain = this.innerDomain;
7347 opts.colors = this.colors;
7348 opts.title = this.legendTitle;
7349 }
7350 else {
7351 opts.domain = this.valueDomain;
7352 opts.colors = this.colors.scale;
7353 }
7354 return opts;
7355 }
7356 updateYAxisWidth({ width }) {
7357 this.yAxisWidth = width;
7358 this.update();
7359 }
7360 updateXAxisHeight({ height }) {
7361 this.xAxisHeight = height;
7362 this.update();
7363 }
7364 onActivate(event, group, fromLegend = false) {
7365 const item = Object.assign({}, event);
7366 if (group) {
7367 item.series = group.name;
7368 }
7369 const items = this.results
7370 .map(g => g.series)
7371 .flat()
7372 .filter(i => {
7373 if (fromLegend) {
7374 return i.label === item.name;
7375 }
7376 else {
7377 return i.name === item.name && i.series === item.series;
7378 }
7379 });
7380 this.activeEntries = [...items];
7381 this.activate.emit({ value: item, entries: this.activeEntries });
7382 }
7383 onDeactivate(event, group, fromLegend = false) {
7384 const item = Object.assign({}, event);
7385 if (group) {
7386 item.series = group.name;
7387 }
7388 this.activeEntries = this.activeEntries.filter(i => {
7389 if (fromLegend) {
7390 return i.label !== item.name;
7391 }
7392 else {
7393 return !(i.name === item.name && i.series === item.series);
7394 }
7395 });
7396 this.deactivate.emit({ value: item, entries: this.activeEntries });
7397 }
7398}
7399BarVertical2DComponent.decorators = [
7400 { type: Component, args: [{
7401 selector: 'ngx-charts-bar-vertical-2d',
7402 template: `
7403 <ngx-charts-chart
7404 [view]="[width, height]"
7405 [showLegend]="legend"
7406 [legendOptions]="legendOptions"
7407 [activeEntries]="activeEntries"
7408 [animations]="animations"
7409 (legendLabelActivate)="onActivate($event, undefined, true)"
7410 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
7411 (legendLabelClick)="onClick($event)"
7412 >
7413 <svg:g [attr.transform]="transform" class="bar-chart chart">
7414 <svg:g
7415 ngx-charts-grid-panel-series
7416 [xScale]="groupScale"
7417 [yScale]="valueScale"
7418 [data]="results"
7419 [dims]="dims"
7420 [orient]="barOrientation.Vertical"
7421 ></svg:g>
7422 <svg:g
7423 ngx-charts-x-axis
7424 *ngIf="xAxis"
7425 [xScale]="groupScale"
7426 [dims]="dims"
7427 [showLabel]="showXAxisLabel"
7428 [labelText]="xAxisLabel"
7429 [trimTicks]="trimXAxisTicks"
7430 [rotateTicks]="rotateXAxisTicks"
7431 [maxTickLength]="maxXAxisTickLength"
7432 [tickFormatting]="xAxisTickFormatting"
7433 [ticks]="xAxisTicks"
7434 [xAxisOffset]="dataLabelMaxHeight.negative"
7435 (dimensionsChanged)="updateXAxisHeight($event)"
7436 ></svg:g>
7437 <svg:g
7438 ngx-charts-y-axis
7439 *ngIf="yAxis"
7440 [yScale]="valueScale"
7441 [dims]="dims"
7442 [showGridLines]="showGridLines"
7443 [showLabel]="showYAxisLabel"
7444 [labelText]="yAxisLabel"
7445 [trimTicks]="trimYAxisTicks"
7446 [maxTickLength]="maxYAxisTickLength"
7447 [tickFormatting]="yAxisTickFormatting"
7448 [ticks]="yAxisTicks"
7449 (dimensionsChanged)="updateYAxisWidth($event)"
7450 ></svg:g>
7451 <svg:g
7452 ngx-charts-series-vertical
7453 *ngFor="let group of results; let index = index; trackBy: trackBy"
7454 [@animationState]="'active'"
7455 [attr.transform]="groupTransform(group)"
7456 [activeEntries]="activeEntries"
7457 [xScale]="innerScale"
7458 [yScale]="valueScale"
7459 [colors]="colors"
7460 [series]="group.series"
7461 [dims]="dims"
7462 [gradient]="gradient"
7463 [tooltipDisabled]="tooltipDisabled"
7464 [tooltipTemplate]="tooltipTemplate"
7465 [showDataLabel]="showDataLabel"
7466 [dataLabelFormatting]="dataLabelFormatting"
7467 [seriesName]="group.name"
7468 [roundEdges]="roundEdges"
7469 [animations]="animations"
7470 [noBarWhenZero]="noBarWhenZero"
7471 (select)="onClick($event, group)"
7472 (activate)="onActivate($event, group)"
7473 (deactivate)="onDeactivate($event, group)"
7474 (dataLabelHeightChanged)="onDataLabelMaxHeightChanged($event, index)"
7475 />
7476 </svg:g>
7477 </ngx-charts-chart>
7478 `,
7479 encapsulation: ViewEncapsulation.None,
7480 changeDetection: ChangeDetectionStrategy.OnPush,
7481 animations: [
7482 trigger('animationState', [
7483 transition(':leave', [
7484 style({
7485 opacity: 1,
7486 transform: '*'
7487 }),
7488 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
7489 ])
7490 ])
7491 ],
7492 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
7493 },] }
7494];
7495BarVertical2DComponent.propDecorators = {
7496 legend: [{ type: Input }],
7497 legendTitle: [{ type: Input }],
7498 legendPosition: [{ type: Input }],
7499 xAxis: [{ type: Input }],
7500 yAxis: [{ type: Input }],
7501 showXAxisLabel: [{ type: Input }],
7502 showYAxisLabel: [{ type: Input }],
7503 xAxisLabel: [{ type: Input }],
7504 yAxisLabel: [{ type: Input }],
7505 tooltipDisabled: [{ type: Input }],
7506 scaleType: [{ type: Input }],
7507 gradient: [{ type: Input }],
7508 showGridLines: [{ type: Input }],
7509 activeEntries: [{ type: Input }],
7510 schemeType: [{ type: Input }],
7511 trimXAxisTicks: [{ type: Input }],
7512 trimYAxisTicks: [{ type: Input }],
7513 rotateXAxisTicks: [{ type: Input }],
7514 maxXAxisTickLength: [{ type: Input }],
7515 maxYAxisTickLength: [{ type: Input }],
7516 xAxisTickFormatting: [{ type: Input }],
7517 yAxisTickFormatting: [{ type: Input }],
7518 xAxisTicks: [{ type: Input }],
7519 yAxisTicks: [{ type: Input }],
7520 groupPadding: [{ type: Input }],
7521 barPadding: [{ type: Input }],
7522 roundDomains: [{ type: Input }],
7523 roundEdges: [{ type: Input }],
7524 yScaleMax: [{ type: Input }],
7525 showDataLabel: [{ type: Input }],
7526 dataLabelFormatting: [{ type: Input }],
7527 noBarWhenZero: [{ type: Input }],
7528 activate: [{ type: Output }],
7529 deactivate: [{ type: Output }],
7530 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
7531};
7532
7533class BarVerticalNormalizedComponent extends BaseChartComponent {
7534 constructor() {
7535 super(...arguments);
7536 this.legend = false;
7537 this.legendTitle = 'Legend';
7538 this.legendPosition = LegendPosition.Right;
7539 this.tooltipDisabled = false;
7540 this.showGridLines = true;
7541 this.activeEntries = [];
7542 this.trimXAxisTicks = true;
7543 this.trimYAxisTicks = true;
7544 this.rotateXAxisTicks = true;
7545 this.maxXAxisTickLength = 16;
7546 this.maxYAxisTickLength = 16;
7547 this.barPadding = 8;
7548 this.roundDomains = false;
7549 this.noBarWhenZero = true;
7550 this.activate = new EventEmitter();
7551 this.deactivate = new EventEmitter();
7552 this.valueDomain = [0, 100];
7553 this.margin = [10, 20, 10, 20];
7554 this.xAxisHeight = 0;
7555 this.yAxisWidth = 0;
7556 this.barChartType = BarChartType;
7557 this.trackBy = (index, item) => {
7558 return item.name;
7559 };
7560 }
7561 update() {
7562 super.update();
7563 this.dims = calculateViewDimensions({
7564 width: this.width,
7565 height: this.height,
7566 margins: this.margin,
7567 showXAxis: this.xAxis,
7568 showYAxis: this.yAxis,
7569 xAxisHeight: this.xAxisHeight,
7570 yAxisWidth: this.yAxisWidth,
7571 showXLabel: this.showXAxisLabel,
7572 showYLabel: this.showYAxisLabel,
7573 showLegend: this.legend,
7574 legendType: this.schemeType,
7575 legendPosition: this.legendPosition
7576 });
7577 this.formatDates();
7578 this.groupDomain = this.getGroupDomain();
7579 this.innerDomain = this.getInnerDomain();
7580 this.xScale = this.getXScale();
7581 this.yScale = this.getYScale();
7582 this.setColors();
7583 this.legendOptions = this.getLegendOptions();
7584 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
7585 }
7586 getGroupDomain() {
7587 const domain = [];
7588 for (const group of this.results) {
7589 if (!domain.includes(group.label)) {
7590 domain.push(group.label);
7591 }
7592 }
7593 return domain;
7594 }
7595 getInnerDomain() {
7596 const domain = [];
7597 for (const group of this.results) {
7598 for (const d of group.series) {
7599 if (!domain.includes(d.label)) {
7600 domain.push(d.label);
7601 }
7602 }
7603 }
7604 return domain;
7605 }
7606 getXScale() {
7607 const spacing = this.groupDomain.length / (this.dims.width / this.barPadding + 1);
7608 return scaleBand().rangeRound([0, this.dims.width]).paddingInner(spacing).domain(this.groupDomain);
7609 }
7610 getYScale() {
7611 const scale = scaleLinear().range([this.dims.height, 0]).domain(this.valueDomain);
7612 return this.roundDomains ? scale.nice() : scale;
7613 }
7614 groupTransform(group) {
7615 return `translate(${this.xScale(group.name)}, 0)`;
7616 }
7617 onClick(data, group) {
7618 if (group) {
7619 data.series = group.name;
7620 }
7621 this.select.emit(data);
7622 }
7623 setColors() {
7624 let domain;
7625 if (this.schemeType === ScaleType.Ordinal) {
7626 domain = this.innerDomain;
7627 }
7628 else {
7629 domain = this.valueDomain;
7630 }
7631 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
7632 }
7633 getLegendOptions() {
7634 const opts = {
7635 scaleType: this.schemeType,
7636 colors: undefined,
7637 domain: [],
7638 title: undefined,
7639 position: this.legendPosition
7640 };
7641 if (opts.scaleType === ScaleType.Ordinal) {
7642 opts.domain = this.innerDomain;
7643 opts.colors = this.colors;
7644 opts.title = this.legendTitle;
7645 }
7646 else {
7647 opts.domain = this.valueDomain;
7648 opts.colors = this.colors.scale;
7649 }
7650 return opts;
7651 }
7652 updateYAxisWidth({ width }) {
7653 this.yAxisWidth = width;
7654 this.update();
7655 }
7656 updateXAxisHeight({ height }) {
7657 this.xAxisHeight = height;
7658 this.update();
7659 }
7660 onActivate(event, group, fromLegend = false) {
7661 const item = Object.assign({}, event);
7662 if (group) {
7663 item.series = group.name;
7664 }
7665 const items = this.results
7666 .map(g => g.series)
7667 .flat()
7668 .filter(i => {
7669 if (fromLegend) {
7670 return i.label === item.name;
7671 }
7672 else {
7673 return i.name === item.name && i.series === item.series;
7674 }
7675 });
7676 this.activeEntries = [...items];
7677 this.activate.emit({ value: item, entries: this.activeEntries });
7678 }
7679 onDeactivate(event, group, fromLegend = false) {
7680 const item = Object.assign({}, event);
7681 if (group) {
7682 item.series = group.name;
7683 }
7684 this.activeEntries = this.activeEntries.filter(i => {
7685 if (fromLegend) {
7686 return i.label !== item.name;
7687 }
7688 else {
7689 return !(i.name === item.name && i.series === item.series);
7690 }
7691 });
7692 this.deactivate.emit({ value: item, entries: this.activeEntries });
7693 }
7694}
7695BarVerticalNormalizedComponent.decorators = [
7696 { type: Component, args: [{
7697 selector: 'ngx-charts-bar-vertical-normalized',
7698 template: `
7699 <ngx-charts-chart
7700 [view]="[width, height]"
7701 [showLegend]="legend"
7702 [legendOptions]="legendOptions"
7703 [activeEntries]="activeEntries"
7704 [animations]="animations"
7705 (legendLabelActivate)="onActivate($event, undefined, true)"
7706 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
7707 (legendLabelClick)="onClick($event)"
7708 >
7709 <svg:g [attr.transform]="transform" class="bar-chart chart">
7710 <svg:g
7711 ngx-charts-x-axis
7712 *ngIf="xAxis"
7713 [xScale]="xScale"
7714 [dims]="dims"
7715 [showLabel]="showXAxisLabel"
7716 [labelText]="xAxisLabel"
7717 [trimTicks]="trimXAxisTicks"
7718 [rotateTicks]="rotateXAxisTicks"
7719 [maxTickLength]="maxXAxisTickLength"
7720 [tickFormatting]="xAxisTickFormatting"
7721 [ticks]="xAxisTicks"
7722 (dimensionsChanged)="updateXAxisHeight($event)"
7723 ></svg:g>
7724 <svg:g
7725 ngx-charts-y-axis
7726 *ngIf="yAxis"
7727 [yScale]="yScale"
7728 [dims]="dims"
7729 [showGridLines]="showGridLines"
7730 [showLabel]="showYAxisLabel"
7731 [labelText]="yAxisLabel"
7732 [trimTicks]="trimYAxisTicks"
7733 [maxTickLength]="maxYAxisTickLength"
7734 [tickFormatting]="yAxisTickFormatting"
7735 [ticks]="yAxisTicks"
7736 (dimensionsChanged)="updateYAxisWidth($event)"
7737 ></svg:g>
7738 <svg:g
7739 *ngFor="let group of results; trackBy: trackBy"
7740 [@animationState]="'active'"
7741 [attr.transform]="groupTransform(group)"
7742 >
7743 <svg:g
7744 ngx-charts-series-vertical
7745 [type]="barChartType.Normalized"
7746 [xScale]="xScale"
7747 [yScale]="yScale"
7748 [activeEntries]="activeEntries"
7749 [colors]="colors"
7750 [series]="group.series"
7751 [dims]="dims"
7752 [gradient]="gradient"
7753 [tooltipDisabled]="tooltipDisabled"
7754 [tooltipTemplate]="tooltipTemplate"
7755 [seriesName]="group.name"
7756 [animations]="animations"
7757 [noBarWhenZero]="noBarWhenZero"
7758 (select)="onClick($event, group)"
7759 (activate)="onActivate($event, group)"
7760 (deactivate)="onDeactivate($event, group)"
7761 />
7762 </svg:g>
7763 </svg:g>
7764 </ngx-charts-chart>
7765 `,
7766 encapsulation: ViewEncapsulation.None,
7767 changeDetection: ChangeDetectionStrategy.OnPush,
7768 animations: [
7769 trigger('animationState', [
7770 transition(':leave', [
7771 style({
7772 opacity: 1,
7773 transform: '*'
7774 }),
7775 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
7776 ])
7777 ])
7778 ],
7779 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
7780 },] }
7781];
7782BarVerticalNormalizedComponent.propDecorators = {
7783 legend: [{ type: Input }],
7784 legendTitle: [{ type: Input }],
7785 legendPosition: [{ type: Input }],
7786 xAxis: [{ type: Input }],
7787 yAxis: [{ type: Input }],
7788 showXAxisLabel: [{ type: Input }],
7789 showYAxisLabel: [{ type: Input }],
7790 xAxisLabel: [{ type: Input }],
7791 yAxisLabel: [{ type: Input }],
7792 tooltipDisabled: [{ type: Input }],
7793 gradient: [{ type: Input }],
7794 showGridLines: [{ type: Input }],
7795 activeEntries: [{ type: Input }],
7796 schemeType: [{ type: Input }],
7797 trimXAxisTicks: [{ type: Input }],
7798 trimYAxisTicks: [{ type: Input }],
7799 rotateXAxisTicks: [{ type: Input }],
7800 maxXAxisTickLength: [{ type: Input }],
7801 maxYAxisTickLength: [{ type: Input }],
7802 xAxisTickFormatting: [{ type: Input }],
7803 yAxisTickFormatting: [{ type: Input }],
7804 xAxisTicks: [{ type: Input }],
7805 yAxisTicks: [{ type: Input }],
7806 barPadding: [{ type: Input }],
7807 roundDomains: [{ type: Input }],
7808 noBarWhenZero: [{ type: Input }],
7809 activate: [{ type: Output }],
7810 deactivate: [{ type: Output }],
7811 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
7812};
7813
7814class BarVerticalStackedComponent extends BaseChartComponent {
7815 constructor() {
7816 super(...arguments);
7817 this.legend = false;
7818 this.legendTitle = 'Legend';
7819 this.legendPosition = LegendPosition.Right;
7820 this.tooltipDisabled = false;
7821 this.showGridLines = true;
7822 this.activeEntries = [];
7823 this.trimXAxisTicks = true;
7824 this.trimYAxisTicks = true;
7825 this.rotateXAxisTicks = true;
7826 this.maxXAxisTickLength = 16;
7827 this.maxYAxisTickLength = 16;
7828 this.barPadding = 8;
7829 this.roundDomains = false;
7830 this.showDataLabel = false;
7831 this.noBarWhenZero = true;
7832 this.activate = new EventEmitter();
7833 this.deactivate = new EventEmitter();
7834 this.margin = [10, 20, 10, 20];
7835 this.xAxisHeight = 0;
7836 this.yAxisWidth = 0;
7837 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
7838 this.barChartType = BarChartType;
7839 this.trackBy = (index, item) => {
7840 return item.name;
7841 };
7842 }
7843 update() {
7844 super.update();
7845 if (!this.showDataLabel) {
7846 this.dataLabelMaxHeight = { negative: 0, positive: 0 };
7847 }
7848 this.margin = [10 + this.dataLabelMaxHeight.positive, 20, 10 + this.dataLabelMaxHeight.negative, 20];
7849 this.dims = calculateViewDimensions({
7850 width: this.width,
7851 height: this.height,
7852 margins: this.margin,
7853 showXAxis: this.xAxis,
7854 showYAxis: this.yAxis,
7855 xAxisHeight: this.xAxisHeight,
7856 yAxisWidth: this.yAxisWidth,
7857 showXLabel: this.showXAxisLabel,
7858 showYLabel: this.showYAxisLabel,
7859 showLegend: this.legend,
7860 legendType: this.schemeType,
7861 legendPosition: this.legendPosition
7862 });
7863 if (this.showDataLabel) {
7864 this.dims.height -= this.dataLabelMaxHeight.negative;
7865 }
7866 this.formatDates();
7867 this.groupDomain = this.getGroupDomain();
7868 this.innerDomain = this.getInnerDomain();
7869 this.valueDomain = this.getValueDomain();
7870 this.xScale = this.getXScale();
7871 this.yScale = this.getYScale();
7872 this.setColors();
7873 this.legendOptions = this.getLegendOptions();
7874 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0] + this.dataLabelMaxHeight.negative})`;
7875 }
7876 getGroupDomain() {
7877 const domain = [];
7878 for (const group of this.results) {
7879 if (!domain.includes(group.label)) {
7880 domain.push(group.label);
7881 }
7882 }
7883 return domain;
7884 }
7885 getInnerDomain() {
7886 const domain = [];
7887 for (const group of this.results) {
7888 for (const d of group.series) {
7889 if (!domain.includes(d.label)) {
7890 domain.push(d.label);
7891 }
7892 }
7893 }
7894 return domain;
7895 }
7896 getValueDomain() {
7897 const domain = [];
7898 let smallest = 0;
7899 let biggest = 0;
7900 for (const group of this.results) {
7901 let smallestSum = 0;
7902 let biggestSum = 0;
7903 for (const d of group.series) {
7904 if (d.value < 0) {
7905 smallestSum += d.value;
7906 }
7907 else {
7908 biggestSum += d.value;
7909 }
7910 smallest = d.value < smallest ? d.value : smallest;
7911 biggest = d.value > biggest ? d.value : biggest;
7912 }
7913 domain.push(smallestSum);
7914 domain.push(biggestSum);
7915 }
7916 domain.push(smallest);
7917 domain.push(biggest);
7918 const min = Math.min(0, ...domain);
7919 const max = this.yScaleMax ? Math.max(this.yScaleMax, ...domain) : Math.max(...domain);
7920 return [min, max];
7921 }
7922 getXScale() {
7923 const spacing = this.groupDomain.length / (this.dims.width / this.barPadding + 1);
7924 return scaleBand().rangeRound([0, this.dims.width]).paddingInner(spacing).domain(this.groupDomain);
7925 }
7926 getYScale() {
7927 const scale = scaleLinear().range([this.dims.height, 0]).domain(this.valueDomain);
7928 return this.roundDomains ? scale.nice() : scale;
7929 }
7930 onDataLabelMaxHeightChanged(event, groupIndex) {
7931 if (event.size.negative) {
7932 this.dataLabelMaxHeight.negative = Math.max(this.dataLabelMaxHeight.negative, event.size.height);
7933 }
7934 else {
7935 this.dataLabelMaxHeight.positive = Math.max(this.dataLabelMaxHeight.positive, event.size.height);
7936 }
7937 if (groupIndex === this.results.length - 1) {
7938 setTimeout(() => this.update());
7939 }
7940 }
7941 groupTransform(group) {
7942 return `translate(${this.xScale(group.name) || 0}, 0)`;
7943 }
7944 onClick(data, group) {
7945 if (group) {
7946 data.series = group.name;
7947 }
7948 this.select.emit(data);
7949 }
7950 setColors() {
7951 let domain;
7952 if (this.schemeType === ScaleType.Ordinal) {
7953 domain = this.innerDomain;
7954 }
7955 else {
7956 domain = this.valueDomain;
7957 }
7958 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
7959 }
7960 getLegendOptions() {
7961 const opts = {
7962 scaleType: this.schemeType,
7963 colors: undefined,
7964 domain: [],
7965 title: undefined,
7966 position: this.legendPosition
7967 };
7968 if (opts.scaleType === ScaleType.Ordinal) {
7969 opts.domain = this.innerDomain;
7970 opts.colors = this.colors;
7971 opts.title = this.legendTitle;
7972 }
7973 else {
7974 opts.domain = this.valueDomain;
7975 opts.colors = this.colors.scale;
7976 }
7977 return opts;
7978 }
7979 updateYAxisWidth({ width }) {
7980 this.yAxisWidth = width;
7981 this.update();
7982 }
7983 updateXAxisHeight({ height }) {
7984 this.xAxisHeight = height;
7985 this.update();
7986 }
7987 onActivate(event, group, fromLegend = false) {
7988 const item = Object.assign({}, event);
7989 if (group) {
7990 item.series = group.name;
7991 }
7992 const items = this.results
7993 .map(g => g.series)
7994 .flat()
7995 .filter(i => {
7996 if (fromLegend) {
7997 return i.label === item.name;
7998 }
7999 else {
8000 return i.name === item.name && i.series === item.series;
8001 }
8002 });
8003 this.activeEntries = [...items];
8004 this.activate.emit({ value: item, entries: this.activeEntries });
8005 }
8006 onDeactivate(event, group, fromLegend = false) {
8007 const item = Object.assign({}, event);
8008 if (group) {
8009 item.series = group.name;
8010 }
8011 this.activeEntries = this.activeEntries.filter(i => {
8012 if (fromLegend) {
8013 return i.label !== item.name;
8014 }
8015 else {
8016 return !(i.name === item.name && i.series === item.series);
8017 }
8018 });
8019 this.deactivate.emit({ value: item, entries: this.activeEntries });
8020 }
8021}
8022BarVerticalStackedComponent.decorators = [
8023 { type: Component, args: [{
8024 selector: 'ngx-charts-bar-vertical-stacked',
8025 template: `
8026 <ngx-charts-chart
8027 [view]="[width, height]"
8028 [showLegend]="legend"
8029 [legendOptions]="legendOptions"
8030 [activeEntries]="activeEntries"
8031 [animations]="animations"
8032 (legendLabelActivate)="onActivate($event, undefined, true)"
8033 (legendLabelDeactivate)="onDeactivate($event, undefined, true)"
8034 (legendLabelClick)="onClick($event)"
8035 >
8036 <svg:g [attr.transform]="transform" class="bar-chart chart">
8037 <svg:g
8038 ngx-charts-x-axis
8039 *ngIf="xAxis"
8040 [xScale]="xScale"
8041 [dims]="dims"
8042 [showLabel]="showXAxisLabel"
8043 [labelText]="xAxisLabel"
8044 [trimTicks]="trimXAxisTicks"
8045 [rotateTicks]="rotateXAxisTicks"
8046 [maxTickLength]="maxXAxisTickLength"
8047 [tickFormatting]="xAxisTickFormatting"
8048 [ticks]="xAxisTicks"
8049 [xAxisOffset]="dataLabelMaxHeight.negative"
8050 (dimensionsChanged)="updateXAxisHeight($event)"
8051 ></svg:g>
8052 <svg:g
8053 ngx-charts-y-axis
8054 *ngIf="yAxis"
8055 [yScale]="yScale"
8056 [dims]="dims"
8057 [showGridLines]="showGridLines"
8058 [showLabel]="showYAxisLabel"
8059 [labelText]="yAxisLabel"
8060 [trimTicks]="trimYAxisTicks"
8061 [maxTickLength]="maxYAxisTickLength"
8062 [tickFormatting]="yAxisTickFormatting"
8063 [ticks]="yAxisTicks"
8064 (dimensionsChanged)="updateYAxisWidth($event)"
8065 ></svg:g>
8066 <svg:g
8067 *ngFor="let group of results; let index = index; trackBy: trackBy"
8068 [@animationState]="'active'"
8069 [attr.transform]="groupTransform(group)"
8070 >
8071 <svg:g
8072 ngx-charts-series-vertical
8073 [type]="barChartType.Stacked"
8074 [xScale]="xScale"
8075 [yScale]="yScale"
8076 [activeEntries]="activeEntries"
8077 [colors]="colors"
8078 [series]="group.series"
8079 [dims]="dims"
8080 [gradient]="gradient"
8081 [tooltipDisabled]="tooltipDisabled"
8082 [tooltipTemplate]="tooltipTemplate"
8083 [showDataLabel]="showDataLabel"
8084 [dataLabelFormatting]="dataLabelFormatting"
8085 [seriesName]="group.name"
8086 [animations]="animations"
8087 [noBarWhenZero]="noBarWhenZero"
8088 (select)="onClick($event, group)"
8089 (activate)="onActivate($event, group)"
8090 (deactivate)="onDeactivate($event, group)"
8091 (dataLabelHeightChanged)="onDataLabelMaxHeightChanged($event, index)"
8092 />
8093 </svg:g>
8094 </svg:g>
8095 </ngx-charts-chart>
8096 `,
8097 encapsulation: ViewEncapsulation.None,
8098 changeDetection: ChangeDetectionStrategy.OnPush,
8099 animations: [
8100 trigger('animationState', [
8101 transition(':leave', [
8102 style({
8103 opacity: 1,
8104 transform: '*'
8105 }),
8106 animate(500, style({ opacity: 0, transform: 'scale(0)' }))
8107 ])
8108 ])
8109 ],
8110 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
8111 },] }
8112];
8113BarVerticalStackedComponent.propDecorators = {
8114 legend: [{ type: Input }],
8115 legendTitle: [{ type: Input }],
8116 legendPosition: [{ type: Input }],
8117 xAxis: [{ type: Input }],
8118 yAxis: [{ type: Input }],
8119 showXAxisLabel: [{ type: Input }],
8120 showYAxisLabel: [{ type: Input }],
8121 xAxisLabel: [{ type: Input }],
8122 yAxisLabel: [{ type: Input }],
8123 tooltipDisabled: [{ type: Input }],
8124 gradient: [{ type: Input }],
8125 showGridLines: [{ type: Input }],
8126 activeEntries: [{ type: Input }],
8127 schemeType: [{ type: Input }],
8128 trimXAxisTicks: [{ type: Input }],
8129 trimYAxisTicks: [{ type: Input }],
8130 rotateXAxisTicks: [{ type: Input }],
8131 maxXAxisTickLength: [{ type: Input }],
8132 maxYAxisTickLength: [{ type: Input }],
8133 xAxisTickFormatting: [{ type: Input }],
8134 yAxisTickFormatting: [{ type: Input }],
8135 xAxisTicks: [{ type: Input }],
8136 yAxisTicks: [{ type: Input }],
8137 barPadding: [{ type: Input }],
8138 roundDomains: [{ type: Input }],
8139 yScaleMax: [{ type: Input }],
8140 showDataLabel: [{ type: Input }],
8141 dataLabelFormatting: [{ type: Input }],
8142 noBarWhenZero: [{ type: Input }],
8143 activate: [{ type: Output }],
8144 deactivate: [{ type: Output }],
8145 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
8146};
8147
8148var D0Types;
8149(function (D0Types) {
8150 D0Types["positive"] = "positive";
8151 D0Types["negative"] = "negative";
8152})(D0Types || (D0Types = {}));
8153
8154class SeriesHorizontal {
8155 constructor() {
8156 this.type = BarChartType.Standard;
8157 this.tooltipDisabled = false;
8158 this.animations = true;
8159 this.showDataLabel = false;
8160 this.noBarWhenZero = true;
8161 this.select = new EventEmitter();
8162 this.activate = new EventEmitter();
8163 this.deactivate = new EventEmitter();
8164 this.dataLabelWidthChanged = new EventEmitter();
8165 this.barsForDataLabels = [];
8166 this.barOrientation = BarOrientation;
8167 }
8168 ngOnChanges(changes) {
8169 this.update();
8170 }
8171 update() {
8172 this.updateTooltipSettings();
8173 const d0 = {
8174 [D0Types.positive]: 0,
8175 [D0Types.negative]: 0
8176 };
8177 let d0Type;
8178 d0Type = D0Types.positive;
8179 let total;
8180 if (this.type === BarChartType.Normalized) {
8181 total = this.series.map(d => d.value).reduce((sum, d) => sum + d, 0);
8182 }
8183 const xScaleMin = Math.max(this.xScale.domain()[0], 0);
8184 this.bars = this.series.map(d => {
8185 let value = d.value;
8186 const label = this.getLabel(d);
8187 const formattedLabel = formatLabel(label);
8188 const roundEdges = this.roundEdges;
8189 d0Type = value > 0 ? D0Types.positive : D0Types.negative;
8190 const bar = {
8191 value,
8192 label,
8193 roundEdges,
8194 data: d,
8195 formattedLabel
8196 };
8197 bar.height = this.yScale.bandwidth();
8198 if (this.type === BarChartType.Standard) {
8199 bar.width = Math.abs(this.xScale(value) - this.xScale(xScaleMin));
8200 if (value < 0) {
8201 bar.x = this.xScale(value);
8202 }
8203 else {
8204 bar.x = this.xScale(xScaleMin);
8205 }
8206 bar.y = this.yScale(label);
8207 }
8208 else if (this.type === BarChartType.Stacked) {
8209 const offset0 = d0[d0Type];
8210 const offset1 = offset0 + value;
8211 d0[d0Type] += value;
8212 bar.width = this.xScale(offset1) - this.xScale(offset0);
8213 bar.x = this.xScale(offset0);
8214 bar.y = 0;
8215 bar.offset0 = offset0;
8216 bar.offset1 = offset1;
8217 }
8218 else if (this.type === BarChartType.Normalized) {
8219 let offset0 = d0[d0Type];
8220 let offset1 = offset0 + value;
8221 d0[d0Type] += value;
8222 if (total > 0) {
8223 offset0 = (offset0 * 100) / total;
8224 offset1 = (offset1 * 100) / total;
8225 }
8226 else {
8227 offset0 = 0;
8228 offset1 = 0;
8229 }
8230 bar.width = this.xScale(offset1) - this.xScale(offset0);
8231 bar.x = this.xScale(offset0);
8232 bar.y = 0;
8233 bar.offset0 = offset0;
8234 bar.offset1 = offset1;
8235 value = (offset1 - offset0).toFixed(2) + '%';
8236 }
8237 if (this.colors.scaleType === ScaleType.Ordinal) {
8238 bar.color = this.colors.getColor(label);
8239 }
8240 else {
8241 if (this.type === BarChartType.Standard) {
8242 bar.color = this.colors.getColor(value);
8243 bar.gradientStops = this.colors.getLinearGradientStops(value);
8244 }
8245 else {
8246 bar.color = this.colors.getColor(bar.offset1);
8247 bar.gradientStops = this.colors.getLinearGradientStops(bar.offset1, bar.offset0);
8248 }
8249 }
8250 let tooltipLabel = formattedLabel;
8251 bar.ariaLabel = formattedLabel + ' ' + value.toLocaleString();
8252 if (this.seriesName !== null && this.seriesName !== undefined) {
8253 tooltipLabel = `${this.seriesName}${formattedLabel}`;
8254 bar.data.series = this.seriesName;
8255 bar.ariaLabel = this.seriesName + ' ' + bar.ariaLabel;
8256 }
8257 bar.tooltipText = this.tooltipDisabled
8258 ? undefined
8259 : `
8260 <span class="tooltip-label">${escapeLabel(tooltipLabel)}</span>
8261 <span class="tooltip-val">${this.dataLabelFormatting ? this.dataLabelFormatting(value) : value.toLocaleString()}</span>
8262 `;
8263 return bar;
8264 });
8265 this.updateDataLabels();
8266 }
8267 updateDataLabels() {
8268 if (this.type === BarChartType.Stacked) {
8269 this.barsForDataLabels = [];
8270 const section = {};
8271 section.series = this.seriesName;
8272 const totalPositive = this.series.map(d => d.value).reduce((sum, d) => (d > 0 ? sum + d : sum), 0);
8273 const totalNegative = this.series.map(d => d.value).reduce((sum, d) => (d < 0 ? sum + d : sum), 0);
8274 section.total = totalPositive + totalNegative;
8275 section.x = 0;
8276 section.y = 0;
8277 // if total is positive then we show it on the right, otherwise on the left
8278 if (section.total > 0) {
8279 section.width = this.xScale(totalPositive);
8280 }
8281 else {
8282 section.width = this.xScale(totalNegative);
8283 }
8284 section.height = this.yScale.bandwidth();
8285 this.barsForDataLabels.push(section);
8286 }
8287 else {
8288 this.barsForDataLabels = this.series.map(d => {
8289 var _a;
8290 const section = {};
8291 section.series = (_a = this.seriesName) !== null && _a !== void 0 ? _a : d.label;
8292 section.total = d.value;
8293 section.x = this.xScale(0);
8294 section.y = this.yScale(d.label);
8295 section.width = this.xScale(section.total) - this.xScale(0);
8296 section.height = this.yScale.bandwidth();
8297 return section;
8298 });
8299 }
8300 }
8301 updateTooltipSettings() {
8302 this.tooltipPlacement = this.tooltipDisabled ? undefined : PlacementTypes.Top;
8303 this.tooltipType = this.tooltipDisabled ? undefined : StyleTypes.tooltip;
8304 }
8305 isActive(entry) {
8306 if (!this.activeEntries)
8307 return false;
8308 const item = this.activeEntries.find(active => {
8309 return entry.name === active.name && entry.value === active.value;
8310 });
8311 return item !== undefined;
8312 }
8313 getLabel(dataItem) {
8314 if (dataItem.label) {
8315 return dataItem.label;
8316 }
8317 return dataItem.name;
8318 }
8319 trackBy(index, bar) {
8320 return bar.label;
8321 }
8322 trackDataLabelBy(index, barLabel) {
8323 return index + '#' + barLabel.series + '#' + barLabel.total;
8324 }
8325 click(data) {
8326 this.select.emit(data);
8327 }
8328}
8329SeriesHorizontal.decorators = [
8330 { type: Component, args: [{
8331 selector: 'g[ngx-charts-series-horizontal]',
8332 template: `
8333 <svg:g
8334 ngx-charts-bar
8335 *ngFor="let bar of bars; trackBy: trackBy"
8336 [@animationState]="'active'"
8337 [width]="bar.width"
8338 [height]="bar.height"
8339 [x]="bar.x"
8340 [y]="bar.y"
8341 [fill]="bar.color"
8342 [stops]="bar.gradientStops"
8343 [data]="bar.data"
8344 [orientation]="barOrientation.Horizontal"
8345 [roundEdges]="bar.roundEdges"
8346 (select)="click($event)"
8347 [gradient]="gradient"
8348 [isActive]="isActive(bar.data)"
8349 [ariaLabel]="bar.ariaLabel"
8350 [animations]="animations"
8351 (activate)="activate.emit($event)"
8352 (deactivate)="deactivate.emit($event)"
8353 ngx-tooltip
8354 [tooltipDisabled]="tooltipDisabled"
8355 [tooltipPlacement]="tooltipPlacement"
8356 [tooltipType]="tooltipType"
8357 [tooltipTitle]="tooltipTemplate ? undefined : bar.tooltipText"
8358 [tooltipTemplate]="tooltipTemplate"
8359 [tooltipContext]="bar.data"
8360 [noBarWhenZero]="noBarWhenZero"
8361 ></svg:g>
8362 <svg:g *ngIf="showDataLabel">
8363 <svg:g
8364 ngx-charts-bar-label
8365 *ngFor="let b of barsForDataLabels; let i = index; trackBy: trackDataLabelBy"
8366 [barX]="b.x"
8367 [barY]="b.y"
8368 [barWidth]="b.width"
8369 [barHeight]="b.height"
8370 [value]="b.total"
8371 [valueFormatting]="dataLabelFormatting"
8372 [orientation]="barOrientation.Horizontal"
8373 (dimensionsChanged)="dataLabelWidthChanged.emit({ size: $event, index: i })"
8374 />
8375 </svg:g>
8376 `,
8377 changeDetection: ChangeDetectionStrategy.OnPush,
8378 animations: [
8379 trigger('animationState', [
8380 transition(':leave', [
8381 style({
8382 opacity: 1
8383 }),
8384 animate(500, style({ opacity: 0 }))
8385 ])
8386 ])
8387 ]
8388 },] }
8389];
8390SeriesHorizontal.propDecorators = {
8391 dims: [{ type: Input }],
8392 type: [{ type: Input }],
8393 series: [{ type: Input }],
8394 xScale: [{ type: Input }],
8395 yScale: [{ type: Input }],
8396 colors: [{ type: Input }],
8397 tooltipDisabled: [{ type: Input }],
8398 gradient: [{ type: Input }],
8399 activeEntries: [{ type: Input }],
8400 seriesName: [{ type: Input }],
8401 tooltipTemplate: [{ type: Input }],
8402 roundEdges: [{ type: Input }],
8403 animations: [{ type: Input }],
8404 showDataLabel: [{ type: Input }],
8405 dataLabelFormatting: [{ type: Input }],
8406 noBarWhenZero: [{ type: Input }],
8407 select: [{ type: Output }],
8408 activate: [{ type: Output }],
8409 deactivate: [{ type: Output }],
8410 dataLabelWidthChanged: [{ type: Output }]
8411};
8412
8413class SeriesVerticalComponent {
8414 constructor() {
8415 this.type = BarChartType.Standard;
8416 this.tooltipDisabled = false;
8417 this.animations = true;
8418 this.showDataLabel = false;
8419 this.noBarWhenZero = true;
8420 this.select = new EventEmitter();
8421 this.activate = new EventEmitter();
8422 this.deactivate = new EventEmitter();
8423 this.dataLabelHeightChanged = new EventEmitter();
8424 this.barsForDataLabels = [];
8425 this.barOrientation = BarOrientation;
8426 }
8427 ngOnChanges(changes) {
8428 this.update();
8429 }
8430 update() {
8431 this.updateTooltipSettings();
8432 let width;
8433 if (this.series.length) {
8434 width = this.xScale.bandwidth();
8435 }
8436 width = Math.round(width);
8437 const yScaleMin = Math.max(this.yScale.domain()[0], 0);
8438 const d0 = {
8439 [D0Types.positive]: 0,
8440 [D0Types.negative]: 0
8441 };
8442 let d0Type = D0Types.positive;
8443 let total;
8444 if (this.type === BarChartType.Normalized) {
8445 total = this.series.map(d => d.value).reduce((sum, d) => sum + d, 0);
8446 }
8447 this.bars = this.series.map((d, index) => {
8448 let value = d.value;
8449 const label = this.getLabel(d);
8450 const formattedLabel = formatLabel(label);
8451 const roundEdges = this.roundEdges;
8452 d0Type = value > 0 ? D0Types.positive : D0Types.negative;
8453 const bar = {
8454 value,
8455 label,
8456 roundEdges,
8457 data: d,
8458 width,
8459 formattedLabel,
8460 height: 0,
8461 x: 0,
8462 y: 0
8463 };
8464 if (this.type === BarChartType.Standard) {
8465 bar.height = Math.abs(this.yScale(value) - this.yScale(yScaleMin));
8466 bar.x = this.xScale(label);
8467 if (value < 0) {
8468 bar.y = this.yScale(0);
8469 }
8470 else {
8471 bar.y = this.yScale(value);
8472 }
8473 }
8474 else if (this.type === BarChartType.Stacked) {
8475 const offset0 = d0[d0Type];
8476 const offset1 = offset0 + value;
8477 d0[d0Type] += value;
8478 bar.height = this.yScale(offset0) - this.yScale(offset1);
8479 bar.x = 0;
8480 bar.y = this.yScale(offset1);
8481 bar.offset0 = offset0;
8482 bar.offset1 = offset1;
8483 }
8484 else if (this.type === BarChartType.Normalized) {
8485 let offset0 = d0[d0Type];
8486 let offset1 = offset0 + value;
8487 d0[d0Type] += value;
8488 if (total > 0) {
8489 offset0 = (offset0 * 100) / total;
8490 offset1 = (offset1 * 100) / total;
8491 }
8492 else {
8493 offset0 = 0;
8494 offset1 = 0;
8495 }
8496 bar.height = this.yScale(offset0) - this.yScale(offset1);
8497 bar.x = 0;
8498 bar.y = this.yScale(offset1);
8499 bar.offset0 = offset0;
8500 bar.offset1 = offset1;
8501 value = (offset1 - offset0).toFixed(2) + '%';
8502 }
8503 if (this.colors.scaleType === ScaleType.Ordinal) {
8504 bar.color = this.colors.getColor(label);
8505 }
8506 else {
8507 if (this.type === BarChartType.Standard) {
8508 bar.color = this.colors.getColor(value);
8509 bar.gradientStops = this.colors.getLinearGradientStops(value);
8510 }
8511 else {
8512 bar.color = this.colors.getColor(bar.offset1);
8513 bar.gradientStops = this.colors.getLinearGradientStops(bar.offset1, bar.offset0);
8514 }
8515 }
8516 let tooltipLabel = formattedLabel;
8517 bar.ariaLabel = formattedLabel + ' ' + value.toLocaleString();
8518 if (this.seriesName !== null && this.seriesName !== undefined) {
8519 tooltipLabel = `${this.seriesName}${formattedLabel}`;
8520 bar.data.series = this.seriesName;
8521 bar.ariaLabel = this.seriesName + ' ' + bar.ariaLabel;
8522 }
8523 bar.tooltipText = this.tooltipDisabled
8524 ? undefined
8525 : `
8526 <span class="tooltip-label">${escapeLabel(tooltipLabel)}</span>
8527 <span class="tooltip-val">${this.dataLabelFormatting ? this.dataLabelFormatting(value) : value.toLocaleString()}</span>
8528 `;
8529 return bar;
8530 });
8531 this.updateDataLabels();
8532 }
8533 updateDataLabels() {
8534 if (this.type === BarChartType.Stacked) {
8535 this.barsForDataLabels = [];
8536 const section = {};
8537 section.series = this.seriesName;
8538 const totalPositive = this.series.map(d => d.value).reduce((sum, d) => (d > 0 ? sum + d : sum), 0);
8539 const totalNegative = this.series.map(d => d.value).reduce((sum, d) => (d < 0 ? sum + d : sum), 0);
8540 section.total = totalPositive + totalNegative;
8541 section.x = 0;
8542 section.y = 0;
8543 if (section.total > 0) {
8544 section.height = this.yScale(totalPositive);
8545 }
8546 else {
8547 section.height = this.yScale(totalNegative);
8548 }
8549 section.width = this.xScale.bandwidth();
8550 this.barsForDataLabels.push(section);
8551 }
8552 else {
8553 this.barsForDataLabels = this.series.map(d => {
8554 var _a;
8555 const section = {};
8556 section.series = (_a = this.seriesName) !== null && _a !== void 0 ? _a : d.label;
8557 section.total = d.value;
8558 section.x = this.xScale(d.label);
8559 section.y = this.yScale(0);
8560 section.height = this.yScale(section.total) - this.yScale(0);
8561 section.width = this.xScale.bandwidth();
8562 return section;
8563 });
8564 }
8565 }
8566 updateTooltipSettings() {
8567 this.tooltipPlacement = this.tooltipDisabled ? undefined : PlacementTypes.Top;
8568 this.tooltipType = this.tooltipDisabled ? undefined : StyleTypes.tooltip;
8569 }
8570 isActive(entry) {
8571 if (!this.activeEntries)
8572 return false;
8573 const item = this.activeEntries.find(active => {
8574 return entry.name === active.name && entry.value === active.value;
8575 });
8576 return item !== undefined;
8577 }
8578 onClick(data) {
8579 this.select.emit(data);
8580 }
8581 getLabel(dataItem) {
8582 if (dataItem.label) {
8583 return dataItem.label;
8584 }
8585 return dataItem.name;
8586 }
8587 trackBy(index, bar) {
8588 return bar.label;
8589 }
8590 trackDataLabelBy(index, barLabel) {
8591 return index + '#' + barLabel.series + '#' + barLabel.total;
8592 }
8593}
8594SeriesVerticalComponent.decorators = [
8595 { type: Component, args: [{
8596 selector: 'g[ngx-charts-series-vertical]',
8597 template: `
8598 <svg:g
8599 ngx-charts-bar
8600 *ngFor="let bar of bars; trackBy: trackBy"
8601 [@animationState]="'active'"
8602 [@.disabled]="!animations"
8603 [width]="bar.width"
8604 [height]="bar.height"
8605 [x]="bar.x"
8606 [y]="bar.y"
8607 [fill]="bar.color"
8608 [stops]="bar.gradientStops"
8609 [data]="bar.data"
8610 [orientation]="barOrientation.Vertical"
8611 [roundEdges]="bar.roundEdges"
8612 [gradient]="gradient"
8613 [ariaLabel]="bar.ariaLabel"
8614 [isActive]="isActive(bar.data)"
8615 (select)="onClick($event)"
8616 (activate)="activate.emit($event)"
8617 (deactivate)="deactivate.emit($event)"
8618 ngx-tooltip
8619 [tooltipDisabled]="tooltipDisabled"
8620 [tooltipPlacement]="tooltipPlacement"
8621 [tooltipType]="tooltipType"
8622 [tooltipTitle]="tooltipTemplate ? undefined : bar.tooltipText"
8623 [tooltipTemplate]="tooltipTemplate"
8624 [tooltipContext]="bar.data"
8625 [noBarWhenZero]="noBarWhenZero"
8626 [animations]="animations"
8627 ></svg:g>
8628 <svg:g *ngIf="showDataLabel">
8629 <svg:g
8630 ngx-charts-bar-label
8631 *ngFor="let b of barsForDataLabels; let i = index; trackBy: trackDataLabelBy"
8632 [barX]="b.x"
8633 [barY]="b.y"
8634 [barWidth]="b.width"
8635 [barHeight]="b.height"
8636 [value]="b.total"
8637 [valueFormatting]="dataLabelFormatting"
8638 [orientation]="barOrientation.Vertical"
8639 (dimensionsChanged)="dataLabelHeightChanged.emit({ size: $event, index: i })"
8640 />
8641 </svg:g>
8642 `,
8643 changeDetection: ChangeDetectionStrategy.OnPush,
8644 animations: [
8645 trigger('animationState', [
8646 transition(':leave', [
8647 style({
8648 opacity: 1
8649 }),
8650 animate(500, style({ opacity: 0 }))
8651 ])
8652 ])
8653 ]
8654 },] }
8655];
8656SeriesVerticalComponent.propDecorators = {
8657 dims: [{ type: Input }],
8658 type: [{ type: Input }],
8659 series: [{ type: Input }],
8660 xScale: [{ type: Input }],
8661 yScale: [{ type: Input }],
8662 colors: [{ type: Input }],
8663 gradient: [{ type: Input }],
8664 activeEntries: [{ type: Input }],
8665 seriesName: [{ type: Input }],
8666 tooltipDisabled: [{ type: Input }],
8667 tooltipTemplate: [{ type: Input }],
8668 roundEdges: [{ type: Input }],
8669 animations: [{ type: Input }],
8670 showDataLabel: [{ type: Input }],
8671 dataLabelFormatting: [{ type: Input }],
8672 noBarWhenZero: [{ type: Input }],
8673 select: [{ type: Output }],
8674 activate: [{ type: Output }],
8675 deactivate: [{ type: Output }],
8676 dataLabelHeightChanged: [{ type: Output }]
8677};
8678
8679class BarLabelComponent {
8680 constructor(element) {
8681 this.dimensionsChanged = new EventEmitter();
8682 this.horizontalPadding = 2;
8683 this.verticalPadding = 5;
8684 this.element = element.nativeElement;
8685 }
8686 ngOnChanges(changes) {
8687 this.update();
8688 }
8689 getSize() {
8690 const h = this.element.getBoundingClientRect().height;
8691 const w = this.element.getBoundingClientRect().width;
8692 return { height: h, width: w, negative: this.value < 0 };
8693 }
8694 ngAfterViewInit() {
8695 this.dimensionsChanged.emit(this.getSize());
8696 }
8697 update() {
8698 if (this.valueFormatting) {
8699 this.formatedValue = this.valueFormatting(this.value);
8700 }
8701 else {
8702 this.formatedValue = formatLabel(this.value);
8703 }
8704 if (this.orientation === 'horizontal') {
8705 this.x = this.barX + this.barWidth;
8706 // if the value is negative then it's on the left of the x0.
8707 // we need to put the data label in front of the bar
8708 if (this.value < 0) {
8709 this.x = this.x - this.horizontalPadding;
8710 this.textAnchor = 'end';
8711 }
8712 else {
8713 this.x = this.x + this.horizontalPadding;
8714 this.textAnchor = 'start';
8715 }
8716 this.y = this.barY + this.barHeight / 2;
8717 }
8718 else {
8719 // orientation must be "vertical"
8720 this.x = this.barX + this.barWidth / 2;
8721 this.y = this.barY + this.barHeight;
8722 if (this.value < 0) {
8723 this.y = this.y + this.verticalPadding;
8724 this.textAnchor = 'end';
8725 }
8726 else {
8727 this.y = this.y - this.verticalPadding;
8728 this.textAnchor = 'start';
8729 }
8730 this.transform = `rotate(-45, ${this.x} , ${this.y})`;
8731 }
8732 }
8733}
8734BarLabelComponent.decorators = [
8735 { type: Component, args: [{
8736 selector: 'g[ngx-charts-bar-label]',
8737 template: `
8738 <svg:text
8739 class="textDataLabel"
8740 alignment-baseline="middle"
8741 [attr.text-anchor]="textAnchor"
8742 [attr.transform]="transform"
8743 [attr.x]="x"
8744 [attr.y]="y"
8745 >
8746 {{ formatedValue }}
8747 </svg:text>
8748 `,
8749 changeDetection: ChangeDetectionStrategy.OnPush,
8750 styles: [".textDataLabel{font-size:11px}\n"]
8751 },] }
8752];
8753BarLabelComponent.ctorParameters = () => [
8754 { type: ElementRef }
8755];
8756BarLabelComponent.propDecorators = {
8757 value: [{ type: Input }],
8758 valueFormatting: [{ type: Input }],
8759 barX: [{ type: Input }],
8760 barY: [{ type: Input }],
8761 barWidth: [{ type: Input }],
8762 barHeight: [{ type: Input }],
8763 orientation: [{ type: Input }],
8764 dimensionsChanged: [{ type: Output }]
8765};
8766
8767class BarChartModule {
8768}
8769BarChartModule.decorators = [
8770 { type: NgModule, args: [{
8771 imports: [ChartCommonModule],
8772 declarations: [
8773 BarComponent,
8774 BarHorizontalComponent,
8775 BarHorizontal2DComponent,
8776 BarHorizontalNormalizedComponent,
8777 BarHorizontalStackedComponent,
8778 BarVerticalComponent,
8779 BarVertical2DComponent,
8780 BarVerticalNormalizedComponent,
8781 BarVerticalStackedComponent,
8782 BarLabelComponent,
8783 SeriesHorizontal,
8784 SeriesVerticalComponent
8785 ],
8786 exports: [
8787 BarComponent,
8788 BarHorizontalComponent,
8789 BarHorizontal2DComponent,
8790 BarHorizontalNormalizedComponent,
8791 BarHorizontalStackedComponent,
8792 BarVerticalComponent,
8793 BarVertical2DComponent,
8794 BarVerticalNormalizedComponent,
8795 BarVerticalStackedComponent,
8796 BarLabelComponent,
8797 SeriesHorizontal,
8798 SeriesVerticalComponent
8799 ]
8800 },] }
8801];
8802
8803class BoxChartComponent extends BaseChartComponent {
8804 constructor() {
8805 super(...arguments);
8806 /** Show or hide the legend. */
8807 this.legend = false;
8808 this.legendPosition = LegendPosition.Right;
8809 this.legendTitle = 'Legend';
8810 this.showGridLines = true;
8811 this.xAxis = true;
8812 this.yAxis = true;
8813 this.showXAxisLabel = true;
8814 this.showYAxisLabel = true;
8815 this.roundDomains = false;
8816 this.roundEdges = true;
8817 this.strokeColor = '#FFFFFF';
8818 this.strokeWidth = 2;
8819 this.tooltipDisabled = false;
8820 this.select = new EventEmitter();
8821 this.activate = new EventEmitter();
8822 this.deactivate = new EventEmitter();
8823 /** Chart Margins (For each side, counterclock wise). */
8824 this.margin = [10, 20, 10, 20];
8825 /** Chart X axis dimension. */
8826 this.xAxisHeight = 0;
8827 /** Chart Y axis dimension. */
8828 this.yAxisWidth = 0;
8829 }
8830 trackBy(index, item) {
8831 return item.name;
8832 }
8833 update() {
8834 super.update();
8835 this.dims = calculateViewDimensions({
8836 width: this.width,
8837 height: this.height,
8838 margins: this.margin,
8839 showXAxis: this.xAxis,
8840 showYAxis: this.yAxis,
8841 xAxisHeight: this.xAxisHeight,
8842 yAxisWidth: this.yAxisWidth,
8843 showXLabel: this.showXAxisLabel,
8844 showYLabel: this.showYAxisLabel,
8845 showLegend: this.legend,
8846 legendPosition: this.legendPosition
8847 });
8848 this.xDomain = this.getXDomain();
8849 this.yDomain = this.getYDomain();
8850 this.seriesDomain = this.getSeriesDomain();
8851 this.setScales();
8852 this.setColors();
8853 this.legendOptions = this.getLegendOptions();
8854 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
8855 }
8856 setColors() {
8857 let domain = [];
8858 if (this.schemeType === ScaleType.Ordinal) {
8859 domain = this.seriesDomain;
8860 }
8861 else {
8862 domain = this.yDomain;
8863 }
8864 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
8865 }
8866 setScales() {
8867 this.xScale = this.getXScale(this.xDomain, this.dims.width);
8868 this.yScale = this.getYScale(this.yDomain, this.dims.height);
8869 }
8870 getXScale(domain, width) {
8871 const scale = scaleBand()
8872 .domain(domain.map(d => d.toString()))
8873 .rangeRound([0, width])
8874 .padding(0.5);
8875 return scale;
8876 }
8877 getYScale(domain, height) {
8878 const scale = scaleLinear().domain(domain).range([height, 0]);
8879 return this.roundDomains ? scale.nice() : scale;
8880 }
8881 getUniqueBoxChartXDomainValues(results) {
8882 const valueSet = new Set();
8883 for (const result of results) {
8884 valueSet.add(result.name);
8885 }
8886 return Array.from(valueSet);
8887 }
8888 getXDomain() {
8889 let domain = [];
8890 const values = this.getUniqueBoxChartXDomainValues(this.results);
8891 let min;
8892 let max;
8893 if (typeof values[0] === 'string') {
8894 domain = values.map(val => val.toString());
8895 }
8896 else if (typeof values[0] === 'number') {
8897 const mappedValues = values.map(v => Number(v));
8898 min = Math.min(...mappedValues);
8899 max = Math.max(...mappedValues);
8900 domain = [min, max];
8901 }
8902 else {
8903 const mappedValues = values.map(v => Number(new Date(v)));
8904 min = Math.min(...mappedValues);
8905 max = Math.max(...mappedValues);
8906 domain = [new Date(min), new Date(max)];
8907 }
8908 return domain;
8909 }
8910 getYDomain() {
8911 const domain = [];
8912 for (const results of this.results) {
8913 for (const d of results.series) {
8914 if (domain.indexOf(d.value) < 0) {
8915 domain.push(d.value);
8916 }
8917 }
8918 }
8919 const values = [...domain];
8920 const mappedValues = values.map(v => Number(v));
8921 const min = Math.min(...mappedValues);
8922 const max = Math.max(...mappedValues);
8923 return [min, max];
8924 }
8925 getSeriesDomain() {
8926 return this.results.map(d => `${d.name}`);
8927 }
8928 updateYAxisWidth({ width }) {
8929 this.yAxisWidth = width;
8930 this.update();
8931 }
8932 updateXAxisHeight({ height }) {
8933 this.xAxisHeight = height;
8934 this.update();
8935 }
8936 onClick(data) {
8937 this.select.emit(data);
8938 }
8939 onActivate(data) {
8940 this.activate.emit(data);
8941 }
8942 onDeactivate(data) {
8943 this.deactivate.emit(data);
8944 }
8945 getLegendOptions() {
8946 const legendOpts = {
8947 scaleType: this.schemeType,
8948 colors: this.colors,
8949 domain: [],
8950 position: this.legendPosition,
8951 title: this.legendTitle
8952 };
8953 if (this.schemeType === ScaleType.Ordinal) {
8954 legendOpts.domain = this.xDomain;
8955 legendOpts.colors = this.colors;
8956 }
8957 else {
8958 legendOpts.domain = this.yDomain;
8959 legendOpts.colors = this.colors.scale;
8960 }
8961 return legendOpts;
8962 }
8963}
8964BoxChartComponent.decorators = [
8965 { type: Component, args: [{
8966 selector: 'ngx-charts-box-chart',
8967 template: `
8968 <ngx-charts-chart
8969 [view]="[width, height]"
8970 [showLegend]="legend"
8971 [legendOptions]="legendOptions"
8972 [animations]="animations"
8973 (legendLabelClick)="onClick($event)"
8974 (legendLabelActivate)="onActivate($event)"
8975 (legendLabelDeactivate)="onDeactivate($event)"
8976 >
8977 <svg:g [attr.transform]="transform" class="box-chart chart">
8978 <svg:g
8979 ngx-charts-x-axis
8980 [showGridLines]="showGridLines"
8981 [dims]="dims"
8982 [xScale]="xScale"
8983 [showLabel]="showXAxisLabel"
8984 [labelText]="xAxisLabel"
8985 (dimensionsChanged)="updateXAxisHeight($event)"
8986 />
8987 <svg:g
8988 ngx-charts-y-axis
8989 [showGridLines]="showGridLines"
8990 [dims]="dims"
8991 [yScale]="yScale"
8992 [showLabel]="showYAxisLabel"
8993 [labelText]="yAxisLabel"
8994 (dimensionsChanged)="updateYAxisWidth($event)"
8995 />
8996 </svg:g>
8997 <svg:g [attr.transform]="transform">
8998 <svg:g *ngFor="let result of results; trackBy: trackBy">
8999 <svg:g
9000 ngx-charts-box-series
9001 [xScale]="xScale"
9002 [yScale]="yScale"
9003 [colors]="colors"
9004 [roundEdges]="roundEdges"
9005 [strokeColor]="strokeColor"
9006 [strokeWidth]="strokeWidth"
9007 [tooltipDisabled]="tooltipDisabled"
9008 [tooltipTemplate]="tooltipTemplate"
9009 [series]="result"
9010 [dims]="dims"
9011 [animations]="animations"
9012 [gradient]="gradient"
9013 (activate)="onActivate($event)"
9014 (deactivate)="onDeactivate($event)"
9015 (select)="onClick($event)"
9016 />
9017 </svg:g>
9018 </svg:g>
9019 </ngx-charts-chart>
9020 `,
9021 changeDetection: ChangeDetectionStrategy.OnPush,
9022 encapsulation: ViewEncapsulation.None,
9023 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
9024 },] }
9025];
9026BoxChartComponent.propDecorators = {
9027 legend: [{ type: Input }],
9028 legendPosition: [{ type: Input }],
9029 legendTitle: [{ type: Input }],
9030 legendOptionsConfig: [{ type: Input }],
9031 showGridLines: [{ type: Input }],
9032 xAxis: [{ type: Input }],
9033 yAxis: [{ type: Input }],
9034 showXAxisLabel: [{ type: Input }],
9035 showYAxisLabel: [{ type: Input }],
9036 roundDomains: [{ type: Input }],
9037 xAxisLabel: [{ type: Input }],
9038 yAxisLabel: [{ type: Input }],
9039 roundEdges: [{ type: Input }],
9040 strokeColor: [{ type: Input }],
9041 strokeWidth: [{ type: Input }],
9042 tooltipDisabled: [{ type: Input }],
9043 gradient: [{ type: Input }],
9044 select: [{ type: Output }],
9045 activate: [{ type: Output }],
9046 deactivate: [{ type: Output }],
9047 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate', { static: false },] }]
9048};
9049
9050class BoxSeriesComponent {
9051 constructor() {
9052 this.animations = true;
9053 this.tooltipDisabled = false;
9054 this.gradient = false;
9055 this.select = new EventEmitter();
9056 this.activate = new EventEmitter();
9057 this.deactivate = new EventEmitter();
9058 }
9059 ngOnChanges(changes) {
9060 this.update();
9061 }
9062 onClick(data) {
9063 this.select.emit(data);
9064 }
9065 update() {
9066 this.updateTooltipSettings();
9067 const width = this.series && this.series.series.length ? Math.round(this.xScale.bandwidth()) : null;
9068 const seriesName = this.series.name;
9069 // Calculate Quantile and Whiskers for each box serie.
9070 this.counts = this.series.series;
9071 const mappedCounts = this.counts.map(serie => Number(serie.value));
9072 this.whiskers = [min(mappedCounts), max(mappedCounts)];
9073 // We get the group count and must sort it in order to retrieve quantiles.
9074 const groupCounts = this.counts.map(item => item.value).sort((a, b) => Number(a) - Number(b));
9075 this.quartiles = this.getBoxQuantiles(groupCounts);
9076 this.lineCoordinates = this.getLinesCoordinates(seriesName.toString(), this.whiskers, this.quartiles, width);
9077 const value = this.quartiles[1];
9078 const formattedLabel = formatLabel(seriesName);
9079 const box = {
9080 value,
9081 data: this.counts,
9082 label: seriesName,
9083 formattedLabel,
9084 width,
9085 height: 0,
9086 x: 0,
9087 y: 0,
9088 roundEdges: this.roundEdges,
9089 quartiles: this.quartiles,
9090 lineCoordinates: this.lineCoordinates
9091 };
9092 box.height = Math.abs(this.yScale(this.quartiles[0]) - this.yScale(this.quartiles[2]));
9093 box.x = this.xScale(seriesName.toString());
9094 box.y = this.yScale(this.quartiles[2]);
9095 box.ariaLabel = formattedLabel + ' - Median: ' + value.toLocaleString();
9096 if (this.colors.scaleType === ScaleType.Ordinal) {
9097 box.color = this.colors.getColor(seriesName);
9098 }
9099 else {
9100 box.color = this.colors.getColor(this.quartiles[1]);
9101 box.gradientStops = this.colors.getLinearGradientStops(this.quartiles[0], this.quartiles[2]);
9102 }
9103 const tooltipLabel = formattedLabel;
9104 const formattedTooltipLabel = `
9105 <span class="tooltip-label">${escapeLabel(tooltipLabel)}</span>
9106 <span class="tooltip-val">
9107 • Q1: ${this.quartiles[0]} • Q2: ${this.quartiles[1]} • Q3: ${this.quartiles[2]}<br>
9108 • Min: ${this.whiskers[0]} • Max: ${this.whiskers[1]}
9109 </span>`;
9110 box.tooltipText = this.tooltipDisabled ? undefined : formattedTooltipLabel;
9111 this.tooltipTitle = this.tooltipDisabled ? undefined : box.tooltipText;
9112 this.box = box;
9113 }
9114 getBoxQuantiles(inputData) {
9115 return [quantile(inputData, 0.25), quantile(inputData, 0.5), quantile(inputData, 0.75)];
9116 }
9117 getLinesCoordinates(seriesName, whiskers, quartiles, barWidth) {
9118 // The X value is not being centered, so had to sum half the width to align it.
9119 const commonX = this.xScale(seriesName);
9120 const offsetX = commonX + barWidth / 2;
9121 const medianLineWidth = Math.max(barWidth + 4 * this.strokeWidth, 1);
9122 const whiskerLineWidth = Math.max(barWidth / 3, 1);
9123 const whiskerZero = this.yScale(whiskers[0]);
9124 const whiskerOne = this.yScale(whiskers[1]);
9125 const median = this.yScale(quartiles[1]);
9126 const topLine = {
9127 v1: { x: offsetX + whiskerLineWidth / 2, y: whiskerZero },
9128 v2: { x: offsetX - whiskerLineWidth / 2, y: whiskerZero }
9129 };
9130 const medianLine = {
9131 v1: { x: offsetX + medianLineWidth / 2, y: median },
9132 v2: { x: offsetX - medianLineWidth / 2, y: median }
9133 };
9134 const bottomLine = {
9135 v1: { x: offsetX + whiskerLineWidth / 2, y: whiskerOne },
9136 v2: { x: offsetX - whiskerLineWidth / 2, y: whiskerOne }
9137 };
9138 const verticalLine = {
9139 v1: { x: offsetX, y: whiskerZero },
9140 v2: { x: offsetX, y: whiskerOne }
9141 };
9142 return [verticalLine, topLine, medianLine, bottomLine];
9143 }
9144 updateTooltipSettings() {
9145 if (this.tooltipDisabled) {
9146 this.tooltipPlacement = undefined;
9147 this.tooltipType = undefined;
9148 }
9149 else {
9150 if (!this.tooltipPlacement) {
9151 this.tooltipPlacement = PlacementTypes.Top;
9152 }
9153 if (!this.tooltipType) {
9154 this.tooltipType = StyleTypes.tooltip;
9155 }
9156 }
9157 }
9158}
9159BoxSeriesComponent.decorators = [
9160 { type: Component, args: [{
9161 selector: 'g[ngx-charts-box-series]',
9162 template: `
9163 <svg:g
9164 ngx-charts-box
9165 [@animationState]="'active'"
9166 [@.disabled]="!animations"
9167 [width]="box.width"
9168 [height]="box.height"
9169 [x]="box.x"
9170 [y]="box.y"
9171 [roundEdges]="box.roundEdges"
9172 [fill]="box.color"
9173 [gradientStops]="box.gradientStops"
9174 [strokeColor]="strokeColor"
9175 [strokeWidth]="strokeWidth"
9176 [data]="box.data"
9177 [lineCoordinates]="box.lineCoordinates"
9178 [gradient]="gradient"
9179 [ariaLabel]="box.ariaLabel"
9180 (select)="onClick($event)"
9181 (activate)="activate.emit($event)"
9182 (deactivate)="deactivate.emit($event)"
9183 ngx-tooltip
9184 [tooltipDisabled]="tooltipDisabled"
9185 [tooltipPlacement]="tooltipPlacement"
9186 [tooltipType]="tooltipType"
9187 [tooltipTitle]="tooltipTitle"
9188 [tooltipTemplate]="tooltipTemplate"
9189 [tooltipContext]="box.data"
9190 [animations]="animations"
9191 ></svg:g>
9192 `,
9193 changeDetection: ChangeDetectionStrategy.OnPush,
9194 animations: [
9195 trigger('animationState', [
9196 transition(':leave', [
9197 style({
9198 opacity: 1
9199 }),
9200 animate(500, style({ opacity: 0 }))
9201 ])
9202 ])
9203 ]
9204 },] }
9205];
9206BoxSeriesComponent.propDecorators = {
9207 dims: [{ type: Input }],
9208 series: [{ type: Input }],
9209 xScale: [{ type: Input }],
9210 yScale: [{ type: Input }],
9211 colors: [{ type: Input }],
9212 animations: [{ type: Input }],
9213 strokeColor: [{ type: Input }],
9214 strokeWidth: [{ type: Input }],
9215 tooltipDisabled: [{ type: Input }],
9216 tooltipTemplate: [{ type: Input }],
9217 tooltipPlacement: [{ type: Input }],
9218 tooltipType: [{ type: Input }],
9219 roundEdges: [{ type: Input }],
9220 gradient: [{ type: Input }],
9221 select: [{ type: Output }],
9222 activate: [{ type: Output }],
9223 deactivate: [{ type: Output }]
9224};
9225
9226class BoxComponent {
9227 constructor(element, cd) {
9228 this.cd = cd;
9229 this.roundEdges = true;
9230 this.gradient = false;
9231 this.offset = 0;
9232 this.isActive = false;
9233 this.animations = true;
9234 this.noBarWhenZero = true;
9235 this.select = new EventEmitter();
9236 this.activate = new EventEmitter();
9237 this.deactivate = new EventEmitter();
9238 this.BarOrientation = BarOrientation;
9239 this.initialized = false;
9240 this.hasGradient = false;
9241 this.hideBar = false;
9242 this.nativeElm = element.nativeElement;
9243 }
9244 ngOnChanges(changes) {
9245 if (!this.initialized) {
9246 this.loadAnimation();
9247 this.initialized = true;
9248 }
9249 else {
9250 this.update();
9251 }
9252 }
9253 update() {
9254 this.boxStrokeWidth = Math.max(this.strokeWidth, 1);
9255 this.whiskerStrokeWidth = Math.max(this.strokeWidth / 2, 1);
9256 this.medianLineWidth = 1.5 * this.strokeWidth;
9257 this.gradientId = 'grad' + id().toString();
9258 this.gradientFill = `url(#${this.gradientId})`;
9259 if (this.gradient) {
9260 this.gradientStops = this.getGradient();
9261 this.hasGradient = true;
9262 }
9263 else {
9264 this.hasGradient = false;
9265 }
9266 this.updateLineEl();
9267 this.updatePathEl();
9268 this.checkToHideBar();
9269 this.maskLineId = 'mask' + id().toString();
9270 this.maskLine = `url(#${this.maskLineId})`;
9271 if (this.cd) {
9272 this.cd.markForCheck();
9273 }
9274 }
9275 loadAnimation() {
9276 this.boxPath = this.oldPath = this.getStartingPath();
9277 this.oldLineCoordinates = this.getStartingLineCoordinates();
9278 setTimeout(this.update.bind(this), 100);
9279 }
9280 updatePathEl() {
9281 const nodeBar = select(this.nativeElm).selectAll('.bar');
9282 const path = this.getPath();
9283 if (this.animations) {
9284 nodeBar
9285 .attr('d', this.oldPath)
9286 .transition()
9287 .ease(easeSinInOut)
9288 .duration(500)
9289 .attrTween('d', this.pathTween(path, 4));
9290 }
9291 else {
9292 nodeBar.attr('d', path);
9293 }
9294 this.oldPath = path;
9295 }
9296 updateLineEl() {
9297 const lineEl = select(this.nativeElm).selectAll('.bar-line');
9298 const lineCoordinates = this.lineCoordinates;
9299 const oldLineCoordinates = this.oldLineCoordinates;
9300 if (this.animations) {
9301 lineEl
9302 .attr('x1', (_, index) => oldLineCoordinates[index].v1.x)
9303 .attr('y1', (_, index) => oldLineCoordinates[index].v1.y)
9304 .attr('x2', (_, index) => oldLineCoordinates[index].v2.x)
9305 .attr('y2', (_, index) => oldLineCoordinates[index].v2.y)
9306 .transition()
9307 .ease(easeSinInOut)
9308 .duration(500)
9309 .attr('x1', (_, index) => lineCoordinates[index].v1.x)
9310 .attr('y1', (_, index) => lineCoordinates[index].v1.y)
9311 .attr('x2', (_, index) => lineCoordinates[index].v2.x)
9312 .attr('y2', (_, index) => lineCoordinates[index].v2.y);
9313 }
9314 else {
9315 lineEl
9316 .attr('x1', (_, index) => lineCoordinates[index].v1.x)
9317 .attr('y1', (_, index) => lineCoordinates[index].v1.y)
9318 .attr('x2', (_, index) => lineCoordinates[index].v2.x)
9319 .attr('y2', (_, index) => lineCoordinates[index].v2.y);
9320 }
9321 this.oldLineCoordinates = [...lineCoordinates];
9322 }
9323 /**
9324 * See [D3 Selections](https://www.d3indepth.com/selections/)
9325 * @param d The joined data.
9326 * @param index The index of the element within the selection
9327 * @param node The node element (Line).
9328 */
9329 lineTween(attr, d, index, node) {
9330 const nodeLineEl = node[index];
9331 return nodeLineEl[attr].baseVal.value;
9332 }
9333 // TODO: Refactor into another .ts file if https://github.com/swimlane/ngx-charts/pull/1179 gets merged.
9334 pathTween(d1, precision) {
9335 return function () {
9336 // tslint:disable-next-line: no-this-assignment
9337 const path0 = this;
9338 const path1 = this.cloneNode();
9339 path1.setAttribute('d', d1);
9340 const n0 = path0 === null || path0 === void 0 ? void 0 : path0.getTotalLength();
9341 const n1 = path1 === null || path1 === void 0 ? void 0 : path1.getTotalLength();
9342 // Uniform sampling of distance based on specified precision.
9343 const distances = [0];
9344 let i = 0;
9345 const dt = precision / Math.max(n0, n1);
9346 while (i < 1) {
9347 distances.push(i);
9348 i += dt;
9349 }
9350 distances.push(1);
9351 // Compute point-interpolators at each distance.
9352 const points = distances.map((t) => {
9353 const p0 = path0.getPointAtLength(t * n0);
9354 const p1 = path1.getPointAtLength(t * n1);
9355 return interpolate([p0.x, p0.y], [p1.x, p1.y]);
9356 });
9357 // 't': T is the fraction of time (between 0 and 1) since the transition began.
9358 return (t) => {
9359 return t < 1 ? 'M' + points.map((p) => p(t)).join('L') : d1;
9360 };
9361 };
9362 }
9363 getStartingPath() {
9364 if (!this.animations) {
9365 return this.getPath();
9366 }
9367 const radius = this.roundEdges ? 1 : 0;
9368 const { x, y } = this.lineCoordinates[2].v1;
9369 return roundedRect(x - this.width, y - 1, this.width, 2, radius, this.edges);
9370 }
9371 getPath() {
9372 const radius = this.getRadius();
9373 let path = '';
9374 path = roundedRect(this.x, this.y, this.width, this.height, Math.min(this.height, radius), this.edges);
9375 return path;
9376 }
9377 getStartingLineCoordinates() {
9378 if (!this.animations) {
9379 return [...this.lineCoordinates];
9380 }
9381 const lineCoordinates = cloneDeep(this.lineCoordinates);
9382 lineCoordinates[1].v1.y = lineCoordinates[1].v2.y = lineCoordinates[3].v1.y = lineCoordinates[3].v2.y = lineCoordinates[0].v1.y = lineCoordinates[0].v2.y =
9383 lineCoordinates[2].v1.y;
9384 return lineCoordinates;
9385 }
9386 getRadius() {
9387 let radius = 0;
9388 if (this.roundEdges && this.height > 5 && this.width > 5) {
9389 radius = Math.floor(Math.min(5, this.height / 2, this.width / 2));
9390 }
9391 return radius;
9392 }
9393 getGradient() {
9394 return [
9395 {
9396 offset: 0,
9397 color: this.fill,
9398 opacity: this.getStartOpacity()
9399 },
9400 {
9401 offset: 100,
9402 color: this.fill,
9403 opacity: 1
9404 }
9405 ];
9406 }
9407 getStartOpacity() {
9408 if (this.roundEdges) {
9409 return 0.2;
9410 }
9411 else {
9412 return 0.5;
9413 }
9414 }
9415 get edges() {
9416 let edges = [false, false, false, false];
9417 if (this.roundEdges) {
9418 edges = [true, true, true, true];
9419 }
9420 return edges;
9421 }
9422 onMouseEnter() {
9423 this.activate.emit(this.data);
9424 }
9425 onMouseLeave() {
9426 this.deactivate.emit(this.data);
9427 }
9428 checkToHideBar() {
9429 this.hideBar = this.noBarWhenZero && this.height === 0;
9430 }
9431}
9432BoxComponent.decorators = [
9433 { type: Component, args: [{
9434 selector: 'g[ngx-charts-box]',
9435 template: `
9436 <svg:defs>
9437 <svg:g
9438 *ngIf="hasGradient"
9439 ngx-charts-svg-linear-gradient
9440 [orientation]="BarOrientation.Vertical"
9441 [name]="gradientId"
9442 [stops]="gradientStops"
9443 />
9444 <svg:mask [attr.id]="maskLineId">
9445 <svg:g>
9446 <rect height="100%" width="100%" fill="white" fill-opacity="1" />
9447 <path class="bar" [attr.d]="boxPath" fill="black" fill-opacity="1" />
9448 </svg:g>
9449 </svg:mask>
9450 </svg:defs>
9451 <svg:g>
9452 <svg:path
9453 class="bar"
9454 role="img"
9455 tabIndex="-1"
9456 [class.active]="isActive"
9457 [class.hidden]="hideBar"
9458 [attr.d]="boxPath"
9459 [attr.stroke]="strokeColor"
9460 [attr.stroke-width]="boxStrokeWidth"
9461 [attr.aria-label]="ariaLabel"
9462 [attr.fill]="hasGradient ? gradientFill : fill"
9463 (click)="select.emit(data)"
9464 />
9465 <svg:line
9466 *ngFor="let line of lineCoordinates; let i = index"
9467 class="bar-line"
9468 [class.hidden]="hideBar"
9469 [attr.x1]="line.v1.x"
9470 [attr.y1]="line.v1.y"
9471 [attr.x2]="line.v2.x"
9472 [attr.y2]="line.v2.y"
9473 [attr.stroke]="strokeColor"
9474 [attr.stroke-width]="i === 2 ? medianLineWidth : whiskerStrokeWidth"
9475 [attr.mask]="i ? undefined : maskLine"
9476 fill="none"
9477 />
9478 </svg:g>
9479 `,
9480 changeDetection: ChangeDetectionStrategy.OnPush
9481 },] }
9482];
9483BoxComponent.ctorParameters = () => [
9484 { type: ElementRef },
9485 { type: ChangeDetectorRef }
9486];
9487BoxComponent.propDecorators = {
9488 strokeColor: [{ type: Input }],
9489 strokeWidth: [{ type: Input }],
9490 fill: [{ type: Input }],
9491 data: [{ type: Input }],
9492 width: [{ type: Input }],
9493 height: [{ type: Input }],
9494 x: [{ type: Input }],
9495 y: [{ type: Input }],
9496 lineCoordinates: [{ type: Input }],
9497 roundEdges: [{ type: Input }],
9498 gradient: [{ type: Input }],
9499 gradientStops: [{ type: Input }],
9500 offset: [{ type: Input }],
9501 isActive: [{ type: Input }],
9502 animations: [{ type: Input }],
9503 ariaLabel: [{ type: Input }],
9504 noBarWhenZero: [{ type: Input }],
9505 select: [{ type: Output }],
9506 activate: [{ type: Output }],
9507 deactivate: [{ type: Output }],
9508 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
9509 onMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
9510};
9511
9512class BoxChartModule {
9513}
9514BoxChartModule.decorators = [
9515 { type: NgModule, args: [{
9516 imports: [ChartCommonModule],
9517 declarations: [BoxChartComponent, BoxSeriesComponent, BoxComponent],
9518 exports: [BoxChartComponent, BoxSeriesComponent, BoxComponent]
9519 },] }
9520];
9521
9522function getDomain(values, scaleType, autoScale, minVal, maxVal) {
9523 let domain = [];
9524 if (scaleType === ScaleType.Linear) {
9525 values = values.map(v => Number(v));
9526 if (!autoScale) {
9527 values.push(0);
9528 }
9529 }
9530 if (scaleType === ScaleType.Time || scaleType === ScaleType.Linear) {
9531 const min = minVal ? minVal : Math.min(...values);
9532 const max = maxVal ? maxVal : Math.max(...values);
9533 domain = [min, max];
9534 }
9535 else {
9536 domain = values;
9537 }
9538 return domain;
9539}
9540function getScale(domain, range, scaleType, roundDomains) {
9541 switch (scaleType) {
9542 case ScaleType.Time:
9543 return scaleTime().range(range).domain(domain);
9544 case ScaleType.Linear: {
9545 const scale = scaleLinear().range(range).domain(domain);
9546 if (roundDomains) {
9547 return scale.nice();
9548 }
9549 return scale;
9550 }
9551 case ScaleType.Ordinal:
9552 return scalePoint()
9553 .range([range[0], range[1]])
9554 .domain(domain.map(r => r.toString()));
9555 default:
9556 return undefined;
9557 }
9558}
9559
9560class BubbleChartComponent extends BaseChartComponent {
9561 constructor() {
9562 super(...arguments);
9563 this.showGridLines = true;
9564 this.legend = false;
9565 this.legendTitle = 'Legend';
9566 this.legendPosition = LegendPosition.Right;
9567 this.xAxis = true;
9568 this.yAxis = true;
9569 this.trimXAxisTicks = true;
9570 this.trimYAxisTicks = true;
9571 this.rotateXAxisTicks = true;
9572 this.maxXAxisTickLength = 16;
9573 this.maxYAxisTickLength = 16;
9574 this.roundDomains = false;
9575 this.maxRadius = 10;
9576 this.minRadius = 3;
9577 this.schemeType = ScaleType.Ordinal;
9578 this.tooltipDisabled = false;
9579 this.activate = new EventEmitter();
9580 this.deactivate = new EventEmitter();
9581 this.scaleType = ScaleType.Linear;
9582 this.margin = [10, 20, 10, 20];
9583 this.bubblePadding = [0, 0, 0, 0];
9584 this.xAxisHeight = 0;
9585 this.yAxisWidth = 0;
9586 this.activeEntries = [];
9587 }
9588 update() {
9589 super.update();
9590 this.dims = calculateViewDimensions({
9591 width: this.width,
9592 height: this.height,
9593 margins: this.margin,
9594 showXAxis: this.xAxis,
9595 showYAxis: this.yAxis,
9596 xAxisHeight: this.xAxisHeight,
9597 yAxisWidth: this.yAxisWidth,
9598 showXLabel: this.showXAxisLabel,
9599 showYLabel: this.showYAxisLabel,
9600 showLegend: this.legend,
9601 legendType: this.schemeType,
9602 legendPosition: this.legendPosition
9603 });
9604 this.seriesDomain = this.results.map(d => d.name);
9605 this.rDomain = this.getRDomain();
9606 this.xDomain = this.getXDomain();
9607 this.yDomain = this.getYDomain();
9608 this.transform = `translate(${this.dims.xOffset},${this.margin[0]})`;
9609 const colorDomain = this.schemeType === ScaleType.Ordinal ? this.seriesDomain : this.rDomain;
9610 this.colors = new ColorHelper(this.scheme, this.schemeType, colorDomain, this.customColors);
9611 this.data = this.results;
9612 this.minRadius = Math.max(this.minRadius, 1);
9613 this.maxRadius = Math.max(this.maxRadius, 1);
9614 this.rScale = this.getRScale(this.rDomain, [this.minRadius, this.maxRadius]);
9615 this.bubblePadding = [0, 0, 0, 0];
9616 this.setScales();
9617 this.bubblePadding = this.getBubblePadding();
9618 this.setScales();
9619 this.legendOptions = this.getLegendOptions();
9620 this.clipPathId = 'clip' + id().toString();
9621 this.clipPath = `url(#${this.clipPathId})`;
9622 }
9623 hideCircles() {
9624 this.deactivateAll();
9625 }
9626 onClick(data, series) {
9627 if (series) {
9628 data.series = series.name;
9629 }
9630 this.select.emit(data);
9631 }
9632 getBubblePadding() {
9633 let yMin = 0;
9634 let xMin = 0;
9635 let yMax = this.dims.height;
9636 let xMax = this.dims.width;
9637 for (const s of this.data) {
9638 for (const d of s.series) {
9639 const r = this.rScale(d.r);
9640 const cx = this.xScaleType === ScaleType.Linear ? this.xScale(Number(d.x)) : this.xScale(d.x);
9641 const cy = this.yScaleType === ScaleType.Linear ? this.yScale(Number(d.y)) : this.yScale(d.y);
9642 xMin = Math.max(r - cx, xMin);
9643 yMin = Math.max(r - cy, yMin);
9644 yMax = Math.max(cy + r, yMax);
9645 xMax = Math.max(cx + r, xMax);
9646 }
9647 }
9648 xMax = Math.max(xMax - this.dims.width, 0);
9649 yMax = Math.max(yMax - this.dims.height, 0);
9650 return [yMin, xMax, yMax, xMin];
9651 }
9652 setScales() {
9653 let width = this.dims.width;
9654 if (this.xScaleMin === undefined && this.xScaleMax === undefined) {
9655 width = width - this.bubblePadding[1];
9656 }
9657 let height = this.dims.height;
9658 if (this.yScaleMin === undefined && this.yScaleMax === undefined) {
9659 height = height - this.bubblePadding[2];
9660 }
9661 this.xScale = this.getXScale(this.xDomain, width);
9662 this.yScale = this.getYScale(this.yDomain, height);
9663 }
9664 getYScale(domain, height) {
9665 return getScale(domain, [height, this.bubblePadding[0]], this.yScaleType, this.roundDomains);
9666 }
9667 getXScale(domain, width) {
9668 return getScale(domain, [this.bubblePadding[3], width], this.xScaleType, this.roundDomains);
9669 }
9670 getRScale(domain, range) {
9671 const scale = scaleLinear().range(range).domain(domain);
9672 return this.roundDomains ? scale.nice() : scale;
9673 }
9674 getLegendOptions() {
9675 const opts = {
9676 scaleType: this.schemeType,
9677 colors: undefined,
9678 domain: [],
9679 position: this.legendPosition,
9680 title: undefined
9681 };
9682 if (opts.scaleType === ScaleType.Ordinal) {
9683 opts.domain = this.seriesDomain;
9684 opts.colors = this.colors;
9685 opts.title = this.legendTitle;
9686 }
9687 else {
9688 opts.domain = this.rDomain;
9689 opts.colors = this.colors.scale;
9690 }
9691 return opts;
9692 }
9693 getXDomain() {
9694 const values = [];
9695 for (const results of this.results) {
9696 for (const d of results.series) {
9697 if (!values.includes(d.x)) {
9698 values.push(d.x);
9699 }
9700 }
9701 }
9702 this.xScaleType = getScaleType(values);
9703 return getDomain(values, this.xScaleType, this.autoScale, this.xScaleMin, this.xScaleMax);
9704 }
9705 getYDomain() {
9706 const values = [];
9707 for (const results of this.results) {
9708 for (const d of results.series) {
9709 if (!values.includes(d.y)) {
9710 values.push(d.y);
9711 }
9712 }
9713 }
9714 this.yScaleType = getScaleType(values);
9715 return getDomain(values, this.yScaleType, this.autoScale, this.yScaleMin, this.yScaleMax);
9716 }
9717 getRDomain() {
9718 let min = Infinity;
9719 let max = -Infinity;
9720 for (const results of this.results) {
9721 for (const d of results.series) {
9722 const value = Number(d.r) || 1;
9723 min = Math.min(min, value);
9724 max = Math.max(max, value);
9725 }
9726 }
9727 return [min, max];
9728 }
9729 updateYAxisWidth({ width }) {
9730 this.yAxisWidth = width;
9731 this.update();
9732 }
9733 updateXAxisHeight({ height }) {
9734 this.xAxisHeight = height;
9735 this.update();
9736 }
9737 onActivate(item) {
9738 const idx = this.activeEntries.findIndex(d => {
9739 return d.name === item.name;
9740 });
9741 if (idx > -1) {
9742 return;
9743 }
9744 this.activeEntries = [item, ...this.activeEntries];
9745 this.activate.emit({ value: item, entries: this.activeEntries });
9746 }
9747 onDeactivate(item) {
9748 const idx = this.activeEntries.findIndex(d => {
9749 return d.name === item.name;
9750 });
9751 this.activeEntries.splice(idx, 1);
9752 this.activeEntries = [...this.activeEntries];
9753 this.deactivate.emit({ value: item, entries: this.activeEntries });
9754 }
9755 deactivateAll() {
9756 this.activeEntries = [...this.activeEntries];
9757 for (const entry of this.activeEntries) {
9758 this.deactivate.emit({ value: entry, entries: [] });
9759 }
9760 this.activeEntries = [];
9761 }
9762 trackBy(index, item) {
9763 return `${item.name}`;
9764 }
9765}
9766BubbleChartComponent.decorators = [
9767 { type: Component, args: [{
9768 selector: 'ngx-charts-bubble-chart',
9769 template: `
9770 <ngx-charts-chart
9771 [view]="[width, height]"
9772 [showLegend]="legend"
9773 [activeEntries]="activeEntries"
9774 [legendOptions]="legendOptions"
9775 [animations]="animations"
9776 (legendLabelClick)="onClick($event)"
9777 (legendLabelActivate)="onActivate($event)"
9778 (legendLabelDeactivate)="onDeactivate($event)"
9779 >
9780 <svg:defs>
9781 <svg:clipPath [attr.id]="clipPathId">
9782 <svg:rect
9783 [attr.width]="dims.width + 10"
9784 [attr.height]="dims.height + 10"
9785 [attr.transform]="'translate(-5, -5)'"
9786 />
9787 </svg:clipPath>
9788 </svg:defs>
9789 <svg:g [attr.transform]="transform" class="bubble-chart chart">
9790 <svg:g
9791 ngx-charts-x-axis
9792 *ngIf="xAxis"
9793 [showGridLines]="showGridLines"
9794 [dims]="dims"
9795 [xScale]="xScale"
9796 [showLabel]="showXAxisLabel"
9797 [labelText]="xAxisLabel"
9798 [trimTicks]="trimXAxisTicks"
9799 [rotateTicks]="rotateXAxisTicks"
9800 [maxTickLength]="maxXAxisTickLength"
9801 [tickFormatting]="xAxisTickFormatting"
9802 [ticks]="xAxisTicks"
9803 (dimensionsChanged)="updateXAxisHeight($event)"
9804 />
9805 <svg:g
9806 ngx-charts-y-axis
9807 *ngIf="yAxis"
9808 [showGridLines]="showGridLines"
9809 [yScale]="yScale"
9810 [dims]="dims"
9811 [showLabel]="showYAxisLabel"
9812 [labelText]="yAxisLabel"
9813 [trimTicks]="trimYAxisTicks"
9814 [maxTickLength]="maxYAxisTickLength"
9815 [tickFormatting]="yAxisTickFormatting"
9816 [ticks]="yAxisTicks"
9817 (dimensionsChanged)="updateYAxisWidth($event)"
9818 />
9819 <svg:rect
9820 class="bubble-chart-area"
9821 x="0"
9822 y="0"
9823 [attr.width]="dims.width"
9824 [attr.height]="dims.height"
9825 style="fill: rgb(255, 0, 0); opacity: 0; cursor: 'auto';"
9826 (mouseenter)="deactivateAll()"
9827 />
9828 <svg:g [attr.clip-path]="clipPath">
9829 <svg:g *ngFor="let series of data; trackBy: trackBy" [@animationState]="'active'">
9830 <svg:g
9831 ngx-charts-bubble-series
9832 [xScale]="xScale"
9833 [yScale]="yScale"
9834 [rScale]="rScale"
9835 [xScaleType]="xScaleType"
9836 [yScaleType]="yScaleType"
9837 [xAxisLabel]="xAxisLabel"
9838 [yAxisLabel]="yAxisLabel"
9839 [colors]="colors"
9840 [data]="series"
9841 [activeEntries]="activeEntries"
9842 [tooltipDisabled]="tooltipDisabled"
9843 [tooltipTemplate]="tooltipTemplate"
9844 (select)="onClick($event, series)"
9845 (activate)="onActivate($event)"
9846 (deactivate)="onDeactivate($event)"
9847 />
9848 </svg:g>
9849 </svg:g>
9850 </svg:g>
9851 </ngx-charts-chart>
9852 `,
9853 changeDetection: ChangeDetectionStrategy.OnPush,
9854 encapsulation: ViewEncapsulation.None,
9855 animations: [
9856 trigger('animationState', [
9857 transition(':leave', [
9858 style({
9859 opacity: 1
9860 }),
9861 animate(500, style({
9862 opacity: 0
9863 }))
9864 ])
9865 ])
9866 ],
9867 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
9868 },] }
9869];
9870BubbleChartComponent.propDecorators = {
9871 showGridLines: [{ type: Input }],
9872 legend: [{ type: Input }],
9873 legendTitle: [{ type: Input }],
9874 legendPosition: [{ type: Input }],
9875 xAxis: [{ type: Input }],
9876 yAxis: [{ type: Input }],
9877 showXAxisLabel: [{ type: Input }],
9878 showYAxisLabel: [{ type: Input }],
9879 xAxisLabel: [{ type: Input }],
9880 yAxisLabel: [{ type: Input }],
9881 trimXAxisTicks: [{ type: Input }],
9882 trimYAxisTicks: [{ type: Input }],
9883 rotateXAxisTicks: [{ type: Input }],
9884 maxXAxisTickLength: [{ type: Input }],
9885 maxYAxisTickLength: [{ type: Input }],
9886 xAxisTickFormatting: [{ type: Input }],
9887 yAxisTickFormatting: [{ type: Input }],
9888 xAxisTicks: [{ type: Input }],
9889 yAxisTicks: [{ type: Input }],
9890 roundDomains: [{ type: Input }],
9891 maxRadius: [{ type: Input }],
9892 minRadius: [{ type: Input }],
9893 autoScale: [{ type: Input }],
9894 schemeType: [{ type: Input }],
9895 tooltipDisabled: [{ type: Input }],
9896 xScaleMin: [{ type: Input }],
9897 xScaleMax: [{ type: Input }],
9898 yScaleMin: [{ type: Input }],
9899 yScaleMax: [{ type: Input }],
9900 activate: [{ type: Output }],
9901 deactivate: [{ type: Output }],
9902 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
9903 hideCircles: [{ type: HostListener, args: ['mouseleave',] }]
9904};
9905
9906class BubbleSeriesComponent {
9907 constructor() {
9908 this.tooltipDisabled = false;
9909 this.select = new EventEmitter();
9910 this.activate = new EventEmitter();
9911 this.deactivate = new EventEmitter();
9912 this.placementTypes = PlacementTypes;
9913 this.styleTypes = StyleTypes;
9914 }
9915 ngOnChanges(changes) {
9916 this.update();
9917 }
9918 update() {
9919 this.circles = this.getCircles();
9920 }
9921 getCircles() {
9922 const seriesName = this.data.name;
9923 return this.data.series
9924 .map((d, i) => {
9925 if (typeof d.y !== 'undefined' && typeof d.x !== 'undefined') {
9926 const y = d.y;
9927 const x = d.x;
9928 const r = d.r;
9929 const radius = this.rScale(r || 1);
9930 const tooltipLabel = formatLabel(d.name);
9931 const cx = this.xScaleType === ScaleType.Linear ? this.xScale(Number(x)) : this.xScale(x);
9932 const cy = this.yScaleType === ScaleType.Linear ? this.yScale(Number(y)) : this.yScale(y);
9933 const color = this.colors.scaleType === ScaleType.Linear ? this.colors.getColor(r) : this.colors.getColor(seriesName);
9934 const isActive = !this.activeEntries.length ? true : this.isActive({ name: seriesName });
9935 const opacity = isActive ? 1 : 0.3;
9936 const data = Object.assign({}, d, {
9937 series: seriesName,
9938 name: d.name,
9939 value: d.y,
9940 x: d.x,
9941 radius: d.r
9942 });
9943 return {
9944 data,
9945 x,
9946 y,
9947 r,
9948 classNames: [`circle-data-${i}`],
9949 value: y,
9950 label: x,
9951 cx,
9952 cy,
9953 radius,
9954 tooltipLabel,
9955 color,
9956 opacity,
9957 seriesName,
9958 isActive,
9959 transform: `translate(${cx},${cy})`
9960 };
9961 }
9962 })
9963 .filter(circle => circle !== undefined);
9964 }
9965 getTooltipText(circle) {
9966 const hasRadius = typeof circle.r !== 'undefined';
9967 const hasTooltipLabel = circle.tooltipLabel && circle.tooltipLabel.length;
9968 const hasSeriesName = circle.seriesName && circle.seriesName.length;
9969 const radiusValue = hasRadius ? formatLabel(circle.r) : '';
9970 const xAxisLabel = this.xAxisLabel && this.xAxisLabel !== '' ? `${this.xAxisLabel}:` : '';
9971 const yAxisLabel = this.yAxisLabel && this.yAxisLabel !== '' ? `${this.yAxisLabel}:` : '';
9972 const x = formatLabel(circle.x);
9973 const y = formatLabel(circle.y);
9974 const name = hasSeriesName && hasTooltipLabel
9975 ? `${circle.seriesName}${circle.tooltipLabel}`
9976 : circle.seriesName + circle.tooltipLabel;
9977 const tooltipTitle = hasSeriesName || hasTooltipLabel ? `<span class="tooltip-label">${escapeLabel(name)}</span>` : '';
9978 return `
9979 ${tooltipTitle}
9980 <span class="tooltip-label">
9981 <label>${escapeLabel(xAxisLabel)}</label> ${escapeLabel(x)}<br />
9982 <label>${escapeLabel(yAxisLabel)}</label> ${escapeLabel(y)}
9983 </span>
9984 <span class="tooltip-val">
9985 ${escapeLabel(radiusValue)}
9986 </span>
9987 `;
9988 }
9989 onClick(data) {
9990 this.select.emit(data);
9991 }
9992 isActive(entry) {
9993 if (!this.activeEntries)
9994 return false;
9995 const item = this.activeEntries.find(d => {
9996 return entry.name === d.name;
9997 });
9998 return item !== undefined;
9999 }
10000 isVisible(circle) {
10001 if (this.activeEntries.length > 0) {
10002 return this.isActive({ name: circle.seriesName });
10003 }
10004 return circle.opacity !== 0;
10005 }
10006 activateCircle(circle) {
10007 circle.barVisible = true;
10008 this.activate.emit({ name: this.data.name });
10009 }
10010 deactivateCircle(circle) {
10011 circle.barVisible = false;
10012 this.deactivate.emit({ name: this.data.name });
10013 }
10014 trackBy(index, circle) {
10015 return `${circle.data.series} ${circle.data.name}`;
10016 }
10017}
10018BubbleSeriesComponent.decorators = [
10019 { type: Component, args: [{
10020 selector: 'g[ngx-charts-bubble-series]',
10021 template: `
10022 <svg:g *ngFor="let circle of circles; trackBy: trackBy">
10023 <svg:g [attr.transform]="circle.transform">
10024 <svg:g
10025 ngx-charts-circle
10026 [@animationState]="'active'"
10027 class="circle"
10028 [cx]="0"
10029 [cy]="0"
10030 [r]="circle.radius"
10031 [fill]="circle.color"
10032 [style.opacity]="circle.opacity"
10033 [class.active]="circle.isActive"
10034 [pointerEvents]="'all'"
10035 [data]="circle.value"
10036 [classNames]="circle.classNames"
10037 (select)="onClick(circle.data)"
10038 (activate)="activateCircle(circle)"
10039 (deactivate)="deactivateCircle(circle)"
10040 ngx-tooltip
10041 [tooltipDisabled]="tooltipDisabled"
10042 [tooltipPlacement]="placementTypes.Top"
10043 [tooltipType]="styleTypes.tooltip"
10044 [tooltipTitle]="tooltipTemplate ? undefined : getTooltipText(circle)"
10045 [tooltipTemplate]="tooltipTemplate"
10046 [tooltipContext]="circle.data"
10047 />
10048 </svg:g>
10049 </svg:g>
10050 `,
10051 changeDetection: ChangeDetectionStrategy.OnPush,
10052 animations: [
10053 trigger('animationState', [
10054 transition(':enter', [
10055 style({
10056 opacity: 0,
10057 transform: 'scale(0)'
10058 }),
10059 animate(250, style({ opacity: 1, transform: 'scale(1)' }))
10060 ])
10061 ])
10062 ]
10063 },] }
10064];
10065BubbleSeriesComponent.propDecorators = {
10066 data: [{ type: Input }],
10067 xScale: [{ type: Input }],
10068 yScale: [{ type: Input }],
10069 rScale: [{ type: Input }],
10070 xScaleType: [{ type: Input }],
10071 yScaleType: [{ type: Input }],
10072 colors: [{ type: Input }],
10073 visibleValue: [{ type: Input }],
10074 activeEntries: [{ type: Input }],
10075 xAxisLabel: [{ type: Input }],
10076 yAxisLabel: [{ type: Input }],
10077 tooltipDisabled: [{ type: Input }],
10078 tooltipTemplate: [{ type: Input }],
10079 select: [{ type: Output }],
10080 activate: [{ type: Output }],
10081 deactivate: [{ type: Output }]
10082};
10083
10084class BubbleChartModule {
10085}
10086BubbleChartModule.decorators = [
10087 { type: NgModule, args: [{
10088 imports: [ChartCommonModule],
10089 declarations: [BubbleChartComponent, BubbleSeriesComponent],
10090 exports: [BubbleChartComponent, BubbleSeriesComponent]
10091 },] }
10092];
10093
10094class HeatMapCellComponent {
10095 constructor(element) {
10096 this.gradient = false;
10097 this.animations = true;
10098 this.select = new EventEmitter();
10099 this.activate = new EventEmitter();
10100 this.deactivate = new EventEmitter();
10101 this.barOrientation = BarOrientation;
10102 this.element = element.nativeElement;
10103 }
10104 ngOnChanges(changes) {
10105 this.transform = `translate(${this.x} , ${this.y})`;
10106 this.startOpacity = 0.3;
10107 this.gradientId = 'grad' + id().toString();
10108 this.gradientUrl = `url(#${this.gradientId})`;
10109 this.gradientStops = this.getGradientStops();
10110 if (this.animations) {
10111 this.loadAnimation();
10112 }
10113 }
10114 getGradientStops() {
10115 return [
10116 {
10117 offset: 0,
10118 color: this.fill,
10119 opacity: this.startOpacity
10120 },
10121 {
10122 offset: 100,
10123 color: this.fill,
10124 opacity: 1
10125 }
10126 ];
10127 }
10128 loadAnimation() {
10129 const node = select(this.element).select('.cell');
10130 node.attr('opacity', 0);
10131 this.animateToCurrentForm();
10132 }
10133 animateToCurrentForm() {
10134 const node = select(this.element).select('.cell');
10135 node.transition().duration(750).attr('opacity', 1);
10136 }
10137 onClick() {
10138 this.select.emit(this.data);
10139 }
10140 onMouseEnter() {
10141 this.activate.emit(this.data);
10142 }
10143 onMouseLeave() {
10144 this.deactivate.emit(this.data);
10145 }
10146}
10147HeatMapCellComponent.decorators = [
10148 { type: Component, args: [{
10149 selector: 'g[ngx-charts-heat-map-cell]',
10150 template: `
10151 <svg:g [attr.transform]="transform" class="cell">
10152 <defs *ngIf="gradient">
10153 <svg:g
10154 ngx-charts-svg-linear-gradient
10155 [orientation]="barOrientation.Vertical"
10156 [name]="gradientId"
10157 [stops]="gradientStops"
10158 />
10159 </defs>
10160 <svg:rect
10161 [attr.fill]="gradient ? gradientUrl : fill"
10162 rx="3"
10163 [attr.width]="width"
10164 [attr.height]="height"
10165 class="cell"
10166 (click)="onClick()"
10167 />
10168 </svg:g>
10169 `,
10170 changeDetection: ChangeDetectionStrategy.OnPush
10171 },] }
10172];
10173HeatMapCellComponent.ctorParameters = () => [
10174 { type: ElementRef }
10175];
10176HeatMapCellComponent.propDecorators = {
10177 fill: [{ type: Input }],
10178 x: [{ type: Input }],
10179 y: [{ type: Input }],
10180 width: [{ type: Input }],
10181 height: [{ type: Input }],
10182 data: [{ type: Input }],
10183 gradient: [{ type: Input }],
10184 animations: [{ type: Input }],
10185 select: [{ type: Output }],
10186 activate: [{ type: Output }],
10187 deactivate: [{ type: Output }],
10188 onMouseEnter: [{ type: HostListener, args: ['mouseenter',] }],
10189 onMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
10190};
10191
10192class HeatCellSeriesComponent {
10193 constructor() {
10194 this.tooltipDisabled = false;
10195 this.animations = true;
10196 this.select = new EventEmitter();
10197 this.activate = new EventEmitter();
10198 this.deactivate = new EventEmitter();
10199 this.placementTypes = PlacementTypes;
10200 this.styleTypes = StyleTypes;
10201 }
10202 ngOnInit() {
10203 if (!this.tooltipText) {
10204 this.tooltipText = this.getTooltipText;
10205 }
10206 }
10207 ngOnChanges(changes) {
10208 this.update();
10209 }
10210 update() {
10211 this.cells = this.getCells();
10212 }
10213 getCells() {
10214 const cells = [];
10215 this.data.map(row => {
10216 row.series.map(cell => {
10217 const value = cell.value;
10218 cell.series = row.name;
10219 cells.push({
10220 row,
10221 cell,
10222 x: this.xScale(row.name),
10223 y: this.yScale(cell.name),
10224 width: this.xScale.bandwidth(),
10225 height: this.yScale.bandwidth(),
10226 fill: this.colors.getColor(value),
10227 data: value,
10228 label: formatLabel(cell.name),
10229 series: row.name
10230 });
10231 });
10232 });
10233 return cells;
10234 }
10235 getTooltipText({ label, data, series }) {
10236 return `
10237 <span class="tooltip-label">${escapeLabel(series)}${escapeLabel(label)}</span>
10238 <span class="tooltip-val">${data.toLocaleString()}</span>
10239 `;
10240 }
10241 trackBy(index, item) {
10242 return item.label;
10243 }
10244 onClick(data) {
10245 this.select.emit(data);
10246 }
10247}
10248HeatCellSeriesComponent.decorators = [
10249 { type: Component, args: [{
10250 selector: 'g[ngx-charts-heat-map-cell-series]',
10251 template: `
10252 <svg:g
10253 ngx-charts-heat-map-cell
10254 *ngFor="let c of cells; trackBy: trackBy"
10255 [x]="c.x"
10256 [y]="c.y"
10257 [width]="c.width"
10258 [height]="c.height"
10259 [fill]="c.fill"
10260 [data]="c.data"
10261 (select)="onClick(c.cell)"
10262 (activate)="activate.emit(c.cell)"
10263 (deactivate)="deactivate.emit(c.cell)"
10264 [gradient]="gradient"
10265 [animations]="animations"
10266 ngx-tooltip
10267 [tooltipDisabled]="tooltipDisabled"
10268 [tooltipPlacement]="placementTypes.Top"
10269 [tooltipType]="styleTypes.tooltip"
10270 [tooltipTitle]="tooltipTemplate ? undefined : tooltipText(c)"
10271 [tooltipTemplate]="tooltipTemplate"
10272 [tooltipContext]="{ series: c.series, name: c.label, value: c.data }"
10273 ></svg:g>
10274 `,
10275 changeDetection: ChangeDetectionStrategy.OnPush
10276 },] }
10277];
10278HeatCellSeriesComponent.propDecorators = {
10279 data: [{ type: Input }],
10280 colors: [{ type: Input }],
10281 xScale: [{ type: Input }],
10282 yScale: [{ type: Input }],
10283 gradient: [{ type: Input }],
10284 tooltipDisabled: [{ type: Input }],
10285 tooltipText: [{ type: Input }],
10286 tooltipTemplate: [{ type: Input }],
10287 animations: [{ type: Input }],
10288 select: [{ type: Output }],
10289 activate: [{ type: Output }],
10290 deactivate: [{ type: Output }]
10291};
10292
10293class HeatMapComponent extends BaseChartComponent {
10294 constructor() {
10295 super(...arguments);
10296 this.legendTitle = 'Legend';
10297 this.legendPosition = LegendPosition.Right;
10298 this.innerPadding = 8;
10299 this.trimXAxisTicks = true;
10300 this.trimYAxisTicks = true;
10301 this.rotateXAxisTicks = true;
10302 this.maxXAxisTickLength = 16;
10303 this.maxYAxisTickLength = 16;
10304 this.tooltipDisabled = false;
10305 this.activeEntries = [];
10306 this.activate = new EventEmitter();
10307 this.deactivate = new EventEmitter();
10308 this.margin = [10, 20, 10, 20];
10309 this.xAxisHeight = 0;
10310 this.yAxisWidth = 0;
10311 this.scaleType = ScaleType.Linear;
10312 }
10313 update() {
10314 super.update();
10315 this.formatDates();
10316 this.xDomain = this.getXDomain();
10317 this.yDomain = this.getYDomain();
10318 this.valueDomain = this.getValueDomain();
10319 this.scaleType = getScaleType(this.valueDomain, false);
10320 this.dims = calculateViewDimensions({
10321 width: this.width,
10322 height: this.height,
10323 margins: this.margin,
10324 showXAxis: this.xAxis,
10325 showYAxis: this.yAxis,
10326 xAxisHeight: this.xAxisHeight,
10327 yAxisWidth: this.yAxisWidth,
10328 showXLabel: this.showXAxisLabel,
10329 showYLabel: this.showYAxisLabel,
10330 showLegend: this.legend,
10331 legendType: this.scaleType,
10332 legendPosition: this.legendPosition
10333 });
10334 if (this.scaleType === ScaleType.Linear) {
10335 let min = this.min;
10336 let max = this.max;
10337 if (!this.min) {
10338 min = Math.min(0, ...this.valueDomain);
10339 }
10340 if (!this.max) {
10341 max = Math.max(...this.valueDomain);
10342 }
10343 this.valueDomain = [min, max];
10344 }
10345 this.xScale = this.getXScale();
10346 this.yScale = this.getYScale();
10347 this.setColors();
10348 this.legendOptions = this.getLegendOptions();
10349 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
10350 this.rects = this.getRects();
10351 }
10352 getXDomain() {
10353 const domain = [];
10354 for (const group of this.results) {
10355 if (!domain.includes(group.name)) {
10356 domain.push(group.name);
10357 }
10358 }
10359 return domain;
10360 }
10361 getYDomain() {
10362 const domain = [];
10363 for (const group of this.results) {
10364 for (const d of group.series) {
10365 if (!domain.includes(d.name)) {
10366 domain.push(d.name);
10367 }
10368 }
10369 }
10370 return domain;
10371 }
10372 getValueDomain() {
10373 const domain = [];
10374 for (const group of this.results) {
10375 for (const d of group.series) {
10376 if (!domain.includes(d.value)) {
10377 domain.push(d.value);
10378 }
10379 }
10380 }
10381 return domain;
10382 }
10383 /**
10384 * Converts the input to gap paddingInner in fraction
10385 * Supports the following inputs:
10386 * Numbers: 8
10387 * Strings: "8", "8px", "8%"
10388 * Arrays: [8,2], "8,2", "[8,2]"
10389 * Mixed: [8,"2%"], ["8px","2%"], "8,2%", "[8,2%]"
10390 *
10391 * @memberOf HeatMapComponent
10392 */
10393 getDimension(value, index = 0, N, L) {
10394 if (typeof value === 'string') {
10395 value = value
10396 .replace('[', '')
10397 .replace(']', '')
10398 .replace('px', '')
10399 // tslint:disable-next-line: quotemark
10400 .replace("'", '');
10401 if (value.includes(',')) {
10402 value = value.split(',');
10403 }
10404 }
10405 if (Array.isArray(value) && typeof index === 'number') {
10406 return this.getDimension(value[index], null, N, L);
10407 }
10408 if (typeof value === 'string' && value.includes('%')) {
10409 return +value.replace('%', '') / 100;
10410 }
10411 return N / (L / +value + 1);
10412 }
10413 getXScale() {
10414 const f = this.getDimension(this.innerPadding, 0, this.xDomain.length, this.dims.width);
10415 return scaleBand().rangeRound([0, this.dims.width]).domain(this.xDomain).paddingInner(f);
10416 }
10417 getYScale() {
10418 const f = this.getDimension(this.innerPadding, 1, this.yDomain.length, this.dims.height);
10419 return scaleBand().rangeRound([this.dims.height, 0]).domain(this.yDomain).paddingInner(f);
10420 }
10421 getRects() {
10422 const rects = [];
10423 this.xDomain.map(xVal => {
10424 this.yDomain.map(yVal => {
10425 rects.push({
10426 x: this.xScale(xVal),
10427 y: this.yScale(yVal),
10428 rx: 3,
10429 width: this.xScale.bandwidth(),
10430 height: this.yScale.bandwidth(),
10431 fill: 'rgba(200,200,200,0.03)'
10432 });
10433 });
10434 });
10435 return rects;
10436 }
10437 onClick(data) {
10438 this.select.emit(data);
10439 }
10440 setColors() {
10441 this.colors = new ColorHelper(this.scheme, this.scaleType, this.valueDomain);
10442 }
10443 getLegendOptions() {
10444 return {
10445 scaleType: this.scaleType,
10446 domain: this.valueDomain,
10447 colors: this.scaleType === ScaleType.Ordinal ? this.colors : this.colors.scale,
10448 title: this.scaleType === ScaleType.Ordinal ? this.legendTitle : undefined,
10449 position: this.legendPosition
10450 };
10451 }
10452 updateYAxisWidth({ width }) {
10453 this.yAxisWidth = width;
10454 this.update();
10455 }
10456 updateXAxisHeight({ height }) {
10457 this.xAxisHeight = height;
10458 this.update();
10459 }
10460 onActivate(event, group, fromLegend = false) {
10461 const item = Object.assign({}, event);
10462 if (group) {
10463 item.series = group.name;
10464 }
10465 const items = this.results
10466 .map(g => g.series)
10467 .flat()
10468 .filter(i => {
10469 if (fromLegend) {
10470 return i.label === item.name;
10471 }
10472 else {
10473 return i.name === item.name && i.series === item.series;
10474 }
10475 });
10476 this.activeEntries = [...items];
10477 this.activate.emit({ value: item, entries: this.activeEntries });
10478 }
10479 onDeactivate(event, group, fromLegend = false) {
10480 const item = Object.assign({}, event);
10481 if (group) {
10482 item.series = group.name;
10483 }
10484 this.activeEntries = this.activeEntries.filter(i => {
10485 if (fromLegend) {
10486 return i.label !== item.name;
10487 }
10488 else {
10489 return !(i.name === item.name && i.series === item.series);
10490 }
10491 });
10492 this.deactivate.emit({ value: item, entries: this.activeEntries });
10493 }
10494}
10495HeatMapComponent.decorators = [
10496 { type: Component, args: [{
10497 selector: 'ngx-charts-heat-map',
10498 template: `
10499 <ngx-charts-chart
10500 [view]="[width, height]"
10501 [showLegend]="legend"
10502 [animations]="animations"
10503 [legendOptions]="legendOptions"
10504 (legendLabelClick)="onClick($event)"
10505 >
10506 <svg:g [attr.transform]="transform" class="heat-map chart">
10507 <svg:g
10508 ngx-charts-x-axis
10509 *ngIf="xAxis"
10510 [xScale]="xScale"
10511 [dims]="dims"
10512 [showLabel]="showXAxisLabel"
10513 [labelText]="xAxisLabel"
10514 [trimTicks]="trimXAxisTicks"
10515 [rotateTicks]="rotateXAxisTicks"
10516 [maxTickLength]="maxXAxisTickLength"
10517 [tickFormatting]="xAxisTickFormatting"
10518 [ticks]="xAxisTicks"
10519 (dimensionsChanged)="updateXAxisHeight($event)"
10520 ></svg:g>
10521 <svg:g
10522 ngx-charts-y-axis
10523 *ngIf="yAxis"
10524 [yScale]="yScale"
10525 [dims]="dims"
10526 [showLabel]="showYAxisLabel"
10527 [labelText]="yAxisLabel"
10528 [trimTicks]="trimYAxisTicks"
10529 [maxTickLength]="maxYAxisTickLength"
10530 [tickFormatting]="yAxisTickFormatting"
10531 [ticks]="yAxisTicks"
10532 (dimensionsChanged)="updateYAxisWidth($event)"
10533 ></svg:g>
10534 <svg:rect
10535 *ngFor="let rect of rects"
10536 [attr.x]="rect.x"
10537 [attr.y]="rect.y"
10538 [attr.rx]="rect.rx"
10539 [attr.width]="rect.width"
10540 [attr.height]="rect.height"
10541 [attr.fill]="rect.fill"
10542 />
10543 <svg:g
10544 ngx-charts-heat-map-cell-series
10545 [xScale]="xScale"
10546 [yScale]="yScale"
10547 [colors]="colors"
10548 [data]="results"
10549 [gradient]="gradient"
10550 [animations]="animations"
10551 [tooltipDisabled]="tooltipDisabled"
10552 [tooltipTemplate]="tooltipTemplate"
10553 [tooltipText]="tooltipText"
10554 (select)="onClick($event)"
10555 (activate)="onActivate($event, undefined)"
10556 (deactivate)="onDeactivate($event, undefined)"
10557 />
10558 </svg:g>
10559 </ngx-charts-chart>
10560 `,
10561 changeDetection: ChangeDetectionStrategy.OnPush,
10562 encapsulation: ViewEncapsulation.None,
10563 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
10564 },] }
10565];
10566HeatMapComponent.propDecorators = {
10567 legend: [{ type: Input }],
10568 legendTitle: [{ type: Input }],
10569 legendPosition: [{ type: Input }],
10570 xAxis: [{ type: Input }],
10571 yAxis: [{ type: Input }],
10572 showXAxisLabel: [{ type: Input }],
10573 showYAxisLabel: [{ type: Input }],
10574 xAxisLabel: [{ type: Input }],
10575 yAxisLabel: [{ type: Input }],
10576 gradient: [{ type: Input }],
10577 innerPadding: [{ type: Input }],
10578 trimXAxisTicks: [{ type: Input }],
10579 trimYAxisTicks: [{ type: Input }],
10580 rotateXAxisTicks: [{ type: Input }],
10581 maxXAxisTickLength: [{ type: Input }],
10582 maxYAxisTickLength: [{ type: Input }],
10583 xAxisTickFormatting: [{ type: Input }],
10584 yAxisTickFormatting: [{ type: Input }],
10585 xAxisTicks: [{ type: Input }],
10586 yAxisTicks: [{ type: Input }],
10587 tooltipDisabled: [{ type: Input }],
10588 tooltipText: [{ type: Input }],
10589 min: [{ type: Input }],
10590 max: [{ type: Input }],
10591 activeEntries: [{ type: Input }],
10592 activate: [{ type: Output }],
10593 deactivate: [{ type: Output }],
10594 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
10595};
10596
10597class HeatMapModule {
10598}
10599HeatMapModule.decorators = [
10600 { type: NgModule, args: [{
10601 imports: [ChartCommonModule],
10602 declarations: [HeatMapCellComponent, HeatCellSeriesComponent, HeatMapComponent],
10603 exports: [HeatMapCellComponent, HeatCellSeriesComponent, HeatMapComponent]
10604 },] }
10605];
10606
10607class LineComponent {
10608 constructor(element) {
10609 this.element = element;
10610 this.fill = 'none';
10611 this.animations = true;
10612 // @Output() select = new EventEmitter();
10613 this.initialized = false;
10614 }
10615 ngOnChanges(changes) {
10616 if (!this.initialized) {
10617 this.initialized = true;
10618 this.initialPath = this.path;
10619 }
10620 else {
10621 this.updatePathEl();
10622 }
10623 }
10624 updatePathEl() {
10625 const node = select(this.element.nativeElement).select('.line');
10626 if (this.animations) {
10627 node.transition().duration(750).attr('d', this.path);
10628 }
10629 else {
10630 node.attr('d', this.path);
10631 }
10632 }
10633}
10634LineComponent.decorators = [
10635 { type: Component, args: [{
10636 selector: 'g[ngx-charts-line]',
10637 template: `
10638 <svg:path
10639 [@animationState]="'active'"
10640 class="line"
10641 [attr.d]="initialPath"
10642 [attr.fill]="fill"
10643 [attr.stroke]="stroke"
10644 stroke-width="1.5px"
10645 />
10646 `,
10647 changeDetection: ChangeDetectionStrategy.OnPush,
10648 animations: [
10649 trigger('animationState', [
10650 transition(':enter', [
10651 style({
10652 strokeDasharray: 2000,
10653 strokeDashoffset: 2000
10654 }),
10655 animate(1000, style({
10656 strokeDashoffset: 0
10657 }))
10658 ])
10659 ])
10660 ]
10661 },] }
10662];
10663LineComponent.ctorParameters = () => [
10664 { type: ElementRef }
10665];
10666LineComponent.propDecorators = {
10667 path: [{ type: Input }],
10668 stroke: [{ type: Input }],
10669 data: [{ type: Input }],
10670 fill: [{ type: Input }],
10671 animations: [{ type: Input }]
10672};
10673
10674class LineChartComponent extends BaseChartComponent {
10675 constructor() {
10676 super(...arguments);
10677 this.legendTitle = 'Legend';
10678 this.legendPosition = LegendPosition.Right;
10679 this.showGridLines = true;
10680 this.curve = curveLinear;
10681 this.activeEntries = [];
10682 this.trimXAxisTicks = true;
10683 this.trimYAxisTicks = true;
10684 this.rotateXAxisTicks = true;
10685 this.maxXAxisTickLength = 16;
10686 this.maxYAxisTickLength = 16;
10687 this.roundDomains = false;
10688 this.tooltipDisabled = false;
10689 this.showRefLines = false;
10690 this.showRefLabels = true;
10691 this.activate = new EventEmitter();
10692 this.deactivate = new EventEmitter();
10693 this.margin = [10, 20, 10, 20];
10694 this.xAxisHeight = 0;
10695 this.yAxisWidth = 0;
10696 this.timelineHeight = 50;
10697 this.timelinePadding = 10;
10698 }
10699 update() {
10700 super.update();
10701 this.dims = calculateViewDimensions({
10702 width: this.width,
10703 height: this.height,
10704 margins: this.margin,
10705 showXAxis: this.xAxis,
10706 showYAxis: this.yAxis,
10707 xAxisHeight: this.xAxisHeight,
10708 yAxisWidth: this.yAxisWidth,
10709 showXLabel: this.showXAxisLabel,
10710 showYLabel: this.showYAxisLabel,
10711 showLegend: this.legend,
10712 legendType: this.schemeType,
10713 legendPosition: this.legendPosition
10714 });
10715 if (this.timeline) {
10716 this.dims.height -= this.timelineHeight + this.margin[2] + this.timelinePadding;
10717 }
10718 this.xDomain = this.getXDomain();
10719 if (this.filteredDomain) {
10720 this.xDomain = this.filteredDomain;
10721 }
10722 this.yDomain = this.getYDomain();
10723 this.seriesDomain = this.getSeriesDomain();
10724 this.xScale = this.getXScale(this.xDomain, this.dims.width);
10725 this.yScale = this.getYScale(this.yDomain, this.dims.height);
10726 this.updateTimeline();
10727 this.setColors();
10728 this.legendOptions = this.getLegendOptions();
10729 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
10730 this.clipPathId = 'clip' + id().toString();
10731 this.clipPath = `url(#${this.clipPathId})`;
10732 }
10733 updateTimeline() {
10734 if (this.timeline) {
10735 this.timelineWidth = this.dims.width;
10736 this.timelineXDomain = this.getXDomain();
10737 this.timelineXScale = this.getXScale(this.timelineXDomain, this.timelineWidth);
10738 this.timelineYScale = this.getYScale(this.yDomain, this.timelineHeight);
10739 this.timelineTransform = `translate(${this.dims.xOffset}, ${-this.margin[2]})`;
10740 }
10741 }
10742 getXDomain() {
10743 let values = getUniqueXDomainValues(this.results);
10744 this.scaleType = getScaleType(values);
10745 let domain = [];
10746 if (this.scaleType === ScaleType.Linear) {
10747 values = values.map(v => Number(v));
10748 }
10749 let min;
10750 let max;
10751 if (this.scaleType === ScaleType.Time || this.scaleType === ScaleType.Linear) {
10752 min = this.xScaleMin ? this.xScaleMin : Math.min(...values);
10753 max = this.xScaleMax ? this.xScaleMax : Math.max(...values);
10754 }
10755 if (this.scaleType === ScaleType.Time) {
10756 domain = [new Date(min), new Date(max)];
10757 this.xSet = [...values].sort((a, b) => {
10758 const aDate = a.getTime();
10759 const bDate = b.getTime();
10760 if (aDate > bDate)
10761 return 1;
10762 if (bDate > aDate)
10763 return -1;
10764 return 0;
10765 });
10766 }
10767 else if (this.scaleType === ScaleType.Linear) {
10768 domain = [min, max];
10769 // Use compare function to sort numbers numerically
10770 this.xSet = [...values].sort((a, b) => a - b);
10771 }
10772 else {
10773 domain = values;
10774 this.xSet = values;
10775 }
10776 return domain;
10777 }
10778 getYDomain() {
10779 const domain = [];
10780 for (const results of this.results) {
10781 for (const d of results.series) {
10782 if (domain.indexOf(d.value) < 0) {
10783 domain.push(d.value);
10784 }
10785 if (d.min !== undefined) {
10786 this.hasRange = true;
10787 if (domain.indexOf(d.min) < 0) {
10788 domain.push(d.min);
10789 }
10790 }
10791 if (d.max !== undefined) {
10792 this.hasRange = true;
10793 if (domain.indexOf(d.max) < 0) {
10794 domain.push(d.max);
10795 }
10796 }
10797 }
10798 }
10799 const values = [...domain];
10800 if (!this.autoScale) {
10801 values.push(0);
10802 }
10803 const min = this.yScaleMin ? this.yScaleMin : Math.min(...values);
10804 const max = this.yScaleMax ? this.yScaleMax : Math.max(...values);
10805 return [min, max];
10806 }
10807 getSeriesDomain() {
10808 return this.results.map(d => d.name);
10809 }
10810 getXScale(domain, width) {
10811 let scale;
10812 if (this.scaleType === ScaleType.Time) {
10813 scale = scaleTime().range([0, width]).domain(domain);
10814 }
10815 else if (this.scaleType === ScaleType.Linear) {
10816 scale = scaleLinear().range([0, width]).domain(domain);
10817 if (this.roundDomains) {
10818 scale = scale.nice();
10819 }
10820 }
10821 else if (this.scaleType === ScaleType.Ordinal) {
10822 scale = scalePoint().range([0, width]).padding(0.1).domain(domain);
10823 }
10824 return scale;
10825 }
10826 getYScale(domain, height) {
10827 const scale = scaleLinear().range([height, 0]).domain(domain);
10828 return this.roundDomains ? scale.nice() : scale;
10829 }
10830 updateDomain(domain) {
10831 this.filteredDomain = domain;
10832 this.xDomain = this.filteredDomain;
10833 this.xScale = this.getXScale(this.xDomain, this.dims.width);
10834 }
10835 updateHoveredVertical(item) {
10836 this.hoveredVertical = item.value;
10837 this.deactivateAll();
10838 }
10839 hideCircles() {
10840 this.hoveredVertical = null;
10841 this.deactivateAll();
10842 }
10843 onClick(data) {
10844 this.select.emit(data);
10845 }
10846 trackBy(index, item) {
10847 return `${item.name}`;
10848 }
10849 setColors() {
10850 let domain;
10851 if (this.schemeType === ScaleType.Ordinal) {
10852 domain = this.seriesDomain;
10853 }
10854 else {
10855 domain = this.yDomain;
10856 }
10857 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
10858 }
10859 getLegendOptions() {
10860 const opts = {
10861 scaleType: this.schemeType,
10862 colors: undefined,
10863 domain: [],
10864 title: undefined,
10865 position: this.legendPosition
10866 };
10867 if (opts.scaleType === ScaleType.Ordinal) {
10868 opts.domain = this.seriesDomain;
10869 opts.colors = this.colors;
10870 opts.title = this.legendTitle;
10871 }
10872 else {
10873 opts.domain = this.yDomain;
10874 opts.colors = this.colors.scale;
10875 }
10876 return opts;
10877 }
10878 updateYAxisWidth({ width }) {
10879 this.yAxisWidth = width;
10880 this.update();
10881 }
10882 updateXAxisHeight({ height }) {
10883 this.xAxisHeight = height;
10884 this.update();
10885 }
10886 onActivate(item) {
10887 this.deactivateAll();
10888 const idx = this.activeEntries.findIndex(d => {
10889 return d.name === item.name && d.value === item.value;
10890 });
10891 if (idx > -1) {
10892 return;
10893 }
10894 this.activeEntries = [item];
10895 this.activate.emit({ value: item, entries: this.activeEntries });
10896 }
10897 onDeactivate(item) {
10898 const idx = this.activeEntries.findIndex(d => {
10899 return d.name === item.name && d.value === item.value;
10900 });
10901 this.activeEntries.splice(idx, 1);
10902 this.activeEntries = [...this.activeEntries];
10903 this.deactivate.emit({ value: item, entries: this.activeEntries });
10904 }
10905 deactivateAll() {
10906 this.activeEntries = [...this.activeEntries];
10907 for (const entry of this.activeEntries) {
10908 this.deactivate.emit({ value: entry, entries: [] });
10909 }
10910 this.activeEntries = [];
10911 }
10912}
10913LineChartComponent.decorators = [
10914 { type: Component, args: [{
10915 selector: 'ngx-charts-line-chart',
10916 template: `
10917 <ngx-charts-chart
10918 [view]="[width, height]"
10919 [showLegend]="legend"
10920 [legendOptions]="legendOptions"
10921 [activeEntries]="activeEntries"
10922 [animations]="animations"
10923 (legendLabelClick)="onClick($event)"
10924 (legendLabelActivate)="onActivate($event)"
10925 (legendLabelDeactivate)="onDeactivate($event)"
10926 >
10927 <svg:defs>
10928 <svg:clipPath [attr.id]="clipPathId">
10929 <svg:rect
10930 [attr.width]="dims.width + 10"
10931 [attr.height]="dims.height + 10"
10932 [attr.transform]="'translate(-5, -5)'"
10933 />
10934 </svg:clipPath>
10935 </svg:defs>
10936 <svg:g [attr.transform]="transform" class="line-chart chart">
10937 <svg:g
10938 ngx-charts-x-axis
10939 *ngIf="xAxis"
10940 [xScale]="xScale"
10941 [dims]="dims"
10942 [showGridLines]="showGridLines"
10943 [showLabel]="showXAxisLabel"
10944 [labelText]="xAxisLabel"
10945 [trimTicks]="trimXAxisTicks"
10946 [rotateTicks]="rotateXAxisTicks"
10947 [maxTickLength]="maxXAxisTickLength"
10948 [tickFormatting]="xAxisTickFormatting"
10949 [ticks]="xAxisTicks"
10950 (dimensionsChanged)="updateXAxisHeight($event)"
10951 ></svg:g>
10952 <svg:g
10953 ngx-charts-y-axis
10954 *ngIf="yAxis"
10955 [yScale]="yScale"
10956 [dims]="dims"
10957 [showGridLines]="showGridLines"
10958 [showLabel]="showYAxisLabel"
10959 [labelText]="yAxisLabel"
10960 [trimTicks]="trimYAxisTicks"
10961 [maxTickLength]="maxYAxisTickLength"
10962 [tickFormatting]="yAxisTickFormatting"
10963 [ticks]="yAxisTicks"
10964 [referenceLines]="referenceLines"
10965 [showRefLines]="showRefLines"
10966 [showRefLabels]="showRefLabels"
10967 (dimensionsChanged)="updateYAxisWidth($event)"
10968 ></svg:g>
10969 <svg:g [attr.clip-path]="clipPath">
10970 <svg:g *ngFor="let series of results; trackBy: trackBy" [@animationState]="'active'">
10971 <svg:g
10972 ngx-charts-line-series
10973 [xScale]="xScale"
10974 [yScale]="yScale"
10975 [colors]="colors"
10976 [data]="series"
10977 [activeEntries]="activeEntries"
10978 [scaleType]="scaleType"
10979 [curve]="curve"
10980 [rangeFillOpacity]="rangeFillOpacity"
10981 [hasRange]="hasRange"
10982 [animations]="animations"
10983 />
10984 </svg:g>
10985
10986 <svg:g *ngIf="!tooltipDisabled" (mouseleave)="hideCircles()">
10987 <svg:g
10988 ngx-charts-tooltip-area
10989 [dims]="dims"
10990 [xSet]="xSet"
10991 [xScale]="xScale"
10992 [yScale]="yScale"
10993 [results]="results"
10994 [colors]="colors"
10995 [tooltipDisabled]="tooltipDisabled"
10996 [tooltipTemplate]="seriesTooltipTemplate"
10997 (hover)="updateHoveredVertical($event)"
10998 />
10999
11000 <svg:g *ngFor="let series of results">
11001 <svg:g
11002 ngx-charts-circle-series
11003 [xScale]="xScale"
11004 [yScale]="yScale"
11005 [colors]="colors"
11006 [data]="series"
11007 [scaleType]="scaleType"
11008 [visibleValue]="hoveredVertical"
11009 [activeEntries]="activeEntries"
11010 [tooltipDisabled]="tooltipDisabled"
11011 [tooltipTemplate]="tooltipTemplate"
11012 (select)="onClick($event)"
11013 (activate)="onActivate($event)"
11014 (deactivate)="onDeactivate($event)"
11015 />
11016 </svg:g>
11017 </svg:g>
11018 </svg:g>
11019 </svg:g>
11020 <svg:g
11021 ngx-charts-timeline
11022 *ngIf="timeline && scaleType != 'ordinal'"
11023 [attr.transform]="timelineTransform"
11024 [results]="results"
11025 [view]="[timelineWidth, height]"
11026 [height]="timelineHeight"
11027 [scheme]="scheme"
11028 [customColors]="customColors"
11029 [scaleType]="scaleType"
11030 [legend]="legend"
11031 (onDomainChange)="updateDomain($event)"
11032 >
11033 <svg:g *ngFor="let series of results; trackBy: trackBy">
11034 <svg:g
11035 ngx-charts-line-series
11036 [xScale]="timelineXScale"
11037 [yScale]="timelineYScale"
11038 [colors]="colors"
11039 [data]="series"
11040 [scaleType]="scaleType"
11041 [curve]="curve"
11042 [hasRange]="hasRange"
11043 [animations]="animations"
11044 />
11045 </svg:g>
11046 </svg:g>
11047 </ngx-charts-chart>
11048 `,
11049 encapsulation: ViewEncapsulation.None,
11050 changeDetection: ChangeDetectionStrategy.OnPush,
11051 animations: [
11052 trigger('animationState', [
11053 transition(':leave', [
11054 style({
11055 opacity: 1
11056 }),
11057 animate(500, style({
11058 opacity: 0
11059 }))
11060 ])
11061 ])
11062 ],
11063 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n"]
11064 },] }
11065];
11066LineChartComponent.propDecorators = {
11067 legend: [{ type: Input }],
11068 legendTitle: [{ type: Input }],
11069 legendPosition: [{ type: Input }],
11070 xAxis: [{ type: Input }],
11071 yAxis: [{ type: Input }],
11072 showXAxisLabel: [{ type: Input }],
11073 showYAxisLabel: [{ type: Input }],
11074 xAxisLabel: [{ type: Input }],
11075 yAxisLabel: [{ type: Input }],
11076 autoScale: [{ type: Input }],
11077 timeline: [{ type: Input }],
11078 gradient: [{ type: Input }],
11079 showGridLines: [{ type: Input }],
11080 curve: [{ type: Input }],
11081 activeEntries: [{ type: Input }],
11082 schemeType: [{ type: Input }],
11083 rangeFillOpacity: [{ type: Input }],
11084 trimXAxisTicks: [{ type: Input }],
11085 trimYAxisTicks: [{ type: Input }],
11086 rotateXAxisTicks: [{ type: Input }],
11087 maxXAxisTickLength: [{ type: Input }],
11088 maxYAxisTickLength: [{ type: Input }],
11089 xAxisTickFormatting: [{ type: Input }],
11090 yAxisTickFormatting: [{ type: Input }],
11091 xAxisTicks: [{ type: Input }],
11092 yAxisTicks: [{ type: Input }],
11093 roundDomains: [{ type: Input }],
11094 tooltipDisabled: [{ type: Input }],
11095 showRefLines: [{ type: Input }],
11096 referenceLines: [{ type: Input }],
11097 showRefLabels: [{ type: Input }],
11098 xScaleMin: [{ type: Input }],
11099 xScaleMax: [{ type: Input }],
11100 yScaleMin: [{ type: Input }],
11101 yScaleMax: [{ type: Input }],
11102 activate: [{ type: Output }],
11103 deactivate: [{ type: Output }],
11104 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
11105 seriesTooltipTemplate: [{ type: ContentChild, args: ['seriesTooltipTemplate',] }],
11106 hideCircles: [{ type: HostListener, args: ['mouseleave',] }]
11107};
11108
11109class LineSeriesComponent {
11110 constructor() {
11111 this.animations = true;
11112 this.barOrientation = BarOrientation;
11113 }
11114 ngOnChanges(changes) {
11115 this.update();
11116 }
11117 update() {
11118 this.updateGradients();
11119 const data = this.sortData(this.data.series);
11120 const lineGen = this.getLineGenerator();
11121 this.path = lineGen(data) || '';
11122 const areaGen = this.getAreaGenerator();
11123 this.areaPath = areaGen(data) || '';
11124 if (this.hasRange) {
11125 const range = this.getRangeGenerator();
11126 this.outerPath = range(data) || '';
11127 }
11128 if (this.hasGradient) {
11129 this.stroke = this.gradientUrl;
11130 const values = this.data.series.map(d => d.value);
11131 const max = Math.max(...values);
11132 const min = Math.min(...values);
11133 if (max === min) {
11134 this.stroke = this.colors.getColor(max);
11135 }
11136 }
11137 else {
11138 this.stroke = this.colors.getColor(this.data.name);
11139 }
11140 }
11141 getLineGenerator() {
11142 return line()
11143 .x(d => {
11144 const label = d.name;
11145 let value;
11146 if (this.scaleType === ScaleType.Time) {
11147 value = this.xScale(label);
11148 }
11149 else if (this.scaleType === ScaleType.Linear) {
11150 value = this.xScale(Number(label));
11151 }
11152 else {
11153 value = this.xScale(label);
11154 }
11155 return value;
11156 })
11157 .y(d => this.yScale(d.value))
11158 .curve(this.curve);
11159 }
11160 getRangeGenerator() {
11161 return area()
11162 .x(d => {
11163 const label = d.name;
11164 let value;
11165 if (this.scaleType === ScaleType.Time) {
11166 value = this.xScale(label);
11167 }
11168 else if (this.scaleType === ScaleType.Linear) {
11169 value = this.xScale(Number(label));
11170 }
11171 else {
11172 value = this.xScale(label);
11173 }
11174 return value;
11175 })
11176 .y0(d => this.yScale(typeof d.min === 'number' ? d.min : d.value))
11177 .y1(d => this.yScale(typeof d.max === 'number' ? d.max : d.value))
11178 .curve(this.curve);
11179 }
11180 getAreaGenerator() {
11181 const xProperty = d => {
11182 const label = d.name;
11183 return this.xScale(label);
11184 };
11185 return area()
11186 .x(xProperty)
11187 .y0(() => this.yScale.range()[0])
11188 .y1(d => this.yScale(d.value))
11189 .curve(this.curve);
11190 }
11191 sortData(data) {
11192 if (this.scaleType === ScaleType.Linear) {
11193 data = sortLinear(data, 'name');
11194 }
11195 else if (this.scaleType === ScaleType.Time) {
11196 data = sortByTime(data, 'name');
11197 }
11198 else {
11199 data = sortByDomain(data, 'name', 'asc', this.xScale.domain());
11200 }
11201 return data;
11202 }
11203 updateGradients() {
11204 if (this.colors.scaleType === ScaleType.Linear) {
11205 this.hasGradient = true;
11206 this.gradientId = 'grad' + id().toString();
11207 this.gradientUrl = `url(#${this.gradientId})`;
11208 const values = this.data.series.map(d => d.value);
11209 const max = Math.max(...values);
11210 const min = Math.min(...values);
11211 this.gradientStops = this.colors.getLinearGradientStops(max, min);
11212 this.areaGradientStops = this.colors.getLinearGradientStops(max);
11213 }
11214 else {
11215 this.hasGradient = false;
11216 this.gradientStops = undefined;
11217 this.areaGradientStops = undefined;
11218 }
11219 }
11220 isActive(entry) {
11221 if (!this.activeEntries)
11222 return false;
11223 const item = this.activeEntries.find(d => {
11224 return entry.name === d.name;
11225 });
11226 return item !== undefined;
11227 }
11228 isInactive(entry) {
11229 if (!this.activeEntries || this.activeEntries.length === 0)
11230 return false;
11231 const item = this.activeEntries.find(d => {
11232 return entry.name === d.name;
11233 });
11234 return item === undefined;
11235 }
11236}
11237LineSeriesComponent.decorators = [
11238 { type: Component, args: [{
11239 selector: 'g[ngx-charts-line-series]',
11240 template: `
11241 <svg:g>
11242 <defs>
11243 <svg:g
11244 ngx-charts-svg-linear-gradient
11245 *ngIf="hasGradient"
11246 [orientation]="barOrientation.Vertical"
11247 [name]="gradientId"
11248 [stops]="gradientStops"
11249 />
11250 </defs>
11251 <svg:g
11252 ngx-charts-area
11253 class="line-highlight"
11254 [data]="data"
11255 [path]="areaPath"
11256 [fill]="hasGradient ? gradientUrl : colors.getColor(data.name)"
11257 [opacity]="0.25"
11258 [startOpacity]="0"
11259 [gradient]="true"
11260 [stops]="areaGradientStops"
11261 [class.active]="isActive(data)"
11262 [class.inactive]="isInactive(data)"
11263 [animations]="animations"
11264 />
11265 <svg:g
11266 ngx-charts-line
11267 class="line-series"
11268 [data]="data"
11269 [path]="path"
11270 [stroke]="stroke"
11271 [animations]="animations"
11272 [class.active]="isActive(data)"
11273 [class.inactive]="isInactive(data)"
11274 />
11275 <svg:g
11276 ngx-charts-area
11277 *ngIf="hasRange"
11278 class="line-series-range"
11279 [data]="data"
11280 [path]="outerPath"
11281 [fill]="hasGradient ? gradientUrl : colors.getColor(data.name)"
11282 [class.active]="isActive(data)"
11283 [class.inactive]="isInactive(data)"
11284 [opacity]="rangeFillOpacity"
11285 [animations]="animations"
11286 />
11287 </svg:g>
11288 `,
11289 changeDetection: ChangeDetectionStrategy.OnPush
11290 },] }
11291];
11292LineSeriesComponent.propDecorators = {
11293 data: [{ type: Input }],
11294 xScale: [{ type: Input }],
11295 yScale: [{ type: Input }],
11296 colors: [{ type: Input }],
11297 scaleType: [{ type: Input }],
11298 curve: [{ type: Input }],
11299 activeEntries: [{ type: Input }],
11300 rangeFillOpacity: [{ type: Input }],
11301 hasRange: [{ type: Input }],
11302 animations: [{ type: Input }]
11303};
11304
11305class LineChartModule {
11306}
11307LineChartModule.decorators = [
11308 { type: NgModule, args: [{
11309 imports: [ChartCommonModule],
11310 declarations: [LineComponent, LineChartComponent, LineSeriesComponent],
11311 exports: [LineComponent, LineChartComponent, LineSeriesComponent]
11312 },] }
11313];
11314
11315const twoPI = 2 * Math.PI;
11316class PolarChartComponent extends BaseChartComponent {
11317 constructor() {
11318 super(...arguments);
11319 this.legendTitle = 'Legend';
11320 this.legendPosition = LegendPosition.Right;
11321 this.showGridLines = true;
11322 this.curve = curveCardinalClosed;
11323 this.activeEntries = [];
11324 this.rangeFillOpacity = 0.15;
11325 this.trimYAxisTicks = true;
11326 this.maxYAxisTickLength = 16;
11327 this.roundDomains = false;
11328 this.tooltipDisabled = false;
11329 this.showSeriesOnHover = true;
11330 this.gradient = false;
11331 this.yAxisMinScale = 0;
11332 this.labelTrim = true;
11333 this.labelTrimSize = 10;
11334 this.activate = new EventEmitter();
11335 this.deactivate = new EventEmitter();
11336 // series: any; // ???
11337 this.margin = [10, 20, 10, 20];
11338 this.xAxisHeight = 0;
11339 this.yAxisWidth = 0;
11340 this.orientation = Orientation;
11341 }
11342 update() {
11343 super.update();
11344 this.setDims();
11345 this.setScales();
11346 this.setColors();
11347 this.legendOptions = this.getLegendOptions();
11348 this.setTicks();
11349 }
11350 setDims() {
11351 this.dims = calculateViewDimensions({
11352 width: this.width,
11353 height: this.height,
11354 margins: this.margin,
11355 showXAxis: this.xAxis,
11356 showYAxis: this.yAxis,
11357 xAxisHeight: this.xAxisHeight,
11358 yAxisWidth: this.yAxisWidth,
11359 showXLabel: this.showXAxisLabel,
11360 showYLabel: this.showYAxisLabel,
11361 showLegend: this.legend,
11362 legendType: this.schemeType,
11363 legendPosition: this.legendPosition
11364 });
11365 const halfWidth = Math.floor(this.dims.width / 2);
11366 const halfHeight = Math.floor(this.dims.height / 2);
11367 const outerRadius = (this.outerRadius = Math.min(halfHeight / 1.5, halfWidth / 1.5));
11368 const yOffset = Math.max(0, halfHeight - outerRadius);
11369 this.yAxisDims = Object.assign(Object.assign({}, this.dims), { width: halfWidth });
11370 this.transform = `translate(${this.dims.xOffset}, ${this.margin[0]})`;
11371 this.transformYAxis = `translate(0, ${yOffset})`;
11372 this.labelOffset = this.dims.height + 40;
11373 this.transformPlot = `translate(${halfWidth}, ${halfHeight})`;
11374 }
11375 setScales() {
11376 const xValues = this.getXValues();
11377 this.scaleType = getScaleType(xValues);
11378 this.xDomain = this.filteredDomain || this.getXDomain(xValues);
11379 this.yDomain = this.getYDomain();
11380 this.seriesDomain = this.getSeriesDomain();
11381 this.xScale = this.getXScale(this.xDomain, twoPI);
11382 this.yScale = this.getYScale(this.yDomain, this.outerRadius);
11383 this.yAxisScale = this.getYScale(this.yDomain.reverse(), this.outerRadius);
11384 }
11385 setTicks() {
11386 let tickFormat;
11387 if (this.xAxisTickFormatting) {
11388 tickFormat = this.xAxisTickFormatting;
11389 }
11390 else if (this.xScale.tickFormat) {
11391 tickFormat = this.xScale.tickFormat.apply(this.xScale, [5]);
11392 }
11393 else {
11394 tickFormat = d => {
11395 if (isDate(d)) {
11396 return d.toLocaleDateString();
11397 }
11398 return d.toLocaleString();
11399 };
11400 }
11401 const outerRadius = this.outerRadius;
11402 const s = 1.1;
11403 this.thetaTicks = this.xDomain.map(d => {
11404 const startAngle = this.xScale(d);
11405 const dd = s * outerRadius * (startAngle > Math.PI ? -1 : 1);
11406 const label = tickFormat(d);
11407 const startPos = [outerRadius * Math.sin(startAngle), -outerRadius * Math.cos(startAngle)];
11408 const pos = [dd, s * startPos[1]];
11409 return {
11410 innerRadius: 0,
11411 outerRadius,
11412 startAngle,
11413 endAngle: startAngle,
11414 value: outerRadius,
11415 label,
11416 startPos,
11417 pos
11418 };
11419 });
11420 const minDistance = 10;
11421 /* from pie chart, abstract out -*/
11422 for (let i = 0; i < this.thetaTicks.length - 1; i++) {
11423 const a = this.thetaTicks[i];
11424 for (let j = i + 1; j < this.thetaTicks.length; j++) {
11425 const b = this.thetaTicks[j];
11426 // if they're on the same side
11427 if (b.pos[0] * a.pos[0] > 0) {
11428 // if they're overlapping
11429 const o = minDistance - Math.abs(b.pos[1] - a.pos[1]);
11430 if (o > 0) {
11431 // push the second up or down
11432 b.pos[1] += Math.sign(b.pos[0]) * o;
11433 }
11434 }
11435 }
11436 }
11437 this.radiusTicks = this.yAxisScale.ticks(Math.floor(this.dims.height / 50)).map(d => this.yScale(d));
11438 }
11439 getXValues() {
11440 const values = [];
11441 for (const results of this.results) {
11442 for (const d of results.series) {
11443 if (!values.includes(d.name)) {
11444 values.push(d.name);
11445 }
11446 }
11447 }
11448 return values;
11449 }
11450 getXDomain(values = this.getXValues()) {
11451 if (this.scaleType === ScaleType.Time) {
11452 const min = Math.min(...values);
11453 const max = Math.max(...values);
11454 return [min, max];
11455 }
11456 else if (this.scaleType === ScaleType.Linear) {
11457 values = values.map(v => Number(v));
11458 const min = Math.min(...values);
11459 const max = Math.max(...values);
11460 return [min, max];
11461 }
11462 return values;
11463 }
11464 getYValues() {
11465 const domain = [];
11466 for (const results of this.results) {
11467 for (const d of results.series) {
11468 if (domain.indexOf(d.value) < 0) {
11469 domain.push(d.value);
11470 }
11471 if (d.min !== undefined) {
11472 if (domain.indexOf(d.min) < 0) {
11473 domain.push(d.min);
11474 }
11475 }
11476 if (d.max !== undefined) {
11477 if (domain.indexOf(d.max) < 0) {
11478 domain.push(d.max);
11479 }
11480 }
11481 }
11482 }
11483 return domain;
11484 }
11485 getYDomain(domain = this.getYValues()) {
11486 let min = Math.min(...domain);
11487 const max = Math.max(this.yAxisMinScale, ...domain);
11488 min = Math.max(0, min);
11489 if (!this.autoScale) {
11490 min = Math.min(0, min);
11491 }
11492 return [min, max];
11493 }
11494 getSeriesDomain() {
11495 return this.results.map(d => d.name);
11496 }
11497 getXScale(domain, width) {
11498 switch (this.scaleType) {
11499 case ScaleType.Time:
11500 return scaleTime().range([0, width]).domain(domain);
11501 case ScaleType.Linear:
11502 const scale = scaleLinear().range([0, width]).domain(domain);
11503 return this.roundDomains ? scale.nice() : scale;
11504 default:
11505 return scalePoint()
11506 .range([0, width - twoPI / domain.length])
11507 .padding(0)
11508 .domain(domain);
11509 }
11510 }
11511 getYScale(domain, height) {
11512 const scale = scaleLinear().range([0, height]).domain(domain);
11513 return this.roundDomains ? scale.nice() : scale;
11514 }
11515 onClick(data, series) {
11516 if (series) {
11517 data.series = series.name;
11518 }
11519 this.select.emit(data);
11520 }
11521 setColors() {
11522 const domain = this.schemeType === ScaleType.Ordinal ? this.seriesDomain : this.yDomain.reverse();
11523 this.colors = new ColorHelper(this.scheme, this.schemeType, domain, this.customColors);
11524 }
11525 getLegendOptions() {
11526 if (this.schemeType === ScaleType.Ordinal) {
11527 return {
11528 scaleType: this.schemeType,
11529 colors: this.colors,
11530 domain: this.seriesDomain,
11531 title: this.legendTitle,
11532 position: this.legendPosition
11533 };
11534 }
11535 return {
11536 scaleType: this.schemeType,
11537 colors: this.colors.scale,
11538 domain: this.yDomain,
11539 title: undefined,
11540 position: this.legendPosition
11541 };
11542 }
11543 updateYAxisWidth({ width }) {
11544 this.yAxisWidth = width;
11545 this.update();
11546 }
11547 updateXAxisHeight({ height }) {
11548 this.xAxisHeight = height;
11549 this.update();
11550 }
11551 onActivate(item) {
11552 const idx = this.activeEntries.findIndex(d => {
11553 return d.name === item.name && d.value === item.value;
11554 });
11555 if (idx > -1) {
11556 return;
11557 }
11558 this.activeEntries = this.showSeriesOnHover ? [item, ...this.activeEntries] : this.activeEntries;
11559 this.activate.emit({ value: item, entries: this.activeEntries });
11560 }
11561 onDeactivate(item) {
11562 const idx = this.activeEntries.findIndex(d => {
11563 return d.name === item.name && d.value === item.value;
11564 });
11565 this.activeEntries.splice(idx, 1);
11566 this.activeEntries = [...this.activeEntries];
11567 this.deactivate.emit({ value: item, entries: this.activeEntries });
11568 }
11569 deactivateAll() {
11570 this.activeEntries = [...this.activeEntries];
11571 for (const entry of this.activeEntries) {
11572 this.deactivate.emit({ value: entry, entries: [] });
11573 }
11574 this.activeEntries = [];
11575 }
11576 trackBy(index, item) {
11577 return `${item.name}`;
11578 }
11579}
11580PolarChartComponent.decorators = [
11581 { type: Component, args: [{
11582 selector: 'ngx-charts-polar-chart',
11583 template: `
11584 <ngx-charts-chart
11585 [view]="[width, height]"
11586 [showLegend]="legend"
11587 [legendOptions]="legendOptions"
11588 [activeEntries]="activeEntries"
11589 [animations]="animations"
11590 (legendLabelClick)="onClick($event)"
11591 (legendLabelActivate)="onActivate($event)"
11592 (legendLabelDeactivate)="onDeactivate($event)"
11593 >
11594 <svg:g class="polar-chart chart" [attr.transform]="transform">
11595 <svg:g [attr.transform]="transformPlot">
11596 <svg:circle class="polar-chart-background" cx="0" cy="0" [attr.r]="this.outerRadius" />
11597 <svg:g *ngIf="showGridLines">
11598 <svg:circle
11599 *ngFor="let r of radiusTicks"
11600 class="gridline-path radial-gridline-path"
11601 cx="0"
11602 cy="0"
11603 [attr.r]="r"
11604 />
11605 </svg:g>
11606 <svg:g *ngIf="xAxis">
11607 <svg:g
11608 ngx-charts-pie-label
11609 *ngFor="let tick of thetaTicks"
11610 [data]="tick"
11611 [radius]="outerRadius"
11612 [label]="tick.label"
11613 [max]="outerRadius"
11614 [value]="showGridLines ? 1 : outerRadius"
11615 [explodeSlices]="true"
11616 [animations]="animations"
11617 [labelTrim]="labelTrim"
11618 [labelTrimSize]="labelTrimSize"
11619 ></svg:g>
11620 </svg:g>
11621 </svg:g>
11622 <svg:g
11623 ngx-charts-y-axis
11624 [attr.transform]="transformYAxis"
11625 *ngIf="yAxis"
11626 [yScale]="yAxisScale"
11627 [dims]="yAxisDims"
11628 [showGridLines]="showGridLines"
11629 [showLabel]="showYAxisLabel"
11630 [labelText]="yAxisLabel"
11631 [trimTicks]="trimYAxisTicks"
11632 [maxTickLength]="maxYAxisTickLength"
11633 [tickFormatting]="yAxisTickFormatting"
11634 (dimensionsChanged)="updateYAxisWidth($event)"
11635 ></svg:g>
11636 <svg:g
11637 ngx-charts-axis-label
11638 *ngIf="xAxis && showXAxisLabel"
11639 [label]="xAxisLabel"
11640 [offset]="labelOffset"
11641 [orient]="orientation.Bottom"
11642 [height]="dims.height"
11643 [width]="dims.width"
11644 ></svg:g>
11645 <svg:g [attr.transform]="transformPlot">
11646 <svg:g *ngFor="let series of results; trackBy: trackBy" [@animationState]="'active'">
11647 <svg:g
11648 ngx-charts-polar-series
11649 [gradient]="gradient"
11650 [xScale]="xScale"
11651 [yScale]="yScale"
11652 [colors]="colors"
11653 [data]="series"
11654 [activeEntries]="activeEntries"
11655 [scaleType]="scaleType"
11656 [curve]="curve"
11657 [rangeFillOpacity]="rangeFillOpacity"
11658 [animations]="animations"
11659 [tooltipDisabled]="tooltipDisabled"
11660 [tooltipTemplate]="tooltipTemplate"
11661 (select)="onClick($event)"
11662 (activate)="onActivate($event)"
11663 (deactivate)="onDeactivate($event)"
11664 />
11665 </svg:g>
11666 </svg:g>
11667 </svg:g>
11668 </ngx-charts-chart>
11669 `,
11670 encapsulation: ViewEncapsulation.None,
11671 changeDetection: ChangeDetectionStrategy.OnPush,
11672 animations: [
11673 trigger('animationState', [
11674 transition(':leave', [
11675 style({
11676 opacity: 1
11677 }),
11678 animate(500, style({
11679 opacity: 0
11680 }))
11681 ])
11682 ])
11683 ],
11684 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".pie-label{font-size:11px}.pie-label.animation{-webkit-animation:.75s ease-in fadeIn;animation:.75s ease-in fadeIn}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.pie-label-line{stroke-dasharray:100%}.pie-label-line.animation{-webkit-animation:3s linear drawOut;animation:3s linear drawOut;transition:d .75s}@-webkit-keyframes drawOut{0%{stroke-dashoffset:100%}to{stroke-dashoffset:0}}@keyframes drawOut{0%{stroke-dashoffset:100%}to{stroke-dashoffset:0}}\n", ".polar-chart .polar-chart-background{fill:none}.polar-chart .radial-gridline-path{stroke-dasharray:10 10;fill:none}.polar-chart .pie-label-line{stroke:#2f3646}.polar-charts-series .polar-series-area{pointer-events:none}.polar-series-path{pointer-events:none}\n"]
11685 },] }
11686];
11687PolarChartComponent.propDecorators = {
11688 legend: [{ type: Input }],
11689 legendTitle: [{ type: Input }],
11690 legendPosition: [{ type: Input }],
11691 xAxis: [{ type: Input }],
11692 yAxis: [{ type: Input }],
11693 showXAxisLabel: [{ type: Input }],
11694 showYAxisLabel: [{ type: Input }],
11695 xAxisLabel: [{ type: Input }],
11696 yAxisLabel: [{ type: Input }],
11697 autoScale: [{ type: Input }],
11698 showGridLines: [{ type: Input }],
11699 curve: [{ type: Input }],
11700 activeEntries: [{ type: Input }],
11701 schemeType: [{ type: Input }],
11702 rangeFillOpacity: [{ type: Input }],
11703 trimYAxisTicks: [{ type: Input }],
11704 maxYAxisTickLength: [{ type: Input }],
11705 xAxisTickFormatting: [{ type: Input }],
11706 yAxisTickFormatting: [{ type: Input }],
11707 roundDomains: [{ type: Input }],
11708 tooltipDisabled: [{ type: Input }],
11709 showSeriesOnHover: [{ type: Input }],
11710 gradient: [{ type: Input }],
11711 yAxisMinScale: [{ type: Input }],
11712 labelTrim: [{ type: Input }],
11713 labelTrimSize: [{ type: Input }],
11714 activate: [{ type: Output }],
11715 deactivate: [{ type: Output }],
11716 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
11717};
11718
11719class PolarSeriesComponent {
11720 constructor() {
11721 this.tooltipDisabled = false;
11722 this.gradient = false;
11723 this.animations = true;
11724 this.select = new EventEmitter();
11725 this.activate = new EventEmitter();
11726 this.deactivate = new EventEmitter();
11727 this.circleRadius = 3;
11728 this.barOrientation = BarOrientation;
11729 this.placementTypes = PlacementTypes;
11730 this.styleTypes = StyleTypes;
11731 }
11732 ngOnChanges(changes) {
11733 this.update();
11734 }
11735 update() {
11736 this.updateGradients();
11737 const line = this.getLineGenerator();
11738 const data = this.sortData(this.data.series);
11739 const seriesName = this.data.name;
11740 const linearScaleType = this.colors.scaleType === ScaleType.Linear;
11741 const min = this.yScale.domain()[0];
11742 this.seriesColor = this.colors.getColor(linearScaleType ? min : seriesName);
11743 this.path = line(data) || '';
11744 this.circles = data.map(d => {
11745 const a = this.getAngle(d);
11746 const r = this.getRadius(d);
11747 const value = d.value;
11748 const color = this.colors.getColor(linearScaleType ? Math.abs(value) : seriesName);
11749 const cData = Object.assign({}, d, {
11750 series: seriesName,
11751 value,
11752 name: d.name
11753 });
11754 return {
11755 data: cData,
11756 cx: r * Math.sin(a),
11757 cy: -r * Math.cos(a),
11758 value,
11759 color,
11760 label: d.name
11761 };
11762 });
11763 this.active = this.isActive(this.data);
11764 this.inactive = this.isInactive(this.data);
11765 this.tooltipText = this.tooltipText || (c => this.defaultTooltipText(c));
11766 }
11767 getAngle(d) {
11768 const label = d.name;
11769 if (this.scaleType === ScaleType.Time) {
11770 return this.xScale(label);
11771 }
11772 else if (this.scaleType === ScaleType.Linear) {
11773 return this.xScale(Number(label));
11774 }
11775 return this.xScale(label);
11776 }
11777 getRadius(d) {
11778 return this.yScale(d.value);
11779 }
11780 getLineGenerator() {
11781 return lineRadial()
11782 .angle(d => this.getAngle(d))
11783 .radius(d => this.getRadius(d))
11784 .curve(this.curve);
11785 }
11786 sortData(data) {
11787 if (this.scaleType === ScaleType.Linear) {
11788 return sortLinear(data, 'name');
11789 }
11790 else if (this.scaleType === ScaleType.Time) {
11791 return sortByTime(data, 'name');
11792 }
11793 return sortByDomain(data, 'name', 'asc', this.xScale.domain());
11794 }
11795 isActive(entry) {
11796 if (!this.activeEntries)
11797 return false;
11798 const item = this.activeEntries.find(d => {
11799 return entry.name === d.name;
11800 });
11801 return item !== undefined;
11802 }
11803 isInactive(entry) {
11804 if (!this.activeEntries || this.activeEntries.length === 0)
11805 return false;
11806 const item = this.activeEntries.find(d => {
11807 return entry.name === d.name;
11808 });
11809 return item === undefined;
11810 }
11811 defaultTooltipText({ label, value }) {
11812 return `
11813 <span class="tooltip-label">${escapeLabel(this.data.name)}${escapeLabel(label)}</span>
11814 <span class="tooltip-val">${value.toLocaleString()}</span>
11815 `;
11816 }
11817 updateGradients() {
11818 this.hasGradient = this.gradient || this.colors.scaleType === ScaleType.Linear;
11819 if (!this.hasGradient) {
11820 return;
11821 }
11822 this.gradientId = 'grad' + id().toString();
11823 this.gradientUrl = `url(#${this.gradientId})`;
11824 if (this.colors.scaleType === ScaleType.Linear) {
11825 const values = this.data.series.map(d => d.value);
11826 const max = Math.max(...values);
11827 const min = Math.min(...values);
11828 this.gradientStops = this.colors.getLinearGradientStops(max, min);
11829 }
11830 else {
11831 this.gradientStops = undefined;
11832 }
11833 }
11834}
11835PolarSeriesComponent.decorators = [
11836 { type: Component, args: [{
11837 selector: 'g[ngx-charts-polar-series]',
11838 template: `
11839 <svg:g class="polar-charts-series">
11840 <defs>
11841 <svg:g
11842 ngx-charts-svg-radial-gradient
11843 *ngIf="hasGradient"
11844 [color]="seriesColor"
11845 [name]="gradientId"
11846 [startOpacity]="0.25"
11847 [endOpacity]="1"
11848 [stops]="gradientStops"
11849 />
11850 </defs>
11851 <svg:g
11852 ngx-charts-line
11853 class="polar-series-path"
11854 [path]="path"
11855 [stroke]="hasGradient ? gradientUrl : seriesColor"
11856 [class.active]="active"
11857 [class.inactive]="inactive"
11858 [attr.fill-opacity]="rangeFillOpacity"
11859 [fill]="hasGradient ? gradientUrl : seriesColor"
11860 [animations]="animations"
11861 />
11862 <svg:g
11863 ngx-charts-circle
11864 *ngFor="let circle of circles"
11865 class="circle"
11866 [cx]="circle.cx"
11867 [cy]="circle.cy"
11868 [r]="circleRadius"
11869 [fill]="circle.color"
11870 [style.opacity]="inactive ? 0.2 : 1"
11871 ngx-tooltip
11872 [tooltipDisabled]="tooltipDisabled"
11873 [tooltipPlacement]="placementTypes.Top"
11874 [tooltipType]="styleTypes.tooltip"
11875 [tooltipTitle]="tooltipTemplate ? undefined : tooltipText(circle)"
11876 [tooltipTemplate]="tooltipTemplate"
11877 [tooltipContext]="circle.data"
11878 (select)="select.emit(circle.data)"
11879 (activate)="activate.emit({ name: circle.data.series })"
11880 (deactivate)="deactivate.emit({ name: circle.data.series })"
11881 ></svg:g>
11882 </svg:g>
11883 `,
11884 changeDetection: ChangeDetectionStrategy.OnPush
11885 },] }
11886];
11887PolarSeriesComponent.propDecorators = {
11888 name: [{ type: Input }],
11889 data: [{ type: Input }],
11890 xScale: [{ type: Input }],
11891 yScale: [{ type: Input }],
11892 colors: [{ type: Input }],
11893 scaleType: [{ type: Input }],
11894 curve: [{ type: Input }],
11895 activeEntries: [{ type: Input }],
11896 rangeFillOpacity: [{ type: Input }],
11897 tooltipDisabled: [{ type: Input }],
11898 tooltipText: [{ type: Input }],
11899 gradient: [{ type: Input }],
11900 tooltipTemplate: [{ type: Input }],
11901 animations: [{ type: Input }],
11902 select: [{ type: Output }],
11903 activate: [{ type: Output }],
11904 deactivate: [{ type: Output }]
11905};
11906
11907class AdvancedPieChartComponent extends BaseChartComponent {
11908 constructor() {
11909 super(...arguments);
11910 this.activeEntries = [];
11911 this.tooltipDisabled = false;
11912 this.label = 'Total';
11913 this.activate = new EventEmitter();
11914 this.deactivate = new EventEmitter();
11915 this.margin = [20, 20, 20, 20];
11916 }
11917 update() {
11918 super.update();
11919 this.dims = calculateViewDimensions({
11920 width: (this.width * 4) / 12.0,
11921 height: this.height,
11922 margins: this.margin
11923 });
11924 this.formatDates();
11925 this.domain = this.getDomain();
11926 this.setColors();
11927 const xOffset = this.dims.width / 2;
11928 const yOffset = this.margin[0] + this.dims.height / 2;
11929 this.legendWidth = this.width - this.dims.width - this.margin[1];
11930 this.outerRadius = Math.min(this.dims.width, this.dims.height) / 2.5;
11931 this.innerRadius = this.outerRadius * 0.75;
11932 this.transform = `translate(${xOffset} , ${yOffset})`;
11933 }
11934 getDomain() {
11935 return this.results.map(d => d.label);
11936 }
11937 onClick(data) {
11938 this.select.emit(data);
11939 }
11940 setColors() {
11941 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
11942 }
11943 onActivate(item, fromLegend = false) {
11944 item = this.results.find(d => {
11945 if (fromLegend) {
11946 return d.label === item.name;
11947 }
11948 else {
11949 return d.name === item.name;
11950 }
11951 });
11952 const idx = this.activeEntries.findIndex(d => {
11953 return d.name === item.name && d.value === item.value && d.series === item.series;
11954 });
11955 if (idx > -1) {
11956 return;
11957 }
11958 this.activeEntries = [item, ...this.activeEntries];
11959 this.activate.emit({ value: item, entries: this.activeEntries });
11960 }
11961 onDeactivate(item, fromLegend = false) {
11962 item = this.results.find(d => {
11963 if (fromLegend) {
11964 return d.label === item.name;
11965 }
11966 else {
11967 return d.name === item.name;
11968 }
11969 });
11970 const idx = this.activeEntries.findIndex(d => {
11971 return d.name === item.name && d.value === item.value && d.series === item.series;
11972 });
11973 this.activeEntries.splice(idx, 1);
11974 this.activeEntries = [...this.activeEntries];
11975 this.deactivate.emit({ value: item, entries: this.activeEntries });
11976 }
11977}
11978AdvancedPieChartComponent.decorators = [
11979 { type: Component, args: [{
11980 selector: 'ngx-charts-advanced-pie-chart',
11981 template: `
11982 <div [style.width.px]="width" [style.height.px]="height">
11983 <div class="advanced-pie chart" [style.width.px]="dims.width" [style.height.px]="dims.height">
11984 <ngx-charts-chart [view]="[width, height]" [showLegend]="false" [animations]="animations">
11985 <svg:g [attr.transform]="transform" class="pie chart">
11986 <svg:g
11987 ngx-charts-pie-series
11988 [colors]="colors"
11989 [series]="results"
11990 [innerRadius]="innerRadius"
11991 [activeEntries]="activeEntries"
11992 [outerRadius]="outerRadius"
11993 [gradient]="gradient"
11994 [tooltipDisabled]="tooltipDisabled"
11995 [tooltipTemplate]="tooltipTemplate"
11996 [tooltipText]="tooltipText"
11997 (select)="onClick($event)"
11998 (activate)="onActivate($event)"
11999 (deactivate)="onDeactivate($event)"
12000 [animations]="animations"
12001 ></svg:g>
12002 </svg:g>
12003 </ngx-charts-chart>
12004 </div>
12005 <div class="advanced-pie-legend-wrapper" [style.width.px]="width - dims.width" [style.height.px]="height">
12006 <ngx-charts-advanced-legend
12007 [data]="results"
12008 [colors]="colors"
12009 [width]="width - dims.width - margin[1]"
12010 [label]="label"
12011 [animations]="animations"
12012 [valueFormatting]="valueFormatting"
12013 [labelFormatting]="nameFormatting"
12014 [percentageFormatting]="percentageFormatting"
12015 (select)="onClick($event)"
12016 (activate)="onActivate($event, true)"
12017 (deactivate)="onDeactivate($event, true)"
12018 >
12019 </ngx-charts-advanced-legend>
12020 </div>
12021 </div>
12022 `,
12023 encapsulation: ViewEncapsulation.None,
12024 changeDetection: ChangeDetectionStrategy.OnPush,
12025 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".advanced-pie{display:inline-block;float:left}.advanced-pie-legend-wrapper{display:inline-block}\n"]
12026 },] }
12027];
12028AdvancedPieChartComponent.propDecorators = {
12029 gradient: [{ type: Input }],
12030 activeEntries: [{ type: Input }],
12031 tooltipDisabled: [{ type: Input }],
12032 tooltipText: [{ type: Input }],
12033 label: [{ type: Input }],
12034 activate: [{ type: Output }],
12035 deactivate: [{ type: Output }],
12036 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
12037 valueFormatting: [{ type: Input }],
12038 nameFormatting: [{ type: Input }],
12039 percentageFormatting: [{ type: Input }]
12040};
12041
12042class PieLabelComponent {
12043 constructor(platformId) {
12044 this.platformId = platformId;
12045 this.animations = true;
12046 this.labelTrim = true;
12047 this.labelTrimSize = 10;
12048 this.trimLabel = trimLabel;
12049 }
12050 ngOnChanges(changes) {
12051 this.setTransforms();
12052 this.update();
12053 }
12054 setTransforms() {
12055 if (isPlatformServer(this.platformId)) {
12056 this.styleTransform = `translate3d(${this.textX}px,${this.textY}px, 0)`;
12057 this.attrTransform = `translate(${this.textX},${this.textY})`;
12058 this.textTransition = !this.animations ? null : 'transform 0.75s';
12059 }
12060 else {
12061 const isIE = /(edge|msie|trident)/i.test(navigator.userAgent);
12062 this.styleTransform = isIE ? null : `translate3d(${this.textX}px,${this.textY}px, 0)`;
12063 this.attrTransform = !isIE ? null : `translate(${this.textX},${this.textY})`;
12064 this.textTransition = isIE || !this.animations ? null : 'transform 0.75s';
12065 }
12066 }
12067 update() {
12068 let startRadius = this.radius;
12069 if (this.explodeSlices) {
12070 startRadius = (this.radius * this.value) / this.max;
12071 }
12072 const innerArc = arc().innerRadius(startRadius).outerRadius(startRadius);
12073 // Calculate innerPos then scale outer position to match label position
12074 const innerPos = innerArc.centroid(this.data);
12075 let scale = this.data.pos[1] / innerPos[1];
12076 if (this.data.pos[1] === 0 || innerPos[1] === 0) {
12077 scale = 1;
12078 }
12079 const outerPos = [scale * innerPos[0], scale * innerPos[1]];
12080 this.line = `M${innerPos}L${outerPos}L${this.data.pos}`;
12081 }
12082 get textX() {
12083 return this.data.pos[0];
12084 }
12085 get textY() {
12086 return this.data.pos[1];
12087 }
12088 textAnchor() {
12089 return this.midAngle(this.data) < Math.PI ? TextAnchor.Start : TextAnchor.End;
12090 }
12091 midAngle(d) {
12092 return d.startAngle + (d.endAngle - d.startAngle) / 2;
12093 }
12094}
12095PieLabelComponent.decorators = [
12096 { type: Component, args: [{
12097 selector: 'g[ngx-charts-pie-label]',
12098 template: `
12099 <title>{{ label }}</title>
12100 <svg:g [attr.transform]="attrTransform" [style.transform]="styleTransform" [style.transition]="textTransition">
12101 <svg:text
12102 class="pie-label"
12103 [class.animation]="animations"
12104 dy=".35em"
12105 [style.textAnchor]="textAnchor()"
12106 [style.shapeRendering]="'crispEdges'"
12107 >
12108 {{ labelTrim ? trimLabel(label, labelTrimSize) : label }}
12109 </svg:text>
12110 </svg:g>
12111 <svg:path
12112 [attr.d]="line"
12113 [attr.stroke]="color"
12114 fill="none"
12115 class="pie-label-line line"
12116 [class.animation]="animations"
12117 ></svg:path>
12118 `,
12119 changeDetection: ChangeDetectionStrategy.OnPush
12120 },] }
12121];
12122PieLabelComponent.ctorParameters = () => [
12123 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
12124];
12125PieLabelComponent.propDecorators = {
12126 data: [{ type: Input }],
12127 radius: [{ type: Input }],
12128 label: [{ type: Input }],
12129 color: [{ type: Input }],
12130 max: [{ type: Input }],
12131 value: [{ type: Input }],
12132 explodeSlices: [{ type: Input }],
12133 animations: [{ type: Input }],
12134 labelTrim: [{ type: Input }],
12135 labelTrimSize: [{ type: Input }]
12136};
12137
12138class PieArcComponent {
12139 constructor(element) {
12140 this.startAngle = 0;
12141 this.endAngle = Math.PI * 2;
12142 this.cornerRadius = 0;
12143 this.explodeSlices = false;
12144 this.gradient = false;
12145 this.animate = true;
12146 this.pointerEvents = true;
12147 this.isActive = false;
12148 this.select = new EventEmitter();
12149 this.activate = new EventEmitter();
12150 this.deactivate = new EventEmitter();
12151 this.dblclick = new EventEmitter();
12152 this.barOrientation = BarOrientation;
12153 this.initialized = false;
12154 this.element = element.nativeElement;
12155 }
12156 ngOnChanges(changes) {
12157 this.update();
12158 }
12159 getGradient() {
12160 return this.gradient ? this.gradientFill : this.fill;
12161 }
12162 getPointerEvents() {
12163 return this.pointerEvents ? 'auto' : 'none';
12164 }
12165 update() {
12166 const calc = this.calculateArc();
12167 this.startOpacity = 0.5;
12168 this.radialGradientId = 'linearGrad' + id().toString();
12169 this.gradientFill = `url(#${this.radialGradientId})`;
12170 if (this.animate) {
12171 if (this.initialized) {
12172 this.updateAnimation();
12173 }
12174 else {
12175 this.loadAnimation();
12176 this.initialized = true;
12177 }
12178 }
12179 else {
12180 this.path = calc.startAngle(this.startAngle).endAngle(this.endAngle)();
12181 }
12182 }
12183 calculateArc() {
12184 let outerRadius = this.outerRadius;
12185 if (this.explodeSlices && this.innerRadius === 0) {
12186 outerRadius = (this.outerRadius * this.value) / this.max;
12187 }
12188 return arc().innerRadius(this.innerRadius).outerRadius(outerRadius).cornerRadius(this.cornerRadius);
12189 }
12190 loadAnimation() {
12191 const node = select(this.element)
12192 .selectAll('.arc')
12193 .data([{ startAngle: this.startAngle, endAngle: this.endAngle }]);
12194 const calc = this.calculateArc();
12195 node
12196 .transition()
12197 .attrTween('d', function (d) {
12198 this._current = this._current || d;
12199 const copyOfD = Object.assign({}, d);
12200 copyOfD.endAngle = copyOfD.startAngle;
12201 const interpolater = interpolate(copyOfD, copyOfD);
12202 this._current = interpolater(0);
12203 return function (t) {
12204 return calc(interpolater(t));
12205 };
12206 })
12207 .transition()
12208 .duration(750)
12209 .attrTween('d', function (d) {
12210 this._current = this._current || d;
12211 const interpolater = interpolate(this._current, d);
12212 this._current = interpolater(0);
12213 return function (t) {
12214 return calc(interpolater(t));
12215 };
12216 });
12217 }
12218 updateAnimation() {
12219 const node = select(this.element)
12220 .selectAll('.arc')
12221 .data([{ startAngle: this.startAngle, endAngle: this.endAngle }]);
12222 const calc = this.calculateArc();
12223 node
12224 .transition()
12225 .duration(750)
12226 .attrTween('d', function (d) {
12227 this._current = this._current || d;
12228 const interpolater = interpolate(this._current, d);
12229 this._current = interpolater(0);
12230 return function (t) {
12231 return calc(interpolater(t));
12232 };
12233 });
12234 }
12235 onClick() {
12236 clearTimeout(this._timeout);
12237 this._timeout = setTimeout(() => this.select.emit(this.data), 200);
12238 }
12239 onDblClick(event) {
12240 event.preventDefault();
12241 event.stopPropagation();
12242 clearTimeout(this._timeout);
12243 this.dblclick.emit({
12244 data: this.data,
12245 nativeEvent: event
12246 });
12247 }
12248}
12249PieArcComponent.decorators = [
12250 { type: Component, args: [{
12251 selector: 'g[ngx-charts-pie-arc]',
12252 template: `
12253 <svg:g class="arc-group">
12254 <svg:defs *ngIf="gradient">
12255 <svg:g ngx-charts-svg-radial-gradient [color]="fill" [name]="radialGradientId" [startOpacity]="startOpacity" />
12256 </svg:defs>
12257 <svg:path
12258 [attr.d]="path"
12259 class="arc"
12260 [class.active]="isActive"
12261 [attr.fill]="getGradient()"
12262 (click)="onClick()"
12263 (dblclick)="onDblClick($event)"
12264 (mouseenter)="activate.emit(data)"
12265 (mouseleave)="deactivate.emit(data)"
12266 [style.pointer-events]="getPointerEvents()"
12267 />
12268 </svg:g>
12269 `,
12270 changeDetection: ChangeDetectionStrategy.OnPush
12271 },] }
12272];
12273PieArcComponent.ctorParameters = () => [
12274 { type: ElementRef }
12275];
12276PieArcComponent.propDecorators = {
12277 fill: [{ type: Input }],
12278 startAngle: [{ type: Input }],
12279 endAngle: [{ type: Input }],
12280 innerRadius: [{ type: Input }],
12281 outerRadius: [{ type: Input }],
12282 cornerRadius: [{ type: Input }],
12283 value: [{ type: Input }],
12284 max: [{ type: Input }],
12285 data: [{ type: Input }],
12286 explodeSlices: [{ type: Input }],
12287 gradient: [{ type: Input }],
12288 animate: [{ type: Input }],
12289 pointerEvents: [{ type: Input }],
12290 isActive: [{ type: Input }],
12291 select: [{ type: Output }],
12292 activate: [{ type: Output }],
12293 deactivate: [{ type: Output }],
12294 dblclick: [{ type: Output }]
12295};
12296
12297class PieChartComponent extends BaseChartComponent {
12298 constructor() {
12299 super(...arguments);
12300 this.labels = false;
12301 this.legend = false;
12302 this.legendTitle = 'Legend';
12303 this.legendPosition = LegendPosition.Right;
12304 this.explodeSlices = false;
12305 this.doughnut = false;
12306 this.arcWidth = 0.25;
12307 this.activeEntries = [];
12308 this.tooltipDisabled = false;
12309 this.trimLabels = true;
12310 this.maxLabelLength = 10;
12311 this.dblclick = new EventEmitter();
12312 this.select = new EventEmitter();
12313 this.activate = new EventEmitter();
12314 this.deactivate = new EventEmitter();
12315 }
12316 update() {
12317 super.update();
12318 if (this.labels && this.hasNoOptionalMarginsSet()) {
12319 this.margins = [30, 80, 30, 80];
12320 }
12321 else if (!this.labels && this.hasNoOptionalMarginsSet()) {
12322 // default value for margins
12323 this.margins = [20, 20, 20, 20];
12324 }
12325 this.dims = calculateViewDimensions({
12326 width: this.width,
12327 height: this.height,
12328 margins: this.margins,
12329 showLegend: this.legend,
12330 legendPosition: this.legendPosition
12331 });
12332 this.formatDates();
12333 const xOffset = this.margins[3] + this.dims.width / 2;
12334 const yOffset = this.margins[0] + this.dims.height / 2;
12335 this.translation = `translate(${xOffset}, ${yOffset})`;
12336 this.outerRadius = Math.min(this.dims.width, this.dims.height);
12337 if (this.labels) {
12338 // make room for labels
12339 this.outerRadius /= 3;
12340 }
12341 else {
12342 this.outerRadius /= 2;
12343 }
12344 this.innerRadius = 0;
12345 if (this.doughnut) {
12346 this.innerRadius = this.outerRadius * (1 - this.arcWidth);
12347 }
12348 this.domain = this.getDomain();
12349 // sort data according to domain
12350 this.data = this.results.sort((a, b) => {
12351 return this.domain.indexOf(a.name) - this.domain.indexOf(b.name);
12352 });
12353 this.setColors();
12354 this.legendOptions = this.getLegendOptions();
12355 }
12356 getDomain() {
12357 return this.results.map(d => d.label);
12358 }
12359 onClick(data) {
12360 this.select.emit(data);
12361 }
12362 setColors() {
12363 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
12364 }
12365 getLegendOptions() {
12366 return {
12367 scaleType: ScaleType.Ordinal,
12368 domain: this.domain,
12369 colors: this.colors,
12370 title: this.legendTitle,
12371 position: this.legendPosition
12372 };
12373 }
12374 onActivate(item, fromLegend = false) {
12375 item = this.results.find(d => {
12376 if (fromLegend) {
12377 return d.label === item.name;
12378 }
12379 else {
12380 return d.name === item.name;
12381 }
12382 });
12383 const idx = this.activeEntries.findIndex(d => {
12384 return d.name === item.name && d.value === item.value && d.series === item.series;
12385 });
12386 if (idx > -1) {
12387 return;
12388 }
12389 this.activeEntries = [item, ...this.activeEntries];
12390 this.activate.emit({ value: item, entries: this.activeEntries });
12391 }
12392 onDeactivate(item, fromLegend = false) {
12393 item = this.results.find(d => {
12394 if (fromLegend) {
12395 return d.label === item.name;
12396 }
12397 else {
12398 return d.name === item.name;
12399 }
12400 });
12401 const idx = this.activeEntries.findIndex(d => {
12402 return d.name === item.name && d.value === item.value && d.series === item.series;
12403 });
12404 this.activeEntries.splice(idx, 1);
12405 this.activeEntries = [...this.activeEntries];
12406 this.deactivate.emit({ value: item, entries: this.activeEntries });
12407 }
12408 hasNoOptionalMarginsSet() {
12409 return !this.margins || this.margins.length <= 0;
12410 }
12411}
12412PieChartComponent.decorators = [
12413 { type: Component, args: [{
12414 selector: 'ngx-charts-pie-chart',
12415 template: `
12416 <ngx-charts-chart
12417 [view]="[width, height]"
12418 [showLegend]="legend"
12419 [legendOptions]="legendOptions"
12420 [activeEntries]="activeEntries"
12421 [animations]="animations"
12422 (legendLabelActivate)="onActivate($event, true)"
12423 (legendLabelDeactivate)="onDeactivate($event, true)"
12424 (legendLabelClick)="onClick($event)"
12425 >
12426 <svg:g [attr.transform]="translation" class="pie-chart chart">
12427 <svg:g
12428 ngx-charts-pie-series
12429 [colors]="colors"
12430 [series]="data"
12431 [showLabels]="labels"
12432 [labelFormatting]="labelFormatting"
12433 [trimLabels]="trimLabels"
12434 [maxLabelLength]="maxLabelLength"
12435 [activeEntries]="activeEntries"
12436 [innerRadius]="innerRadius"
12437 [outerRadius]="outerRadius"
12438 [explodeSlices]="explodeSlices"
12439 [gradient]="gradient"
12440 [animations]="animations"
12441 [tooltipDisabled]="tooltipDisabled"
12442 [tooltipTemplate]="tooltipTemplate"
12443 [tooltipText]="tooltipText"
12444 (dblclick)="dblclick.emit($event)"
12445 (select)="onClick($event)"
12446 (activate)="onActivate($event)"
12447 (deactivate)="onDeactivate($event)"
12448 />
12449 </svg:g>
12450 </ngx-charts-chart>
12451 `,
12452 encapsulation: ViewEncapsulation.None,
12453 changeDetection: ChangeDetectionStrategy.OnPush,
12454 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".pie-label{font-size:11px}.pie-label.animation{-webkit-animation:.75s ease-in fadeIn;animation:.75s ease-in fadeIn}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.pie-label-line{stroke-dasharray:100%}.pie-label-line.animation{-webkit-animation:3s linear drawOut;animation:3s linear drawOut;transition:d .75s}@-webkit-keyframes drawOut{0%{stroke-dashoffset:100%}to{stroke-dashoffset:0}}@keyframes drawOut{0%{stroke-dashoffset:100%}to{stroke-dashoffset:0}}\n"]
12455 },] }
12456];
12457PieChartComponent.propDecorators = {
12458 labels: [{ type: Input }],
12459 legend: [{ type: Input }],
12460 legendTitle: [{ type: Input }],
12461 legendPosition: [{ type: Input }],
12462 explodeSlices: [{ type: Input }],
12463 doughnut: [{ type: Input }],
12464 arcWidth: [{ type: Input }],
12465 gradient: [{ type: Input }],
12466 activeEntries: [{ type: Input }],
12467 tooltipDisabled: [{ type: Input }],
12468 labelFormatting: [{ type: Input }],
12469 trimLabels: [{ type: Input }],
12470 maxLabelLength: [{ type: Input }],
12471 tooltipText: [{ type: Input }],
12472 dblclick: [{ type: Output }],
12473 margins: [{ type: Input }],
12474 select: [{ type: Output }],
12475 activate: [{ type: Output }],
12476 deactivate: [{ type: Output }],
12477 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
12478};
12479
12480function gridSize(dims, len, minWidth) {
12481 let rows = 1;
12482 let cols = len;
12483 const width = dims.width;
12484 if (width > minWidth) {
12485 while (width / cols < minWidth) {
12486 rows += 1;
12487 cols = Math.ceil(len / rows);
12488 }
12489 }
12490 return [cols, rows];
12491}
12492function gridLayout(dims, data, minWidth, designatedTotal) {
12493 const xScale = scaleBand();
12494 const yScale = scaleBand();
12495 const width = dims.width;
12496 const height = dims.height;
12497 const [columns, rows] = gridSize(dims, data.length, minWidth);
12498 const xDomain = [];
12499 const yDomain = [];
12500 for (let i = 0; i < rows; i++) {
12501 yDomain.push(i);
12502 }
12503 for (let i = 0; i < columns; i++) {
12504 xDomain.push(i);
12505 }
12506 xScale.domain(xDomain);
12507 yScale.domain(yDomain);
12508 xScale.rangeRound([0, width], 0.1);
12509 yScale.rangeRound([0, height], 0.1);
12510 const res = [];
12511 const total = designatedTotal ? designatedTotal : getTotal(data);
12512 const cardWidth = xScale.bandwidth();
12513 const cardHeight = yScale.bandwidth();
12514 for (let i = 0; i < data.length; i++) {
12515 res[i] = {};
12516 res[i].data = {
12517 name: data[i] ? data[i].name : '',
12518 value: data[i] ? data[i].value : undefined,
12519 extra: data[i] ? data[i].extra : undefined,
12520 label: data[i] ? data[i].label : ''
12521 };
12522 res[i].x = xScale(i % columns);
12523 res[i].y = yScale(Math.floor(i / columns));
12524 res[i].width = cardWidth;
12525 res[i].height = cardHeight;
12526 res[i].data.percent = total > 0 ? res[i].data.value / total : 0;
12527 res[i].data.total = total;
12528 }
12529 return res;
12530}
12531function getTotal(results) {
12532 return results.map(d => (d ? d.value : 0)).reduce((sum, val) => sum + val, 0);
12533}
12534
12535class PieGridComponent extends BaseChartComponent {
12536 constructor() {
12537 super(...arguments);
12538 this.tooltipDisabled = false;
12539 this.label = 'Total';
12540 this.minWidth = 150;
12541 this.activeEntries = [];
12542 this.activate = new EventEmitter();
12543 this.deactivate = new EventEmitter();
12544 this.margin = [20, 20, 20, 20];
12545 this.placementTypes = PlacementTypes;
12546 this.styleTypes = StyleTypes;
12547 }
12548 update() {
12549 super.update();
12550 this.dims = calculateViewDimensions({
12551 width: this.width,
12552 height: this.height,
12553 margins: this.margin
12554 });
12555 this.formatDates();
12556 this.domain = this.getDomain();
12557 this.data = gridLayout(this.dims, this.results, this.minWidth, this.designatedTotal);
12558 this.transform = `translate(${this.margin[3]} , ${this.margin[0]})`;
12559 this.series = this.getSeries();
12560 this.setColors();
12561 this.tooltipText = this.tooltipText || this.defaultTooltipText;
12562 }
12563 defaultTooltipText({ data }) {
12564 const label = trimLabel(formatLabel(data.name));
12565 const val = data.value.toLocaleString();
12566 return `
12567 <span class="tooltip-label">${label}</span>
12568 <span class="tooltip-val">${val}</span>
12569 `;
12570 }
12571 getDomain() {
12572 return this.results.map(d => d.label);
12573 }
12574 getSeries() {
12575 const total = this.designatedTotal ? this.designatedTotal : this.getTotal();
12576 return this.data.map(d => {
12577 const baselineLabelHeight = 20;
12578 const padding = 10;
12579 const name = d.data.name;
12580 const label = formatLabel(name);
12581 const value = d.data.value;
12582 const radius = min([d.width - padding, d.height - baselineLabelHeight]) / 2 - 5;
12583 const innerRadius = radius * 0.9;
12584 let count = 0;
12585 const colors = () => {
12586 count += 1;
12587 if (count === 1) {
12588 return 'rgba(100,100,100,0.3)';
12589 }
12590 else {
12591 return this.colorScale.getColor(label);
12592 }
12593 };
12594 const xPos = d.x + (d.width - padding) / 2;
12595 const yPos = d.y + (d.height - baselineLabelHeight) / 2;
12596 return {
12597 transform: `translate(${xPos}, ${yPos})`,
12598 colors,
12599 innerRadius,
12600 outerRadius: radius,
12601 name,
12602 label: trimLabel(label),
12603 total: value,
12604 value,
12605 percent: format('.1%')(d.data.percent),
12606 data: [
12607 d,
12608 {
12609 data: {
12610 other: true,
12611 value: total - value,
12612 name: d.data.name
12613 }
12614 }
12615 ]
12616 };
12617 });
12618 }
12619 getTotal() {
12620 return this.results.map(d => d.value).reduce((sum, d) => sum + d, 0);
12621 }
12622 onClick(data) {
12623 this.select.emit(data);
12624 }
12625 setColors() {
12626 this.colorScale = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
12627 }
12628 onActivate(item, fromLegend = false) {
12629 item = this.results.find(d => {
12630 if (fromLegend) {
12631 return d.label === item.name;
12632 }
12633 else {
12634 return d.name === item.name;
12635 }
12636 });
12637 const idx = this.activeEntries.findIndex(d => {
12638 return d.name === item.name && d.value === item.value && d.series === item.series;
12639 });
12640 if (idx > -1) {
12641 return;
12642 }
12643 this.activeEntries = [item, ...this.activeEntries];
12644 this.activate.emit({ value: item, entries: this.activeEntries });
12645 }
12646 onDeactivate(item, fromLegend = false) {
12647 item = this.results.find(d => {
12648 if (fromLegend) {
12649 return d.label === item.name;
12650 }
12651 else {
12652 return d.name === item.name;
12653 }
12654 });
12655 const idx = this.activeEntries.findIndex(d => {
12656 return d.name === item.name && d.value === item.value && d.series === item.series;
12657 });
12658 this.activeEntries.splice(idx, 1);
12659 this.activeEntries = [...this.activeEntries];
12660 this.deactivate.emit({ value: item, entries: this.activeEntries });
12661 }
12662}
12663PieGridComponent.decorators = [
12664 { type: Component, args: [{
12665 selector: 'ngx-charts-pie-grid',
12666 template: `
12667 <ngx-charts-chart [view]="[width, height]" [showLegend]="false" [animations]="animations">
12668 <svg:g [attr.transform]="transform" class="pie-grid chart">
12669 <svg:g *ngFor="let series of series" class="pie-grid-item" [attr.transform]="series.transform">
12670 <svg:g
12671 ngx-charts-pie-grid-series
12672 [colors]="series.colors"
12673 [data]="series.data"
12674 [innerRadius]="series.innerRadius"
12675 [outerRadius]="series.outerRadius"
12676 [animations]="animations"
12677 (select)="onClick($event)"
12678 ngx-tooltip
12679 [tooltipDisabled]="tooltipDisabled"
12680 [tooltipPlacement]="placementTypes.Top"
12681 [tooltipType]="styleTypes.tooltip"
12682 [tooltipTitle]="tooltipTemplate ? undefined : tooltipText({ data: series })"
12683 [tooltipTemplate]="tooltipTemplate"
12684 [tooltipContext]="series.data[0].data"
12685 (activate)="onActivate($event)"
12686 (deactivate)="onDeactivate($event)"
12687 />
12688 <svg:text
12689 *ngIf="animations"
12690 class="label percent-label"
12691 dy="-0.5em"
12692 x="0"
12693 y="5"
12694 ngx-charts-count-up
12695 [countTo]="series.percent"
12696 [countSuffix]="'%'"
12697 text-anchor="middle"
12698 ></svg:text>
12699 <svg:text *ngIf="!animations" class="label percent-label" dy="-0.5em" x="0" y="5" text-anchor="middle">
12700 {{ series.percent.toLocaleString() }}
12701 </svg:text>
12702 <svg:text class="label" dy="0.5em" x="0" y="5" text-anchor="middle">
12703 {{ series.label }}
12704 </svg:text>
12705 <svg:text
12706 *ngIf="animations"
12707 class="label"
12708 dy="1.23em"
12709 x="0"
12710 [attr.y]="series.outerRadius"
12711 text-anchor="middle"
12712 ngx-charts-count-up
12713 [countTo]="series.total"
12714 [countPrefix]="label + ': '"
12715 ></svg:text>
12716 <svg:text
12717 *ngIf="!animations"
12718 class="label"
12719 dy="1.23em"
12720 x="0"
12721 [attr.y]="series.outerRadius"
12722 text-anchor="middle"
12723 >
12724 {{ label }}: {{ series.total.toLocaleString() }}
12725 </svg:text>
12726 </svg:g>
12727 </svg:g>
12728 </ngx-charts-chart>
12729 `,
12730 encapsulation: ViewEncapsulation.None,
12731 changeDetection: ChangeDetectionStrategy.OnPush,
12732 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".pie-grid .arc1{opacity:.4}.pie-grid .percent-label{font-size:16px;font-weight:400}\n"]
12733 },] }
12734];
12735PieGridComponent.propDecorators = {
12736 designatedTotal: [{ type: Input }],
12737 tooltipDisabled: [{ type: Input }],
12738 tooltipText: [{ type: Input }],
12739 label: [{ type: Input }],
12740 minWidth: [{ type: Input }],
12741 activeEntries: [{ type: Input }],
12742 activate: [{ type: Output }],
12743 deactivate: [{ type: Output }],
12744 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
12745};
12746
12747class PieGridSeriesComponent {
12748 constructor(element) {
12749 this.innerRadius = 70;
12750 this.outerRadius = 80;
12751 this.animations = true;
12752 this.select = new EventEmitter();
12753 this.activate = new EventEmitter();
12754 this.deactivate = new EventEmitter();
12755 this.element = element.nativeElement;
12756 }
12757 ngOnChanges(changes) {
12758 this.update();
12759 }
12760 update() {
12761 this.layout = pie()
12762 .value(d => d.data.value)
12763 .sort(null);
12764 this.arcs = this.getArcs();
12765 }
12766 getArcs() {
12767 return this.layout(this.data).map((arc, index) => {
12768 const label = arc.data.data.name;
12769 const other = arc.data.data.other;
12770 if (index === 0) {
12771 arc.startAngle = 0;
12772 }
12773 const color = this.colors(label);
12774 return {
12775 data: arc.data.data,
12776 class: 'arc ' + 'arc' + index,
12777 fill: color,
12778 startAngle: other ? 0 : arc.startAngle,
12779 endAngle: arc.endAngle,
12780 animate: this.animations && !other,
12781 pointerEvents: !other
12782 };
12783 });
12784 }
12785 onClick(data) {
12786 this.select.emit(this.data[0].data);
12787 }
12788 trackBy(index, item) {
12789 return item.data.name;
12790 }
12791 label(arc) {
12792 return arc.data.name;
12793 }
12794 color(arc) {
12795 return this.colors(this.label(arc));
12796 }
12797}
12798PieGridSeriesComponent.decorators = [
12799 { type: Component, args: [{
12800 selector: 'g[ngx-charts-pie-grid-series]',
12801 template: `
12802 <svg:g class="pie-grid-arcs">
12803 <svg:g
12804 ngx-charts-pie-arc
12805 *ngFor="let arc of arcs; trackBy: trackBy"
12806 [attr.class]="arc.class"
12807 [startAngle]="arc.startAngle"
12808 [endAngle]="arc.endAngle"
12809 [innerRadius]="innerRadius"
12810 [outerRadius]="outerRadius"
12811 [fill]="color(arc)"
12812 [value]="arc.data.value"
12813 [data]="arc.data"
12814 [gradient]="false"
12815 [pointerEvents]="arc.pointerEvents"
12816 [animate]="arc.animate"
12817 (select)="onClick($event)"
12818 (activate)="activate.emit($event)"
12819 (deactivate)="deactivate.emit($event)"
12820 ></svg:g>
12821 </svg:g>
12822 `,
12823 changeDetection: ChangeDetectionStrategy.OnPush
12824 },] }
12825];
12826PieGridSeriesComponent.ctorParameters = () => [
12827 { type: ElementRef }
12828];
12829PieGridSeriesComponent.propDecorators = {
12830 colors: [{ type: Input }],
12831 data: [{ type: Input }],
12832 innerRadius: [{ type: Input }],
12833 outerRadius: [{ type: Input }],
12834 animations: [{ type: Input }],
12835 select: [{ type: Output }],
12836 activate: [{ type: Output }],
12837 deactivate: [{ type: Output }]
12838};
12839
12840class PieSeriesComponent {
12841 constructor() {
12842 this.series = [];
12843 this.innerRadius = 60;
12844 this.outerRadius = 80;
12845 this.trimLabels = true;
12846 this.maxLabelLength = 10;
12847 this.tooltipDisabled = false;
12848 this.animations = true;
12849 this.select = new EventEmitter();
12850 this.activate = new EventEmitter();
12851 this.deactivate = new EventEmitter();
12852 this.dblclick = new EventEmitter();
12853 this.placementTypes = PlacementTypes;
12854 this.styleTypes = StyleTypes;
12855 }
12856 ngOnChanges(changes) {
12857 this.update();
12858 }
12859 update() {
12860 const pieGenerator = pie()
12861 .value(d => d.value)
12862 .sort(null);
12863 const arcData = pieGenerator(this.series);
12864 this.max = max(arcData, d => {
12865 return d.value;
12866 });
12867 this.data = this.calculateLabelPositions(arcData);
12868 this.tooltipText = this.tooltipText || this.defaultTooltipText;
12869 }
12870 midAngle(d) {
12871 return d.startAngle + (d.endAngle - d.startAngle) / 2;
12872 }
12873 outerArc() {
12874 const factor = 1.5;
12875 return arc()
12876 .innerRadius(this.outerRadius * factor)
12877 .outerRadius(this.outerRadius * factor);
12878 }
12879 calculateLabelPositions(pieData) {
12880 const factor = 1.5;
12881 const minDistance = 10;
12882 const labelPositions = pieData;
12883 labelPositions.forEach(d => {
12884 d.pos = this.outerArc().centroid(d);
12885 d.pos[0] = factor * this.outerRadius * (this.midAngle(d) < Math.PI ? 1 : -1);
12886 });
12887 for (let i = 0; i < labelPositions.length - 1; i++) {
12888 const a = labelPositions[i];
12889 if (!this.labelVisible(a)) {
12890 continue;
12891 }
12892 for (let j = i + 1; j < labelPositions.length; j++) {
12893 const b = labelPositions[j];
12894 if (!this.labelVisible(b)) {
12895 continue;
12896 }
12897 // if they're on the same side
12898 if (b.pos[0] * a.pos[0] > 0) {
12899 // if they're overlapping
12900 const o = minDistance - Math.abs(b.pos[1] - a.pos[1]);
12901 if (o > 0) {
12902 // push the second up or down
12903 b.pos[1] += Math.sign(b.pos[0]) * o;
12904 }
12905 }
12906 }
12907 }
12908 return labelPositions;
12909 }
12910 labelVisible(myArc) {
12911 return this.showLabels && myArc.endAngle - myArc.startAngle > Math.PI / 30;
12912 }
12913 getTooltipTitle(a) {
12914 return this.tooltipTemplate ? undefined : this.tooltipText(a);
12915 }
12916 labelText(myArc) {
12917 if (this.labelFormatting) {
12918 return this.labelFormatting(myArc.data.name);
12919 }
12920 return this.label(myArc);
12921 }
12922 label(myArc) {
12923 return formatLabel(myArc.data.name);
12924 }
12925 defaultTooltipText(myArc) {
12926 const label = this.label(myArc);
12927 const val = formatLabel(myArc.data.value);
12928 return `
12929 <span class="tooltip-label">${escapeLabel(label)}</span>
12930 <span class="tooltip-val">${val}</span>
12931 `;
12932 }
12933 color(myArc) {
12934 return this.colors.getColor(this.label(myArc));
12935 }
12936 trackBy(index, item) {
12937 return item.data.name;
12938 }
12939 onClick(data) {
12940 this.select.emit(data);
12941 }
12942 isActive(entry) {
12943 if (!this.activeEntries)
12944 return false;
12945 const item = this.activeEntries.find(d => {
12946 return entry.name === d.name && entry.series === d.series;
12947 });
12948 return item !== undefined;
12949 }
12950}
12951PieSeriesComponent.decorators = [
12952 { type: Component, args: [{
12953 selector: 'g[ngx-charts-pie-series]',
12954 template: `
12955 <svg:g *ngFor="let arc of data; trackBy: trackBy">
12956 <svg:g
12957 ngx-charts-pie-label
12958 *ngIf="labelVisible(arc)"
12959 [data]="arc"
12960 [radius]="outerRadius"
12961 [color]="color(arc)"
12962 [label]="labelText(arc)"
12963 [labelTrim]="trimLabels"
12964 [labelTrimSize]="maxLabelLength"
12965 [max]="max"
12966 [value]="arc.value"
12967 [explodeSlices]="explodeSlices"
12968 [animations]="animations"
12969 ></svg:g>
12970 <svg:g
12971 ngx-charts-pie-arc
12972 [startAngle]="arc.startAngle"
12973 [endAngle]="arc.endAngle"
12974 [innerRadius]="innerRadius"
12975 [outerRadius]="outerRadius"
12976 [fill]="color(arc)"
12977 [value]="arc.data.value"
12978 [gradient]="gradient"
12979 [data]="arc.data"
12980 [max]="max"
12981 [explodeSlices]="explodeSlices"
12982 [isActive]="isActive(arc.data)"
12983 [animate]="animations"
12984 (select)="onClick($event)"
12985 (activate)="activate.emit($event)"
12986 (deactivate)="deactivate.emit($event)"
12987 (dblclick)="dblclick.emit($event)"
12988 ngx-tooltip
12989 [tooltipDisabled]="tooltipDisabled"
12990 [tooltipPlacement]="placementTypes.Top"
12991 [tooltipType]="styleTypes.tooltip"
12992 [tooltipTitle]="getTooltipTitle(arc)"
12993 [tooltipTemplate]="tooltipTemplate"
12994 [tooltipContext]="arc.data"
12995 ></svg:g>
12996 </svg:g>
12997 `,
12998 changeDetection: ChangeDetectionStrategy.OnPush
12999 },] }
13000];
13001PieSeriesComponent.propDecorators = {
13002 colors: [{ type: Input }],
13003 series: [{ type: Input }],
13004 dims: [{ type: Input }],
13005 innerRadius: [{ type: Input }],
13006 outerRadius: [{ type: Input }],
13007 explodeSlices: [{ type: Input }],
13008 showLabels: [{ type: Input }],
13009 gradient: [{ type: Input }],
13010 activeEntries: [{ type: Input }],
13011 labelFormatting: [{ type: Input }],
13012 trimLabels: [{ type: Input }],
13013 maxLabelLength: [{ type: Input }],
13014 tooltipText: [{ type: Input }],
13015 tooltipDisabled: [{ type: Input }],
13016 tooltipTemplate: [{ type: Input }],
13017 animations: [{ type: Input }],
13018 select: [{ type: Output }],
13019 activate: [{ type: Output }],
13020 deactivate: [{ type: Output }],
13021 dblclick: [{ type: Output }]
13022};
13023
13024class PieChartModule {
13025}
13026PieChartModule.decorators = [
13027 { type: NgModule, args: [{
13028 imports: [ChartCommonModule],
13029 declarations: [
13030 AdvancedPieChartComponent,
13031 PieLabelComponent,
13032 PieArcComponent,
13033 PieChartComponent,
13034 PieGridComponent,
13035 PieGridSeriesComponent,
13036 PieSeriesComponent
13037 ],
13038 exports: [
13039 AdvancedPieChartComponent,
13040 PieLabelComponent,
13041 PieArcComponent,
13042 PieChartComponent,
13043 PieGridComponent,
13044 PieGridSeriesComponent,
13045 PieSeriesComponent
13046 ]
13047 },] }
13048];
13049
13050class PolarChartModule {
13051}
13052PolarChartModule.decorators = [
13053 { type: NgModule, args: [{
13054 imports: [ChartCommonModule, PieChartModule, LineChartModule],
13055 declarations: [PolarChartComponent, PolarSeriesComponent],
13056 exports: [PolarChartComponent, PolarSeriesComponent]
13057 },] }
13058];
13059
13060function calculateTextWidth(fontFamilyKey, text, defaultWidth = 8) {
13061 return text.split('').reduce((acc, curr) => {
13062 const width = fontFamilyKey[curr] || defaultWidth;
13063 return acc + width;
13064 }, 0);
13065}
13066
13067const VERDANA_FONT_WIDTHS_16_PX = {
13068 '0': 10,
13069 '1': 10,
13070 '2': 10,
13071 '3': 10,
13072 '4': 10,
13073 '5': 10,
13074 '6': 10,
13075 '7': 10,
13076 '8': 10,
13077 '9': 10,
13078 A: 11,
13079 B: 11,
13080 C: 11,
13081 D: 12,
13082 E: 10,
13083 F: 9,
13084 G: 12,
13085 H: 12,
13086 I: 7,
13087 J: 7,
13088 K: 11,
13089 L: 9,
13090 M: 13,
13091 N: 12,
13092 O: 13,
13093 P: 10,
13094 Q: 13,
13095 R: 11,
13096 S: 11,
13097 T: 10,
13098 U: 12,
13099 V: 11,
13100 W: 16,
13101 X: 11,
13102 Y: 10,
13103 Z: 11,
13104 a: 10,
13105 b: 10,
13106 c: 8,
13107 d: 10,
13108 e: 10,
13109 f: 6,
13110 g: 10,
13111 h: 10,
13112 i: 4,
13113 j: 6,
13114 k: 9,
13115 l: 4,
13116 m: 16,
13117 n: 10,
13118 o: 10,
13119 p: 10,
13120 q: 10,
13121 r: 7,
13122 s: 8,
13123 t: 6,
13124 u: 10,
13125 v: 9,
13126 w: 13,
13127 x: 9,
13128 y: 9,
13129 z: 8,
13130 '!': 6,
13131 '@': 16,
13132 '#': 13,
13133 $: 10,
13134 '%': 17,
13135 '^': 13,
13136 '&': 12,
13137 '*': 10,
13138 '(': 7,
13139 ')': 7,
13140 _: 10,
13141 '-': 7,
13142 '+': 13,
13143 '=': 13,
13144 ',': 6,
13145 '.': 6,
13146 '/': 7,
13147 "'": 4,
13148 ':': 7,
13149 '|': 7,
13150 '?': 9,
13151 ';': 7,
13152 '<': 13,
13153 '>': 13
13154};
13155
13156class CardComponent {
13157 constructor(element, cd, zone, platformId) {
13158 this.cd = cd;
13159 this.zone = zone;
13160 this.platformId = platformId;
13161 this.animations = true;
13162 this.select = new EventEmitter();
13163 this.value = '';
13164 this.textFontSize = 12;
13165 this.textTransform = '';
13166 this.initialized = false;
13167 this.bandHeight = 10;
13168 this.textPadding = [10, 20, 5, 20];
13169 this.labelFontSize = 15;
13170 this.element = element.nativeElement;
13171 }
13172 ngOnChanges(changes) {
13173 this.update();
13174 }
13175 ngOnInit() {
13176 if (isPlatformServer(this.platformId)) {
13177 this.scaleTextSSR();
13178 }
13179 }
13180 ngOnDestroy() {
13181 if (isPlatformBrowser(this.platformId)) {
13182 cancelAnimationFrame(this.animationReq);
13183 }
13184 }
13185 update() {
13186 this.zone.run(() => {
13187 const hasValue = this.data && typeof this.data.value !== 'undefined';
13188 const valueFormatting = this.valueFormatting || (card => card.value.toLocaleString());
13189 const labelFormatting = this.labelFormatting || (card => escapeLabel(trimLabel(card.label, 55)));
13190 this.transform = `translate(${this.x} , ${this.y})`;
13191 this.textWidth = Math.max(0, this.width) - this.textPadding[1] - this.textPadding[3];
13192 this.cardWidth = Math.max(0, this.width);
13193 this.cardHeight = Math.max(0, this.height);
13194 this.label = this.label ? this.label : this.data.name;
13195 const cardData = {
13196 label: this.label,
13197 data: this.data,
13198 value: this.data.value
13199 };
13200 this.formattedLabel = labelFormatting(cardData);
13201 this.transformBand = `translate(0 , ${this.cardHeight - this.bandHeight})`;
13202 const value = hasValue ? valueFormatting(cardData) : '';
13203 this.value = this.paddedValue(value);
13204 this.setPadding();
13205 this.bandPath = roundedRect(0, 0, this.cardWidth, this.bandHeight, 3, [false, false, true, true]);
13206 setTimeout(() => {
13207 if (isPlatformBrowser(this.platformId)) {
13208 this.scaleText();
13209 }
13210 this.value = value;
13211 if (hasValue && !this.initialized) {
13212 setTimeout(() => this.startCount(), 20);
13213 }
13214 }, 8);
13215 });
13216 }
13217 paddedValue(value) {
13218 if (this.medianSize && this.medianSize > value.length) {
13219 value += '\u2007'.repeat(this.medianSize - value.length);
13220 }
13221 return value;
13222 }
13223 startCount() {
13224 if (!this.initialized && this.animations) {
13225 cancelAnimationFrame(this.animationReq);
13226 const val = this.data.value;
13227 const decs = decimalChecker(val);
13228 const valueFormatting = this.valueFormatting || (card => card.value.toLocaleString());
13229 const callback = ({ value, finished }) => {
13230 this.zone.run(() => {
13231 value = finished ? val : value;
13232 this.value = valueFormatting({ label: this.label, data: this.data, value });
13233 if (!finished) {
13234 this.value = this.paddedValue(this.value);
13235 }
13236 this.cd.markForCheck();
13237 });
13238 };
13239 this.animationReq = count(0, val, decs, 1, callback);
13240 this.initialized = true;
13241 }
13242 }
13243 scaleText() {
13244 this.zone.run(() => {
13245 const { width, height } = this.textEl.nativeElement.getBoundingClientRect();
13246 if (width === 0 || height === 0) {
13247 return;
13248 }
13249 const textPadding = (this.textPadding[1] = this.textPadding[3] = this.cardWidth / 8);
13250 const availableWidth = this.cardWidth - 2 * textPadding;
13251 const availableHeight = this.cardHeight / 3;
13252 const resizeScale = Math.min(availableWidth / width, availableHeight / height);
13253 this.textFontSize = Math.floor(this.textFontSize * resizeScale);
13254 this.labelFontSize = Math.min(this.textFontSize, 15);
13255 this.setPadding();
13256 this.cd.markForCheck();
13257 });
13258 }
13259 scaleTextSSR() {
13260 const width = calculateTextWidth(VERDANA_FONT_WIDTHS_16_PX, this.value, 10);
13261 const height = 18;
13262 const textPadding = (this.textPadding[1] = this.textPadding[3] = this.cardWidth / 8);
13263 const availableWidth = this.cardWidth - 2 * textPadding;
13264 const availableHeight = this.cardHeight / 3;
13265 const resizeScale = Math.min(availableWidth / width, availableHeight / height);
13266 this.textFontSize = Math.floor(this.textFontSize * resizeScale);
13267 this.labelFontSize = Math.min(this.textFontSize, 15);
13268 this.setPadding();
13269 }
13270 setPadding() {
13271 this.textPadding[1] = this.textPadding[3] = this.cardWidth / 8;
13272 const padding = this.cardHeight / 2;
13273 this.textPadding[0] = padding - this.textFontSize - this.labelFontSize / 2;
13274 this.textPadding[2] = padding - this.labelFontSize;
13275 }
13276 onClick() {
13277 this.select.emit(this.data);
13278 }
13279}
13280CardComponent.decorators = [
13281 { type: Component, args: [{
13282 selector: 'g[ngx-charts-card]',
13283 template: `
13284 <svg:g [attr.transform]="transform" class="cell" (click)="onClick()">
13285 <svg:rect class="card" [style.fill]="color" [attr.width]="cardWidth" [attr.height]="cardHeight" rx="3" ry="3" />
13286 <svg:path
13287 *ngIf="bandColor && bandColor !== color"
13288 class="card-band"
13289 [attr.fill]="bandColor"
13290 [attr.transform]="transformBand"
13291 stroke="none"
13292 [attr.d]="bandPath"
13293 />
13294 <title>{{ label }}</title>
13295 <svg:foreignObject
13296 class="trimmed-label"
13297 x="5"
13298 [attr.x]="textPadding[3]"
13299 [attr.y]="cardHeight - textPadding[2]"
13300 [attr.width]="textWidth"
13301 [attr.height]="labelFontSize + textPadding[2]"
13302 alignment-baseline="hanging"
13303 >
13304 <xhtml:p
13305 [style.color]="textColor"
13306 [style.fontSize.px]="labelFontSize"
13307 [style.lineHeight.px]="labelFontSize"
13308 [innerHTML]="formattedLabel"
13309 >
13310 </xhtml:p>
13311 </svg:foreignObject>
13312 <svg:text
13313 #textEl
13314 class="value-text"
13315 [attr.x]="textPadding[3]"
13316 [attr.y]="textPadding[0]"
13317 [style.fill]="textColor"
13318 text-anchor="start"
13319 alignment-baseline="hanging"
13320 [style.font-size.pt]="textFontSize"
13321 >
13322 {{ value }}
13323 </svg:text>
13324 </svg:g>
13325 `,
13326 changeDetection: ChangeDetectionStrategy.OnPush
13327 },] }
13328];
13329CardComponent.ctorParameters = () => [
13330 { type: ElementRef },
13331 { type: ChangeDetectorRef },
13332 { type: NgZone },
13333 { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
13334];
13335CardComponent.propDecorators = {
13336 color: [{ type: Input }],
13337 bandColor: [{ type: Input }],
13338 textColor: [{ type: Input }],
13339 x: [{ type: Input }],
13340 y: [{ type: Input }],
13341 width: [{ type: Input }],
13342 height: [{ type: Input }],
13343 label: [{ type: Input }],
13344 data: [{ type: Input }],
13345 medianSize: [{ type: Input }],
13346 valueFormatting: [{ type: Input }],
13347 labelFormatting: [{ type: Input }],
13348 animations: [{ type: Input }],
13349 select: [{ type: Output }],
13350 textEl: [{ type: ViewChild, args: ['textEl', { static: false },] }]
13351};
13352
13353/**
13354 * Converts a hex to RGB
13355 *
13356 * @export
13357 */
13358function hexToRgb(value) {
13359 // deprecated, use d3.color()
13360 return d3_color.rgb(value);
13361}
13362/**
13363 * Accepts a color (string) and returns a inverted hex color (string)
13364 * http://stackoverflow.com/questions/9600295/automatically-change-text-color-to-assure-readability
13365 *
13366 * @export
13367 */
13368function invertColor(value) {
13369 const color = d3_color.rgb(value);
13370 const { r, g, b, opacity } = color;
13371 if (opacity === 0) {
13372 return color.toString();
13373 }
13374 const yiq = (r * 299 + g * 587 + b * 114) / 1000;
13375 const depth = yiq >= 128 ? -0.8 : 0.8;
13376 return shadeRGBColor(color, depth);
13377}
13378/**
13379 * Given a rgb, it will darken/lighten
13380 * http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
13381 *
13382 * @export
13383 * @param \{ r, g, b }
13384 */
13385function shadeRGBColor({ r, g, b }, percent) {
13386 const t = percent < 0 ? 0 : 255;
13387 const p = percent < 0 ? percent * -1 : percent;
13388 r = Math.round((t - r) * p) + r;
13389 g = Math.round((t - g) * p) + g;
13390 b = Math.round((t - b) * p) + b;
13391 return `rgb(${r}, ${g}, ${b})`;
13392}
13393
13394class CardSeriesComponent {
13395 constructor() {
13396 this.innerPadding = 15;
13397 this.emptyColor = 'rgba(0, 0, 0, 0)';
13398 this.animations = true;
13399 this.select = new EventEmitter();
13400 }
13401 ngOnChanges(changes) {
13402 this.update();
13403 }
13404 update() {
13405 if (this.data.length > 2) {
13406 const valueFormatting = this.valueFormatting || (card => card.value.toLocaleString());
13407 const sortedLengths = this.data
13408 .map(d => {
13409 const hasValue = d && d.data && typeof d.data.value !== 'undefined' && d.data.value !== null;
13410 return hasValue
13411 ? valueFormatting({
13412 data: d.data,
13413 label: d ? d.data.name : '',
13414 value: d && d.data ? d.data.value : ''
13415 }).length
13416 : 0;
13417 })
13418 .sort((a, b) => b - a);
13419 const idx = Math.ceil(this.data.length / 2);
13420 this.medianSize = sortedLengths[idx];
13421 }
13422 const cards = this.getCards();
13423 this.cards = cards.filter(d => d.data.value !== null);
13424 this.emptySlots = cards.filter(d => d.data.value === null);
13425 }
13426 getCards() {
13427 const yPadding = typeof this.innerPadding === 'number' ? this.innerPadding : this.innerPadding[0] + this.innerPadding[2];
13428 const xPadding = typeof this.innerPadding === 'number' ? this.innerPadding : this.innerPadding[1] + this.innerPadding[3];
13429 return this.data.map((d, index) => {
13430 let label = d.data.name;
13431 if (label && label.constructor.name === 'Date') {
13432 label = label.toLocaleDateString();
13433 }
13434 else {
13435 label = label ? label.toLocaleString() : label;
13436 }
13437 const value = d.data.value;
13438 const valueColor = label ? this.colors.getColor(label) : this.emptyColor;
13439 const color = this.cardColor || valueColor || '#000';
13440 return {
13441 x: d.x,
13442 y: d.y,
13443 width: d.width - xPadding,
13444 height: d.height - yPadding,
13445 color,
13446 bandColor: this.bandColor || valueColor,
13447 textColor: this.textColor || invertColor(color),
13448 label,
13449 data: d.data,
13450 tooltipText: `${label}: ${value}`
13451 };
13452 });
13453 }
13454 trackBy(index, card) {
13455 return card.label;
13456 }
13457 onClick(data) {
13458 this.select.emit(data);
13459 }
13460}
13461CardSeriesComponent.decorators = [
13462 { type: Component, args: [{
13463 selector: 'g[ngx-charts-card-series]',
13464 template: `
13465 <svg:rect
13466 *ngFor="let c of emptySlots; trackBy: trackBy"
13467 class="card-empty"
13468 [attr.x]="c.x"
13469 [attr.y]="c.y"
13470 [style.fill]="emptyColor"
13471 [attr.width]="c.width"
13472 [attr.height]="c.height"
13473 rx="3"
13474 ry="3"
13475 />
13476 <svg:g
13477 ngx-charts-card
13478 *ngFor="let c of cards; trackBy: trackBy"
13479 [x]="c.x"
13480 [y]="c.y"
13481 [width]="c.width"
13482 [height]="c.height"
13483 [color]="c.color"
13484 [bandColor]="c.bandColor"
13485 [textColor]="c.textColor"
13486 [data]="c.data"
13487 [label]="c.label"
13488 [medianSize]="medianSize"
13489 [valueFormatting]="valueFormatting"
13490 [labelFormatting]="labelFormatting"
13491 [animations]="animations"
13492 (select)="onClick($event)"
13493 />
13494 `,
13495 changeDetection: ChangeDetectionStrategy.OnPush
13496 },] }
13497];
13498CardSeriesComponent.propDecorators = {
13499 data: [{ type: Input }],
13500 dims: [{ type: Input }],
13501 colors: [{ type: Input }],
13502 innerPadding: [{ type: Input }],
13503 cardColor: [{ type: Input }],
13504 bandColor: [{ type: Input }],
13505 emptyColor: [{ type: Input }],
13506 textColor: [{ type: Input }],
13507 valueFormatting: [{ type: Input }],
13508 labelFormatting: [{ type: Input }],
13509 animations: [{ type: Input }],
13510 select: [{ type: Output }]
13511};
13512
13513class NumberCardComponent extends BaseChartComponent {
13514 constructor() {
13515 super(...arguments);
13516 this.emptyColor = 'rgba(0, 0, 0, 0)';
13517 this.innerPadding = 15;
13518 this.margin = [10, 10, 10, 10];
13519 }
13520 get clickable() {
13521 return !!this.select.observers.length;
13522 }
13523 update() {
13524 super.update();
13525 this.dims = calculateViewDimensions({
13526 width: this.width,
13527 height: this.height,
13528 margins: this.margin
13529 });
13530 this.formatDates();
13531 this.domain = this.getDomain();
13532 this.setColors();
13533 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
13534 const size = gridSize(this.dims, this.results.length, 150);
13535 const N = size[0] * size[1];
13536 const data = this.results.slice();
13537 while (data.length < N) {
13538 data.push({ value: null });
13539 }
13540 this.data = gridLayout(this.dims, data, 150, this.designatedTotal);
13541 }
13542 getDomain() {
13543 return this.results.map(d => d.label);
13544 }
13545 onClick(data) {
13546 this.select.emit(data);
13547 }
13548 setColors() {
13549 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
13550 }
13551}
13552NumberCardComponent.decorators = [
13553 { type: Component, args: [{
13554 selector: 'ngx-charts-number-card',
13555 template: `
13556 <ngx-charts-chart [view]="[width, height]" [showLegend]="false" [animations]="animations">
13557 <svg:g [attr.transform]="transform" class="number-card chart" [class.clickable]="clickable">
13558 <svg:g
13559 ngx-charts-card-series
13560 [colors]="colors"
13561 [cardColor]="cardColor"
13562 [bandColor]="bandColor"
13563 [textColor]="textColor"
13564 [emptyColor]="emptyColor"
13565 [data]="data"
13566 [dims]="dims"
13567 [innerPadding]="innerPadding"
13568 [valueFormatting]="valueFormatting"
13569 [labelFormatting]="labelFormatting"
13570 [animations]="animations"
13571 (select)="onClick($event)"
13572 />
13573 </svg:g>
13574 </ngx-charts-chart>
13575 `,
13576 encapsulation: ViewEncapsulation.None,
13577 changeDetection: ChangeDetectionStrategy.OnPush,
13578 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", "ngx-charts-number-card .cell .trimmed-label{font-size:12px;pointer-events:none;overflow:hidden;text-align:left;line-height:1em}ngx-charts-number-card .cell .trimmed-label p{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;width:100%;padding:0;margin:0}ngx-charts-number-card .cell .value-text{pointer-events:none}ngx-charts-number-card .number-card.clickable .cell .card,ngx-charts-number-card .number-card.clickable .cell .card-band{cursor:pointer}\n"]
13579 },] }
13580];
13581NumberCardComponent.propDecorators = {
13582 cardColor: [{ type: Input }],
13583 bandColor: [{ type: Input }],
13584 emptyColor: [{ type: Input }],
13585 innerPadding: [{ type: Input }],
13586 textColor: [{ type: Input }],
13587 valueFormatting: [{ type: Input }],
13588 labelFormatting: [{ type: Input }],
13589 designatedTotal: [{ type: Input }]
13590};
13591
13592class NumberCardModule {
13593}
13594NumberCardModule.decorators = [
13595 { type: NgModule, args: [{
13596 imports: [ChartCommonModule],
13597 declarations: [CardComponent, CardSeriesComponent, NumberCardComponent],
13598 exports: [CardComponent, CardSeriesComponent, NumberCardComponent]
13599 },] }
13600];
13601
13602class TreeMapCellComponent {
13603 constructor(element) {
13604 this.gradient = false;
13605 this.animations = true;
13606 this.select = new EventEmitter();
13607 this.initialized = false;
13608 this.orientation = BarOrientation;
13609 this.element = element.nativeElement;
13610 }
13611 ngOnChanges() {
13612 this.update();
13613 this.valueFormatting = this.valueFormatting || (value => value.toLocaleString());
13614 const labelFormatting = this.labelFormatting || (cell => escapeLabel(trimLabel(cell.label, 55)));
13615 const cellData = {
13616 data: this.data,
13617 label: this.label,
13618 value: this.value
13619 };
13620 this.formattedValue = this.valueFormatting(cellData.value);
13621 this.formattedLabel = labelFormatting(cellData);
13622 this.gradientId = 'grad' + id().toString();
13623 this.gradientUrl = `url(#${this.gradientId})`;
13624 this.gradientStops = this.getGradientStops();
13625 }
13626 update() {
13627 if (this.initialized) {
13628 this.animateToCurrentForm();
13629 }
13630 else {
13631 if (this.animations) {
13632 this.loadAnimation();
13633 }
13634 this.initialized = true;
13635 }
13636 }
13637 loadAnimation() {
13638 const node = select(this.element).select('.cell');
13639 node.attr('opacity', 0).attr('x', this.x).attr('y', this.y);
13640 this.animateToCurrentForm();
13641 }
13642 getTextColor() {
13643 return invertColor(this.fill);
13644 }
13645 animateToCurrentForm() {
13646 const node = select(this.element).select('.cell');
13647 if (this.animations) {
13648 node
13649 .transition()
13650 .duration(750)
13651 .attr('opacity', 1)
13652 .attr('x', this.x)
13653 .attr('y', this.y)
13654 .attr('width', this.width)
13655 .attr('height', this.height);
13656 }
13657 else {
13658 node.attr('opacity', 1).attr('x', this.x).attr('y', this.y).attr('width', this.width).attr('height', this.height);
13659 }
13660 }
13661 onClick() {
13662 this.select.emit(this.data);
13663 }
13664 getGradientStops() {
13665 return [
13666 {
13667 offset: 0,
13668 color: this.fill,
13669 opacity: 0.3
13670 },
13671 {
13672 offset: 100,
13673 color: this.fill,
13674 opacity: 1
13675 }
13676 ];
13677 }
13678}
13679TreeMapCellComponent.decorators = [
13680 { type: Component, args: [{
13681 selector: 'g[ngx-charts-tree-map-cell]',
13682 template: `
13683 <svg:g>
13684 <defs *ngIf="gradient">
13685 <svg:g
13686 ngx-charts-svg-linear-gradient
13687 [orientation]="orientation.Vertical"
13688 [name]="gradientId"
13689 [stops]="gradientStops"
13690 />
13691 </defs>
13692 <svg:rect
13693 [attr.fill]="gradient ? gradientUrl : fill"
13694 [attr.width]="width"
13695 [attr.height]="height"
13696 [attr.x]="x"
13697 [attr.y]="y"
13698 class="cell"
13699 (click)="onClick()"
13700 />
13701 <svg:foreignObject
13702 *ngIf="width >= 70 && height >= 35"
13703 [attr.x]="x"
13704 [attr.y]="y"
13705 [attr.width]="width"
13706 [attr.height]="height"
13707 class="treemap-label"
13708 [style.pointer-events]="'none'"
13709 >
13710 <xhtml:p [style.color]="getTextColor()" [style.height]="height + 'px'" [style.width]="width + 'px'">
13711 <xhtml:span class="treemap-label" [innerHTML]="formattedLabel"> </xhtml:span>
13712 <xhtml:br />
13713 <xhtml:span
13714 *ngIf="animations"
13715 class="treemap-val"
13716 ngx-charts-count-up
13717 [countTo]="value"
13718 [valueFormatting]="valueFormatting"
13719 >
13720 </xhtml:span>
13721 <xhtml:span *ngIf="!animations" class="treemap-val">
13722 {{ formattedValue }}
13723 </xhtml:span>
13724 </xhtml:p>
13725 </svg:foreignObject>
13726 </svg:g>
13727 `,
13728 changeDetection: ChangeDetectionStrategy.OnPush
13729 },] }
13730];
13731TreeMapCellComponent.ctorParameters = () => [
13732 { type: ElementRef }
13733];
13734TreeMapCellComponent.propDecorators = {
13735 data: [{ type: Input }],
13736 fill: [{ type: Input }],
13737 x: [{ type: Input }],
13738 y: [{ type: Input }],
13739 width: [{ type: Input }],
13740 height: [{ type: Input }],
13741 label: [{ type: Input }],
13742 value: [{ type: Input }],
13743 valueFormatting: [{ type: Input }],
13744 labelFormatting: [{ type: Input }],
13745 gradient: [{ type: Input }],
13746 animations: [{ type: Input }],
13747 select: [{ type: Output }]
13748};
13749
13750class TreeMapCellSeriesComponent {
13751 constructor() {
13752 this.gradient = false;
13753 this.tooltipDisabled = false;
13754 this.animations = true;
13755 this.select = new EventEmitter();
13756 this.styleTypes = StyleTypes;
13757 this.placementTypes = PlacementTypes;
13758 }
13759 ngOnChanges(changes) {
13760 this.cells = this.getCells();
13761 }
13762 getCells() {
13763 return this.data.children
13764 .filter(d => {
13765 return d.depth === 1;
13766 })
13767 .map((d, index) => {
13768 const label = d.id;
13769 return {
13770 data: d.data,
13771 x: d.x0,
13772 y: d.y0,
13773 width: d.x1 - d.x0,
13774 height: d.y1 - d.y0,
13775 fill: this.colors.getColor(label),
13776 label,
13777 value: d.value
13778 };
13779 });
13780 }
13781 getTooltipText({ label, value }) {
13782 return `
13783 <span class="tooltip-label">${escapeLabel(label)}</span>
13784 <span class="tooltip-val">${value.toLocaleString()}</span>
13785 `;
13786 }
13787 onClick(data) {
13788 this.select.emit(data);
13789 }
13790 trackBy(index, item) {
13791 return item.label;
13792 }
13793}
13794TreeMapCellSeriesComponent.decorators = [
13795 { type: Component, args: [{
13796 selector: 'g[ngx-charts-tree-map-cell-series]',
13797 template: `
13798 <svg:g
13799 ngx-charts-tree-map-cell
13800 *ngFor="let c of cells; trackBy: trackBy"
13801 [data]="c.data"
13802 [x]="c.x"
13803 [y]="c.y"
13804 [width]="c.width"
13805 [height]="c.height"
13806 [fill]="c.fill"
13807 [label]="c.label"
13808 [value]="c.value"
13809 [valueFormatting]="valueFormatting"
13810 [labelFormatting]="labelFormatting"
13811 [gradient]="gradient"
13812 [animations]="animations"
13813 (select)="onClick($event)"
13814 ngx-tooltip
13815 [tooltipDisabled]="tooltipDisabled"
13816 [tooltipPlacement]="placementTypes.Top"
13817 [tooltipType]="styleTypes.tooltip"
13818 [tooltipTitle]="tooltipTemplate ? undefined : getTooltipText(c)"
13819 [tooltipTemplate]="tooltipTemplate"
13820 [tooltipContext]="c.data"
13821 ></svg:g>
13822 `,
13823 changeDetection: ChangeDetectionStrategy.OnPush
13824 },] }
13825];
13826TreeMapCellSeriesComponent.propDecorators = {
13827 data: [{ type: Input }],
13828 dims: [{ type: Input }],
13829 colors: [{ type: Input }],
13830 valueFormatting: [{ type: Input }],
13831 labelFormatting: [{ type: Input }],
13832 gradient: [{ type: Input }],
13833 tooltipDisabled: [{ type: Input }],
13834 tooltipTemplate: [{ type: Input }],
13835 animations: [{ type: Input }],
13836 select: [{ type: Output }]
13837};
13838
13839class TreeMapComponent extends BaseChartComponent {
13840 constructor() {
13841 super(...arguments);
13842 this.tooltipDisabled = false;
13843 this.gradient = false;
13844 this.select = new EventEmitter();
13845 this.margin = [10, 10, 10, 10];
13846 }
13847 update() {
13848 super.update();
13849 this.dims = calculateViewDimensions({
13850 width: this.width,
13851 height: this.height,
13852 margins: this.margin
13853 });
13854 this.domain = this.getDomain();
13855 this.treemap = treemap().size([this.dims.width, this.dims.height]);
13856 const rootNode = {
13857 name: 'root',
13858 value: 0,
13859 isRoot: true
13860 };
13861 const root = stratify()
13862 .id(d => {
13863 let label = d.name;
13864 if (label.constructor.name === 'Date') {
13865 label = label.toLocaleDateString();
13866 }
13867 else {
13868 label = label.toLocaleString();
13869 }
13870 return label;
13871 })
13872 .parentId(d => (d.isRoot ? null : 'root'))([rootNode, ...this.results])
13873 .sum(d => d.value);
13874 this.data = this.treemap(root);
13875 this.setColors();
13876 this.transform = `translate(${this.dims.xOffset} , ${this.margin[0]})`;
13877 }
13878 getDomain() {
13879 return this.results.map(d => d.name);
13880 }
13881 onClick(data) {
13882 this.select.emit(data);
13883 }
13884 setColors() {
13885 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
13886 }
13887}
13888TreeMapComponent.decorators = [
13889 { type: Component, args: [{
13890 selector: 'ngx-charts-tree-map',
13891 template: `
13892 <ngx-charts-chart [view]="[width, height]" [showLegend]="false" [animations]="animations">
13893 <svg:g [attr.transform]="transform" class="tree-map chart">
13894 <svg:g
13895 ngx-charts-tree-map-cell-series
13896 [colors]="colors"
13897 [data]="data"
13898 [dims]="dims"
13899 [tooltipDisabled]="tooltipDisabled"
13900 [tooltipTemplate]="tooltipTemplate"
13901 [valueFormatting]="valueFormatting"
13902 [labelFormatting]="labelFormatting"
13903 [gradient]="gradient"
13904 [animations]="animations"
13905 (select)="onClick($event)"
13906 />
13907 </svg:g>
13908 </ngx-charts-chart>
13909 `,
13910 encapsulation: ViewEncapsulation.None,
13911 changeDetection: ChangeDetectionStrategy.OnPush,
13912 styles: [".tree-map .treemap-val{font-size:1.3em;padding-top:5px;display:inline-block}.tree-map .treemap-label p{display:table-cell;text-align:center;line-height:1.2em;vertical-align:middle}\n"]
13913 },] }
13914];
13915TreeMapComponent.propDecorators = {
13916 results: [{ type: Input }],
13917 tooltipDisabled: [{ type: Input }],
13918 valueFormatting: [{ type: Input }],
13919 labelFormatting: [{ type: Input }],
13920 gradient: [{ type: Input }],
13921 select: [{ type: Output }],
13922 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }]
13923};
13924
13925class TreeMapModule {
13926}
13927TreeMapModule.decorators = [
13928 { type: NgModule, args: [{
13929 imports: [ChartCommonModule],
13930 declarations: [TreeMapCellComponent, TreeMapCellSeriesComponent, TreeMapComponent],
13931 exports: [TreeMapCellComponent, TreeMapCellSeriesComponent, TreeMapComponent]
13932 },] }
13933];
13934
13935var ElementType;
13936(function (ElementType) {
13937 ElementType["Value"] = "value";
13938 ElementType["Units"] = "units";
13939})(ElementType || (ElementType = {}));
13940class LinearGaugeComponent extends BaseChartComponent {
13941 constructor() {
13942 super(...arguments);
13943 this.min = 0;
13944 this.max = 100;
13945 this.value = 0;
13946 this.margin = [10, 20, 10, 20];
13947 this.valueResizeScale = 1;
13948 this.unitsResizeScale = 1;
13949 this.valueTextTransform = '';
13950 this.valueTranslate = '';
13951 this.unitsTextTransform = '';
13952 this.unitsTranslate = '';
13953 this.barOrientation = BarOrientation;
13954 }
13955 ngAfterViewInit() {
13956 super.ngAfterViewInit();
13957 setTimeout(() => {
13958 this.scaleText(ElementType.Value);
13959 this.scaleText(ElementType.Units);
13960 });
13961 }
13962 update() {
13963 super.update();
13964 this.hasPreviousValue = this.previousValue !== undefined;
13965 this.max = Math.max(this.max, this.value);
13966 this.min = Math.min(this.min, this.value);
13967 if (this.hasPreviousValue) {
13968 this.max = Math.max(this.max, this.previousValue);
13969 this.min = Math.min(this.min, this.previousValue);
13970 }
13971 this.dims = calculateViewDimensions({
13972 width: this.width,
13973 height: this.height,
13974 margins: this.margin
13975 });
13976 this.valueDomain = this.getValueDomain();
13977 this.valueScale = this.getValueScale();
13978 this.displayValue = this.getDisplayValue();
13979 this.setColors();
13980 const xOffset = this.margin[3] + this.dims.width / 2;
13981 const yOffset = this.margin[0] + this.dims.height / 2;
13982 this.transform = `translate(${xOffset}, ${yOffset})`;
13983 this.transformLine = `translate(${this.margin[3] + this.valueScale(this.previousValue)}, ${yOffset})`;
13984 this.valueTranslate = `translate(0, -15)`;
13985 this.unitsTranslate = `translate(0, 15)`;
13986 if (isPlatformServer(this.platformId)) {
13987 this.scaleTextSSR('value');
13988 this.scaleTextSSR('units');
13989 }
13990 else {
13991 setTimeout(() => this.scaleText(ElementType.Value), 50);
13992 setTimeout(() => this.scaleText(ElementType.Units), 50);
13993 }
13994 }
13995 getValueDomain() {
13996 return [this.min, this.max];
13997 }
13998 getValueScale() {
13999 return scaleLinear().range([0, this.dims.width]).domain(this.valueDomain);
14000 }
14001 getDisplayValue() {
14002 if (this.valueFormatting) {
14003 return this.valueFormatting(this.value);
14004 }
14005 return this.value.toLocaleString();
14006 }
14007 scaleText(element, repeat = true) {
14008 let el;
14009 let resizeScale;
14010 if (element === ElementType.Value) {
14011 el = this.valueTextEl;
14012 resizeScale = this.valueResizeScale;
14013 }
14014 else {
14015 el = this.unitsTextEl;
14016 resizeScale = this.unitsResizeScale;
14017 }
14018 const { width, height } = el.nativeElement.getBoundingClientRect();
14019 if (width === 0 || height === 0)
14020 return;
14021 const oldScale = resizeScale;
14022 const availableWidth = this.dims.width;
14023 const availableHeight = Math.max(this.dims.height / 2 - 15, 0);
14024 const resizeScaleWidth = Math.floor((availableWidth / (width / resizeScale)) * 100) / 100;
14025 const resizeScaleHeight = Math.floor((availableHeight / (height / resizeScale)) * 100) / 100;
14026 resizeScale = Math.min(resizeScaleHeight, resizeScaleWidth);
14027 if (resizeScale !== oldScale) {
14028 if (element === ElementType.Value) {
14029 this.valueResizeScale = resizeScale;
14030 this.valueTextTransform = `scale(${resizeScale}, ${resizeScale})`;
14031 }
14032 else {
14033 this.unitsResizeScale = resizeScale;
14034 this.unitsTextTransform = `scale(${resizeScale}, ${resizeScale})`;
14035 }
14036 this.cd.markForCheck();
14037 if (repeat && isPlatformBrowser(this.platformId)) {
14038 setTimeout(() => {
14039 this.scaleText(element, false);
14040 }, 50);
14041 }
14042 }
14043 }
14044 scaleTextSSR(element) {
14045 let resizeScale = 1;
14046 const value = element === 'value' ? this.displayValue : this.units;
14047 const width = calculateTextWidth(VERDANA_FONT_WIDTHS_16_PX, value, 10);
14048 const height = 25;
14049 const availableWidth = this.dims.width;
14050 const availableHeight = Math.max(this.dims.height / 2 - 15, 0);
14051 const resizeScaleWidth = Math.floor((availableWidth / (width / resizeScale)) * 100) / 100;
14052 const resizeScaleHeight = Math.floor((availableHeight / (height / resizeScale)) * 100) / 100;
14053 resizeScale = Math.min(resizeScaleHeight, resizeScaleWidth);
14054 if (element === 'value') {
14055 this.valueResizeScale = resizeScale;
14056 this.valueTextTransform = `scale(${resizeScale}, ${resizeScale})`;
14057 }
14058 else {
14059 this.unitsResizeScale = resizeScale;
14060 this.unitsTextTransform = `scale(${resizeScale}, ${resizeScale})`;
14061 }
14062 this.cd.markForCheck();
14063 }
14064 onClick() {
14065 this.select.emit({
14066 name: 'Value',
14067 value: this.value
14068 });
14069 }
14070 setColors() {
14071 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, [this.value], this.customColors);
14072 }
14073}
14074LinearGaugeComponent.decorators = [
14075 { type: Component, args: [{
14076 selector: 'ngx-charts-linear-gauge',
14077 template: `
14078 <ngx-charts-chart [view]="[width, height]" [showLegend]="false" [animations]="animations" (click)="onClick()">
14079 <svg:g class="linear-gauge chart">
14080 <svg:g
14081 ngx-charts-bar
14082 class="background-bar"
14083 [width]="dims.width"
14084 [height]="3"
14085 [x]="margin[3]"
14086 [y]="dims.height / 2 + margin[0] - 2"
14087 [data]="{}"
14088 [orientation]="barOrientation.Horizontal"
14089 [roundEdges]="true"
14090 [animations]="animations"
14091 ></svg:g>
14092 <svg:g
14093 ngx-charts-bar
14094 [width]="valueScale(value)"
14095 [height]="3"
14096 [x]="margin[3]"
14097 [y]="dims.height / 2 + margin[0] - 2"
14098 [fill]="colors.getColor(units)"
14099 [data]="{}"
14100 [orientation]="barOrientation.Horizontal"
14101 [roundEdges]="true"
14102 [animations]="animations"
14103 ></svg:g>
14104
14105 <svg:line
14106 *ngIf="hasPreviousValue"
14107 [attr.transform]="transformLine"
14108 x1="0"
14109 y1="5"
14110 x2="0"
14111 y2="15"
14112 [attr.stroke]="colors.getColor(units)"
14113 />
14114
14115 <svg:line
14116 *ngIf="hasPreviousValue"
14117 [attr.transform]="transformLine"
14118 x1="0"
14119 y1="-5"
14120 x2="0"
14121 y2="-15"
14122 [attr.stroke]="colors.getColor(units)"
14123 />
14124
14125 <svg:g [attr.transform]="transform">
14126 <svg:g [attr.transform]="valueTranslate">
14127 <svg:text
14128 #valueTextEl
14129 class="value"
14130 [style.textAnchor]="'middle'"
14131 [attr.transform]="valueTextTransform"
14132 alignment-baseline="after-edge"
14133 >
14134 {{ displayValue }}
14135 </svg:text>
14136 </svg:g>
14137
14138 <svg:g [attr.transform]="unitsTranslate">
14139 <svg:text
14140 #unitsTextEl
14141 class="units"
14142 [style.textAnchor]="'middle'"
14143 [attr.transform]="unitsTextTransform"
14144 alignment-baseline="before-edge"
14145 >
14146 {{ units }}
14147 </svg:text>
14148 </svg:g>
14149 </svg:g>
14150 </svg:g>
14151 </ngx-charts-chart>
14152 `,
14153 encapsulation: ViewEncapsulation.None,
14154 changeDetection: ChangeDetectionStrategy.OnPush,
14155 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".linear-gauge{cursor:pointer}.linear-gauge .background-bar path{fill:#0000000d}.linear-gauge .units{fill:#666}\n"]
14156 },] }
14157];
14158LinearGaugeComponent.propDecorators = {
14159 min: [{ type: Input }],
14160 max: [{ type: Input }],
14161 value: [{ type: Input }],
14162 units: [{ type: Input }],
14163 previousValue: [{ type: Input }],
14164 valueFormatting: [{ type: Input }],
14165 valueTextEl: [{ type: ViewChild, args: ['valueTextEl',] }],
14166 unitsTextEl: [{ type: ViewChild, args: ['unitsTextEl',] }]
14167};
14168
14169class GaugeComponent extends BaseChartComponent {
14170 constructor() {
14171 super(...arguments);
14172 this.legend = false;
14173 this.legendTitle = 'Legend';
14174 this.legendPosition = LegendPosition.Right;
14175 this.min = 0;
14176 this.max = 100;
14177 this.bigSegments = 10;
14178 this.smallSegments = 5;
14179 this.showAxis = true;
14180 this.startAngle = -120;
14181 this.angleSpan = 240;
14182 this.activeEntries = [];
14183 this.tooltipDisabled = false;
14184 this.showText = true;
14185 this.activate = new EventEmitter();
14186 this.deactivate = new EventEmitter();
14187 this.resizeScale = 1;
14188 this.rotation = '';
14189 this.textTransform = 'scale(1, 1)';
14190 this.cornerRadius = 10;
14191 }
14192 ngAfterViewInit() {
14193 super.ngAfterViewInit();
14194 setTimeout(() => this.scaleText());
14195 }
14196 update() {
14197 super.update();
14198 if (!this.showAxis) {
14199 if (!this.margin) {
14200 this.margin = [10, 20, 10, 20];
14201 }
14202 }
14203 else {
14204 if (!this.margin) {
14205 this.margin = [60, 100, 60, 100];
14206 }
14207 }
14208 // make the starting angle positive
14209 if (this.startAngle < 0) {
14210 this.startAngle = (this.startAngle % 360) + 360;
14211 }
14212 this.angleSpan = Math.min(this.angleSpan, 360);
14213 this.dims = calculateViewDimensions({
14214 width: this.width,
14215 height: this.height,
14216 margins: this.margin,
14217 showLegend: this.legend,
14218 legendPosition: this.legendPosition
14219 });
14220 this.domain = this.getDomain();
14221 this.valueDomain = this.getValueDomain();
14222 this.valueScale = this.getValueScale();
14223 this.displayValue = this.getDisplayValue();
14224 this.outerRadius = Math.min(this.dims.width, this.dims.height) / 2;
14225 this.arcs = this.getArcs();
14226 this.setColors();
14227 this.legendOptions = this.getLegendOptions();
14228 const xOffset = this.margin[3] + this.dims.width / 2;
14229 const yOffset = this.margin[0] + this.dims.height / 2;
14230 this.transform = `translate(${xOffset}, ${yOffset})`;
14231 this.rotation = `rotate(${this.startAngle})`;
14232 setTimeout(() => this.scaleText(), 50);
14233 }
14234 getArcs() {
14235 const arcs = [];
14236 const availableRadius = this.outerRadius * 0.7;
14237 const radiusPerArc = Math.min(availableRadius / this.results.length, 10);
14238 const arcWidth = radiusPerArc * 0.7;
14239 this.textRadius = this.outerRadius - this.results.length * radiusPerArc;
14240 this.cornerRadius = Math.floor(arcWidth / 2);
14241 let i = 0;
14242 for (const d of this.results) {
14243 const outerRadius = this.outerRadius - i * radiusPerArc;
14244 const innerRadius = outerRadius - arcWidth;
14245 const backgroundArc = {
14246 endAngle: (this.angleSpan * Math.PI) / 180,
14247 innerRadius,
14248 outerRadius,
14249 data: {
14250 value: this.max,
14251 name: d.name
14252 }
14253 };
14254 const valueArc = {
14255 endAngle: (Math.min(this.valueScale(d.value), this.angleSpan) * Math.PI) / 180,
14256 innerRadius,
14257 outerRadius,
14258 data: {
14259 value: d.value,
14260 name: d.name
14261 }
14262 };
14263 const arc = {
14264 backgroundArc,
14265 valueArc
14266 };
14267 arcs.push(arc);
14268 i++;
14269 }
14270 return arcs;
14271 }
14272 getDomain() {
14273 return this.results.map(d => d.name);
14274 }
14275 getValueDomain() {
14276 const values = this.results.map(d => d.value);
14277 const dataMin = Math.min(...values);
14278 const dataMax = Math.max(...values);
14279 if (this.min !== undefined) {
14280 this.min = Math.min(this.min, dataMin);
14281 }
14282 else {
14283 this.min = dataMin;
14284 }
14285 if (this.max !== undefined) {
14286 this.max = Math.max(this.max, dataMax);
14287 }
14288 else {
14289 this.max = dataMax;
14290 }
14291 return [this.min, this.max];
14292 }
14293 getValueScale() {
14294 return scaleLinear().range([0, this.angleSpan]).nice().domain(this.valueDomain);
14295 }
14296 getDisplayValue() {
14297 const value = this.results.map(d => d.value).reduce((a, b) => a + b, 0);
14298 if (this.textValue && 0 !== this.textValue.length) {
14299 return this.textValue.toLocaleString();
14300 }
14301 if (this.valueFormatting) {
14302 return this.valueFormatting(value);
14303 }
14304 return value.toLocaleString();
14305 }
14306 scaleText(repeat = true) {
14307 if (!this.showText) {
14308 return;
14309 }
14310 const { width } = this.textEl.nativeElement.getBoundingClientRect();
14311 const oldScale = this.resizeScale;
14312 if (width === 0) {
14313 this.resizeScale = 1;
14314 }
14315 else {
14316 const availableSpace = this.textRadius;
14317 this.resizeScale = Math.floor((availableSpace / (width / this.resizeScale)) * 100) / 100;
14318 }
14319 if (this.resizeScale !== oldScale) {
14320 this.textTransform = `scale(${this.resizeScale}, ${this.resizeScale})`;
14321 this.cd.markForCheck();
14322 if (repeat) {
14323 setTimeout(() => this.scaleText(false), 50);
14324 }
14325 }
14326 }
14327 onClick(data) {
14328 this.select.emit(data);
14329 }
14330 getLegendOptions() {
14331 return {
14332 scaleType: ScaleType.Ordinal,
14333 colors: this.colors,
14334 domain: this.domain,
14335 title: this.legendTitle,
14336 position: this.legendPosition
14337 };
14338 }
14339 setColors() {
14340 this.colors = new ColorHelper(this.scheme, ScaleType.Ordinal, this.domain, this.customColors);
14341 }
14342 onActivate(item) {
14343 const idx = this.activeEntries.findIndex(d => {
14344 return d.name === item.name && d.value === item.value;
14345 });
14346 if (idx > -1) {
14347 return;
14348 }
14349 this.activeEntries = [item, ...this.activeEntries];
14350 this.activate.emit({ value: item, entries: this.activeEntries });
14351 }
14352 onDeactivate(item) {
14353 const idx = this.activeEntries.findIndex(d => {
14354 return d.name === item.name && d.value === item.value;
14355 });
14356 this.activeEntries.splice(idx, 1);
14357 this.activeEntries = [...this.activeEntries];
14358 this.deactivate.emit({ value: item, entries: this.activeEntries });
14359 }
14360 isActive(entry) {
14361 if (!this.activeEntries)
14362 return false;
14363 const item = this.activeEntries.find(d => {
14364 return entry.name === d.name && entry.series === d.series;
14365 });
14366 return item !== undefined;
14367 }
14368 trackBy(index, item) {
14369 return item.valueArc.data.name;
14370 }
14371}
14372GaugeComponent.decorators = [
14373 { type: Component, args: [{
14374 selector: 'ngx-charts-gauge',
14375 template: `
14376 <ngx-charts-chart
14377 [view]="[width, height]"
14378 [showLegend]="legend"
14379 [legendOptions]="legendOptions"
14380 [activeEntries]="activeEntries"
14381 [animations]="animations"
14382 (legendLabelClick)="onClick($event)"
14383 (legendLabelActivate)="onActivate($event)"
14384 (legendLabelDeactivate)="onDeactivate($event)"
14385 >
14386 <svg:g [attr.transform]="transform" class="gauge chart">
14387 <svg:g *ngFor="let arc of arcs; trackBy: trackBy" [attr.transform]="rotation">
14388 <svg:g
14389 ngx-charts-gauge-arc
14390 [backgroundArc]="arc.backgroundArc"
14391 [valueArc]="arc.valueArc"
14392 [cornerRadius]="cornerRadius"
14393 [colors]="colors"
14394 [isActive]="isActive(arc.valueArc.data)"
14395 [tooltipDisabled]="tooltipDisabled"
14396 [tooltipTemplate]="tooltipTemplate"
14397 [valueFormatting]="valueFormatting"
14398 [animations]="animations"
14399 (select)="onClick($event)"
14400 (activate)="onActivate($event)"
14401 (deactivate)="onDeactivate($event)"
14402 ></svg:g>
14403 </svg:g>
14404
14405 <svg:g
14406 ngx-charts-gauge-axis
14407 *ngIf="showAxis"
14408 [bigSegments]="bigSegments"
14409 [smallSegments]="smallSegments"
14410 [min]="min"
14411 [max]="max"
14412 [radius]="outerRadius"
14413 [angleSpan]="angleSpan"
14414 [valueScale]="valueScale"
14415 [startAngle]="startAngle"
14416 [tickFormatting]="axisTickFormatting"
14417 ></svg:g>
14418
14419 <svg:text
14420 #textEl
14421 *ngIf="showText"
14422 [style.textAnchor]="'middle'"
14423 [attr.transform]="textTransform"
14424 alignment-baseline="central"
14425 >
14426 <tspan x="0" dy="0">{{ displayValue }}</tspan>
14427 <tspan x="0" dy="1.2em">{{ units }}</tspan>
14428 </svg:text>
14429 </svg:g>
14430 </ngx-charts-chart>
14431 `,
14432 encapsulation: ViewEncapsulation.None,
14433 changeDetection: ChangeDetectionStrategy.OnPush,
14434 styles: [".ngx-charts{float:left;overflow:visible}.ngx-charts .circle,.ngx-charts .cell,.ngx-charts .bar,.ngx-charts .arc{cursor:pointer}.ngx-charts .bar.active,.ngx-charts .bar:hover,.ngx-charts .cell.active,.ngx-charts .cell:hover,.ngx-charts .arc.active,.ngx-charts .arc:hover,.ngx-charts .card.active,.ngx-charts .card:hover{opacity:.8;transition:opacity .1s ease-in-out}.ngx-charts .bar:focus,.ngx-charts .cell:focus,.ngx-charts .arc:focus,.ngx-charts .card:focus{outline:none}.ngx-charts .bar.hidden,.ngx-charts .cell.hidden,.ngx-charts .arc.hidden,.ngx-charts .card.hidden{display:none}.ngx-charts g:focus{outline:none}.ngx-charts .line-series.inactive,.ngx-charts .line-series-range.inactive,.ngx-charts .polar-series-path.inactive,.ngx-charts .polar-series-area.inactive,.ngx-charts .area-series.inactive{transition:opacity .1s ease-in-out;opacity:.2}.ngx-charts .line-highlight{display:none}.ngx-charts .line-highlight.active{display:block}.ngx-charts .area{opacity:.6}.ngx-charts .circle:hover{cursor:pointer}.ngx-charts .label{font-size:12px;font-weight:normal}.ngx-charts .tooltip-anchor{fill:#000}.ngx-charts .gridline-path{stroke:#ddd;stroke-width:1;fill:none}.ngx-charts .refline-path{stroke:#a8b2c7;stroke-width:1;stroke-dasharray:5;stroke-dashoffset:5}.ngx-charts .refline-label{font-size:9px}.ngx-charts .reference-area{fill-opacity:.05;fill:#000}.ngx-charts .gridline-path-dotted{stroke:#ddd;stroke-width:1;fill:none;stroke-dasharray:1,20;stroke-dashoffset:3}.ngx-charts .grid-panel rect{fill:none}.ngx-charts .grid-panel.odd rect{fill:#0000000d}\n", ".gauge .background-arc path{fill:#0000000d}.gauge .gauge-tick path{stroke:#666}.gauge .gauge-tick text{font-size:12px;fill:#666;font-weight:bold}.gauge .gauge-tick-large path{stroke-width:2px}.gauge .gauge-tick-small path{stroke-width:1px}\n"]
14435 },] }
14436];
14437GaugeComponent.propDecorators = {
14438 legend: [{ type: Input }],
14439 legendTitle: [{ type: Input }],
14440 legendPosition: [{ type: Input }],
14441 min: [{ type: Input }],
14442 max: [{ type: Input }],
14443 textValue: [{ type: Input }],
14444 units: [{ type: Input }],
14445 bigSegments: [{ type: Input }],
14446 smallSegments: [{ type: Input }],
14447 results: [{ type: Input }],
14448 showAxis: [{ type: Input }],
14449 startAngle: [{ type: Input }],
14450 angleSpan: [{ type: Input }],
14451 activeEntries: [{ type: Input }],
14452 axisTickFormatting: [{ type: Input }],
14453 tooltipDisabled: [{ type: Input }],
14454 valueFormatting: [{ type: Input }],
14455 showText: [{ type: Input }],
14456 margin: [{ type: Input }],
14457 activate: [{ type: Output }],
14458 deactivate: [{ type: Output }],
14459 tooltipTemplate: [{ type: ContentChild, args: ['tooltipTemplate',] }],
14460 textEl: [{ type: ViewChild, args: ['textEl',] }]
14461};
14462
14463class GaugeArcComponent {
14464 constructor() {
14465 this.isActive = false;
14466 this.tooltipDisabled = false;
14467 this.animations = true;
14468 this.select = new EventEmitter();
14469 this.activate = new EventEmitter();
14470 this.deactivate = new EventEmitter();
14471 this.placementTypes = PlacementTypes;
14472 this.styleTypes = StyleTypes;
14473 }
14474 tooltipText(arc) {
14475 const label = formatLabel(arc.data.name);
14476 let val;
14477 if (this.valueFormatting) {
14478 val = this.valueFormatting(arc.data.value);
14479 }
14480 else {
14481 val = formatLabel(arc.data.value);
14482 }
14483 return `
14484 <span class="tooltip-label">${escapeLabel(label)}</span>
14485 <span class="tooltip-val">${val}</span>
14486 `;
14487 }
14488}
14489GaugeArcComponent.decorators = [
14490 { type: Component, args: [{
14491 selector: 'g[ngx-charts-gauge-arc]',
14492 template: `
14493 <svg:g
14494 ngx-charts-pie-arc
14495 class="background-arc"
14496 [startAngle]="0"
14497 [endAngle]="backgroundArc.endAngle"
14498 [innerRadius]="backgroundArc.innerRadius"
14499 [outerRadius]="backgroundArc.outerRadius"
14500 [cornerRadius]="cornerRadius"
14501 [data]="backgroundArc.data"
14502 [animate]="false"
14503 [pointerEvents]="false"
14504 ></svg:g>
14505 <svg:g
14506 ngx-charts-pie-arc
14507 [startAngle]="0"
14508 [endAngle]="valueArc.endAngle"
14509 [innerRadius]="valueArc.innerRadius"
14510 [outerRadius]="valueArc.outerRadius"
14511 [cornerRadius]="cornerRadius"
14512 [fill]="colors.getColor(valueArc.data.name)"
14513 [data]="valueArc.data"
14514 [animate]="animations"
14515 [isActive]="isActive"
14516 (select)="select.emit($event)"
14517 (activate)="activate.emit($event)"
14518 (deactivate)="deactivate.emit($event)"
14519 ngx-tooltip
14520 [tooltipDisabled]="tooltipDisabled"
14521 [tooltipPlacement]="placementTypes.Top"
14522 [tooltipType]="styleTypes.tooltip"
14523 [tooltipTitle]="tooltipTemplate ? undefined : tooltipText(valueArc)"
14524 [tooltipTemplate]="tooltipTemplate"
14525 [tooltipContext]="valueArc.data"
14526 ></svg:g>
14527 `,
14528 changeDetection: ChangeDetectionStrategy.OnPush
14529 },] }
14530];
14531GaugeArcComponent.propDecorators = {
14532 backgroundArc: [{ type: Input }],
14533 valueArc: [{ type: Input }],
14534 cornerRadius: [{ type: Input }],
14535 colors: [{ type: Input }],
14536 isActive: [{ type: Input }],
14537 tooltipDisabled: [{ type: Input }],
14538 valueFormatting: [{ type: Input }],
14539 tooltipTemplate: [{ type: Input }],
14540 animations: [{ type: Input }],
14541 select: [{ type: Output }],
14542 activate: [{ type: Output }],
14543 deactivate: [{ type: Output }]
14544};
14545
14546class GaugeAxisComponent {
14547 constructor() {
14548 this.rotate = '';
14549 }
14550 ngOnChanges(changes) {
14551 this.update();
14552 }
14553 update() {
14554 this.rotationAngle = -90 + this.startAngle;
14555 this.rotate = `rotate(${this.rotationAngle})`;
14556 this.ticks = this.getTicks();
14557 }
14558 getTicks() {
14559 const bigTickSegment = this.angleSpan / this.bigSegments;
14560 const smallTickSegment = bigTickSegment / this.smallSegments;
14561 const tickLength = 20;
14562 const ticks = {
14563 big: [],
14564 small: []
14565 };
14566 const startDistance = this.radius + 10;
14567 const textDist = startDistance + tickLength + 10;
14568 for (let i = 0; i <= this.bigSegments; i++) {
14569 const angleDeg = i * bigTickSegment;
14570 const angle = (angleDeg * Math.PI) / 180;
14571 const textAnchor = this.getTextAnchor(angleDeg);
14572 let skip = false;
14573 if (i === 0 && this.angleSpan === 360) {
14574 skip = true;
14575 }
14576 if (!skip) {
14577 let text = Number.parseFloat(this.valueScale.invert(angleDeg).toString()).toLocaleString();
14578 if (this.tickFormatting) {
14579 text = this.tickFormatting(text);
14580 }
14581 ticks.big.push({
14582 line: this.getTickPath(startDistance, tickLength, angle),
14583 textAnchor,
14584 text,
14585 textTransform: `
14586 translate(${textDist * Math.cos(angle)}, ${textDist * Math.sin(angle)}) rotate(${-this.rotationAngle})
14587 `
14588 });
14589 }
14590 if (i === this.bigSegments) {
14591 continue;
14592 }
14593 for (let j = 1; j <= this.smallSegments; j++) {
14594 const smallAngleDeg = angleDeg + j * smallTickSegment;
14595 const smallAngle = (smallAngleDeg * Math.PI) / 180;
14596 ticks.small.push({
14597 line: this.getTickPath(startDistance, tickLength / 2, smallAngle)
14598 });
14599 }
14600 }
14601 return ticks;
14602 }
14603 getTextAnchor(angle) {
14604 // [0, 45] = 'middle';
14605 // [46, 135] = 'start';
14606 // [136, 225] = 'middle';
14607 // [226, 315] = 'end';
14608 angle = (this.startAngle + angle) % 360;
14609 let textAnchor = TextAnchor.Middle;
14610 if (angle > 45 && angle <= 135) {
14611 textAnchor = TextAnchor.Start;
14612 }
14613 else if (angle > 225 && angle <= 315) {
14614 textAnchor = TextAnchor.End;
14615 }
14616 return textAnchor;
14617 }
14618 getTickPath(startDistance, tickLength, angle) {
14619 const y1 = startDistance * Math.sin(angle);
14620 const y2 = (startDistance + tickLength) * Math.sin(angle);
14621 const x1 = startDistance * Math.cos(angle);
14622 const x2 = (startDistance + tickLength) * Math.cos(angle);
14623 const points = [
14624 { x: x1, y: y1 },
14625 { x: x2, y: y2 }
14626 ];
14627 const lineGenerator = line()
14628 .x(d => d.x)
14629 .y(d => d.y);
14630 return lineGenerator(points);
14631 }
14632}
14633GaugeAxisComponent.decorators = [
14634 { type: Component, args: [{
14635 selector: 'g[ngx-charts-gauge-axis]',
14636 template: `
14637 <svg:g [attr.transform]="rotate">
14638 <svg:g *ngFor="let tick of ticks.big" class="gauge-tick gauge-tick-large">
14639 <svg:path [attr.d]="tick.line" />
14640 </svg:g>
14641 <svg:g *ngFor="let tick of ticks.big" class="gauge-tick gauge-tick-large">
14642 <svg:text
14643 [style.textAnchor]="tick.textAnchor"
14644 [attr.transform]="tick.textTransform"
14645 alignment-baseline="central"
14646 >
14647 {{ tick.text }}
14648 </svg:text>
14649 </svg:g>
14650 <svg:g *ngFor="let tick of ticks.small" class="gauge-tick gauge-tick-small">
14651 <svg:path [attr.d]="tick.line" />
14652 </svg:g>
14653 </svg:g>
14654 `,
14655 changeDetection: ChangeDetectionStrategy.OnPush
14656 },] }
14657];
14658GaugeAxisComponent.propDecorators = {
14659 bigSegments: [{ type: Input }],
14660 smallSegments: [{ type: Input }],
14661 min: [{ type: Input }],
14662 max: [{ type: Input }],
14663 angleSpan: [{ type: Input }],
14664 startAngle: [{ type: Input }],
14665 radius: [{ type: Input }],
14666 valueScale: [{ type: Input }],
14667 tickFormatting: [{ type: Input }]
14668};
14669
14670class GaugeModule {
14671}
14672GaugeModule.decorators = [
14673 { type: NgModule, args: [{
14674 imports: [ChartCommonModule, PieChartModule, BarChartModule],
14675 declarations: [LinearGaugeComponent, GaugeComponent, GaugeArcComponent, GaugeAxisComponent],
14676 exports: [LinearGaugeComponent, GaugeComponent, GaugeArcComponent, GaugeAxisComponent]
14677 },] }
14678];
14679
14680// The export is needed here to generate a valid polyfills.metadata.json file
14681function ngxChartsPolyfills() {
14682 // IE11 fix
14683 // Ref: https://github.com/swimlane/ngx-charts/issues/386
14684 if (typeof SVGElement !== 'undefined' && typeof SVGElement.prototype.contains === 'undefined') {
14685 SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
14686 }
14687}
14688
14689class NgxChartsModule {
14690 constructor() {
14691 ngxChartsPolyfills();
14692 }
14693}
14694NgxChartsModule.decorators = [
14695 { type: NgModule, args: [{
14696 exports: [
14697 ChartCommonModule,
14698 AreaChartModule,
14699 BarChartModule,
14700 BoxChartModule,
14701 BubbleChartModule,
14702 HeatMapModule,
14703 LineChartModule,
14704 PolarChartModule,
14705 NumberCardModule,
14706 PieChartModule,
14707 TreeMapModule,
14708 GaugeModule
14709 ]
14710 },] }
14711];
14712NgxChartsModule.ctorParameters = () => [];
14713
14714function tickFormat(fieldType, groupByType) {
14715 return function (label) {
14716 if (label === 'No Value' || label === 'Other') {
14717 return label;
14718 }
14719 if (fieldType === 'date' && groupByType === 'groupBy') {
14720 const formatter = timeFormat('MM/DD/YYYY');
14721 return formatter(label);
14722 }
14723 return label.toString();
14724 };
14725}
14726
14727/*
14728 * Public API Surface of ngx-charts
14729 */
14730
14731/**
14732 * Generated bundle index. Do not edit.
14733 */
14734
14735export { AdvancedLegendComponent, AdvancedPieChartComponent, AreaChartComponent, AreaChartModule, AreaChartNormalizedComponent, AreaChartStackedComponent, AreaComponent, AreaSeriesComponent, AxesModule, AxisLabelComponent, BarChartModule, BarChartType, BarComponent, BarHorizontal2DComponent, BarHorizontalComponent, BarHorizontalNormalizedComponent, BarHorizontalStackedComponent, BarLabelComponent, BarOrientation, BarVertical2DComponent, BarVerticalComponent, BarVerticalNormalizedComponent, BarVerticalStackedComponent, BaseChartComponent, BoxChartComponent, BoxChartModule, BoxComponent, BoxSeriesComponent, BubbleChartComponent, BubbleChartModule, BubbleSeriesComponent, CardComponent, CardSeriesComponent, ChartCommonModule, ChartComponent, CircleComponent, CircleSeriesComponent, ColorHelper, CountUpDirective, D0Types, GaugeArcComponent, GaugeAxisComponent, GaugeComponent, GaugeModule, GridPanelComponent, GridPanelSeriesComponent, HeatCellSeriesComponent, HeatMapCellComponent, HeatMapComponent, HeatMapModule, LegendComponent, LegendEntryComponent, LegendPosition, LegendType, LineChartComponent, LineChartModule, LineComponent, LineSeriesComponent, LinearGaugeComponent, NgxChartsModule, NumberCardComponent, NumberCardModule, Orientation, PieArcComponent, PieChartComponent, PieChartModule, PieGridComponent, PieGridSeriesComponent, PieLabelComponent, PieSeriesComponent, PlacementTypes, PolarChartComponent, PolarChartModule, PolarSeriesComponent, ScaleLegendComponent, ScaleType, SeriesHorizontal, SeriesType, SeriesVerticalComponent, ShowTypes, StyleTypes, SvgLinearGradientComponent, SvgRadialGradientComponent, TextAnchor, Timeline, TooltipArea, TooltipContentComponent, TooltipDirective, TooltipModule, TooltipService, TreeMapCellComponent, TreeMapCellSeriesComponent, TreeMapComponent, TreeMapModule, VisibilityObserver, XAxisComponent, XAxisTicksComponent, YAxisComponent, YAxisTicksComponent, calculateViewDimensions, colorSets, count, decimalChecker, escapeLabel, formatLabel, getDomain, getScale, getScaleType, getUniqueXDomainValues, getXDomainArray, gridLayout, gridSize, hexToRgb, id, invertColor, reduceTicks, shadeRGBColor, sortByDomain, sortByTime, sortLinear, throttle, throttleable, tickFormat, trimLabel, InjectionRegisteryService as ɵa, InjectionService as ɵb };
14736//# sourceMappingURL=swimlane-ngx-charts.js.map