ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
219 lines (195 loc) • 5.58 kB
text/typescript
import { Platform } from '@angular/cdk/platform';
import {
ChangeDetectionStrategy,
Component,
ElementRef,
EventEmitter,
Input,
NgZone,
OnChanges,
OnDestroy,
OnInit,
Output,
ViewEncapsulation,
} from '@angular/core';
import DataSet from '@antv/data-set';
import { Chart, Event, registerShape, Types, Util } from '@antv/g2';
import { OhayoConfigService, InputNumber, NumberInput } from '@ohayo/util';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { fromEvent, Subscription } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
export interface G2TagCloudData {
value?: number;
name?: string;
[key: string]: any;
}
export interface G2TagCloudClickItem {
item: G2TagCloudData;
ev: Event;
}
export class G2TagCloudComponent implements OnDestroy, OnChanges, OnInit {
static ngAcceptInputType_delay: NumberInput;
static ngAcceptInputType_height: NumberInput;
static ngAcceptInputType_width: NumberInput;
private resize$: Subscription;
private _chart: Chart;
get chart(): Chart {
return this._chart;
}
// #region fields
delay = 100;
width = 0;
height = 200;
padding: number | number[] | 'auto' = 0;
data: G2TagCloudData[] = [];
theme: string | Types.LooseObject;
clickItem = new EventEmitter<G2TagCloudClickItem>();
// #endregion
constructor(private el: ElementRef<HTMLDivElement>, private ngZone: NgZone, configSrv: OhayoConfigService, private platform: Platform) {
configSrv.attachKey(this, 'chart', 'theme');
}
private initTagCloud(): void {
registerShape('point', 'cloud', {
// tslint:disable-next-line: typedef
draw(cfg, container) {
const data = cfg.data as NzSafeAny;
const textShape = container.addShape({
type: 'text',
name: 'tag-cloud-text',
attrs: {
...cfg.style,
fontSize: data.size,
text: data.text,
textAlign: 'center',
fontFamily: data.font,
fill: cfg.color,
textBaseline: 'Alphabetic',
x: cfg.x,
y: cfg.y,
} as NzSafeAny,
});
if (data.rotate) {
Util.rotate(textShape, (data.rotate * Math.PI) / 180);
}
return textShape;
},
});
}
private install(): void {
const { el, padding, theme } = this;
if (this.height === 0) {
this.height = this.el.nativeElement.clientHeight;
}
if (this.width === 0) {
this.width = this.el.nativeElement.clientWidth;
}
const chart = (this._chart = new Chart({
container: el.nativeElement,
autoFit: false,
padding,
height: this.height,
width: this.width,
theme,
}));
chart.scale({
x: { nice: false },
y: { nice: false },
});
chart.legend(false);
chart.axis(false);
chart.tooltip({
showTitle: false,
showMarkers: false,
});
(chart.coordinate() as NzSafeAny).reflect();
chart
.point()
.position('x*y')
.color('text')
.shape('cloud')
.state({
active: {
style: {
fillOpacity: 0.4,
},
},
});
chart.interaction('element-active');
chart.on('tag-cloud-text:click', (ev: Event) => {
this.ngZone.run(() => this.clickItem.emit({ item: ev.data?.data, ev }));
});
this.attachChart();
}
private attachChart(): void {
const { _chart, padding, data } = this;
if (!_chart || !data || data.length <= 0) return;
_chart.height = this.height;
_chart.width = this.width;
_chart.padding = padding;
const dv = new DataSet.View().source(data);
const range = dv.range('value');
const min = range[0];
const max = range[1];
dv.transform({
type: 'tag-cloud',
fields: ['name', 'value'],
// imageMask,
font: 'Verdana',
size: [this.width, this.height], // 宽高设置最好根据 imageMask 做调整
padding: 0,
timeInterval: 5000, // max execute time
// tslint:disable-next-line: typedef
rotate() {
let random = ~~(Math.random() * 4) % 4;
if (random === 2) {
random = 0;
}
return random * 90; // 0, 90, 270
},
// tslint:disable-next-line: typedef
fontSize(d: NzSafeAny) {
return ((d.value - min) / (max - min)) * (32 - 8) + 8;
},
} as NzSafeAny);
_chart.data(dv.rows);
_chart.render();
}
private _attachChart(): void {
this.ngZone.runOutsideAngular(() => this.attachChart());
}
private installResizeEvent(): void {
this.resize$ = fromEvent(window, 'resize')
.pipe(
filter(() => !!this._chart),
debounceTime(200),
)
.subscribe(() => this._attachChart());
}
ngOnInit(): void {
if (!this.platform.isBrowser) {
return;
}
this.initTagCloud();
this.installResizeEvent();
this.ngZone.runOutsideAngular(() => setTimeout(() => this.install(), this.delay));
}
ngOnChanges(): void {
this._attachChart();
}
ngOnDestroy(): void {
if (this.resize$) {
this.resize$.unsubscribe();
}
if (this._chart) {
this.ngZone.runOutsideAngular(() => this._chart.destroy());
}
}
}