xieziyu / ngx-echarts

An angular (ver >= 2.x) directive for ECharts (ver >= 3.x)
https://xieziyu.github.io/ngx-echarts/
MIT License
1.1k stars 195 forks source link

和tabset组件一起使用时,echarts图表宽高异常的问题 #45

Closed jamessawyer closed 6 years ago

jamessawyer commented 6 years ago

我想在tabset组件中使用二次封装的折线图组件,但是经常报 Can't get dom width or height 警告,但是所有折线图还是会被渲染出来。当前的tab(页面加载时显示的tab)中的折线图宽高正常,但是切换到其余tab中的折线图,折线图宽度只有 100px,我设置的宽度均为 100%(为了自适应),不知道大佬有没有遇到过这个问题?有没有什么解决办法 我个人觉得可能是tabset动态插入模板的时候,app-total-line 组件无法获取到父容器的宽高导致的。

部分代码如下:

tabset

# app-tabset是一个tabset组件
# app-tab表示tab页
# app-total-line 是对echarts指令的二次封装的组件
<div class="line-tab">
    <app-tabset (onSelect)="onTabSelect($event)">
        <app-tab title="全部">
            <app-total-line></app-total-line>
        </app-tab>
        <app-tab title="一个月" [active]="true">
            <app-total-line></app-total-line>
        </app-tab>
        <app-tab title="24小时">
            <app-total-line></app-total-line>
        </app-tab>
    </app-tabset>
</div>

tabset组件模板

<nav class="tabset-style">
    <ul class="tabset-header" [ngClass]="customNavClass">
        <li role="presentation" *ngFor="let tab of tabs" [class.active]="tab.active"
            [class.disabled]="tab.disabled" (click)="changeActiveTab(tab)"
        >
            <span [appTabTransclude]="tab.headingTemplate">{{ tab.title }}</span>
        </li>
    </ul>
</nav>
<div class="tabs-container" [ngClass]="customTabsClass" [@.disabled]="!isAnimate">
    <div class="tabset-content">
        <ng-content></ng-content>
    </div>
</div>

app-total-line 组件

@Component({
    selector: 'app-total-line',
    template: `
        <div class="total-line">
            <app-line-echarts [option]="chartOption"></app-line-echarts>
        </div>
    `,
    styles: [`
        :host {
            width: 100%;
            height: 100%;
        }
    `]
})
export class TotalLineComponent {
    chartOption: ILineChart = {
        xAxisData: ['10-10', '10-11', '10-12', '10-13', '10-14', '10-15',
        '10-16', '10-17', '10-18', '10-19', '10-20', '10-21',
        '11-10', '11-11', '11-12', '11-13', '11-14', '11-15',
        '11-16', '11-17', '11-18', '11-19', '11-20', '11-21'],
        yAxisData1: [100, 123, 56, 12, 199,
            100, 123, 56, 12, 199,
            100, 123, 56, 12, 199,
            100, 123, 56, 12, 199,
            137, 7, 12, 342],
        yAxisData2: [137, 7, 12, 342, 341,
            137, 7, 12, 342, 341,
            137, 7, 12, 342, 341,
            137, 7, 12, 342, 341,
            143, 323, 112, 2]
    };
}

app-line-echarts 是对 echarts 指令的二次封装


@Component({
    selector: 'app-line-echarts',
    template: `
        <div class="line-echarts" echarts [options]="chartOption" (chartInit)="onChartInit($event)"
            [ngStyle]="{'width': chartWidth, 'height': chartHeight}"></div>
    `
})
export class LineChartComponent implements OnInit, OnChanges {
    chartInstance: any;
    private chartWidth: number | string = '100%';   // 宽度给的是100%,没有给固定值
    private chartHeight: number | string = '500px'; // 已经默认的给了一个高度500px
    @Input() option: ILineChart;
    @Input() showDataZoom = true;

    /**
     * 设置canvas的宽度
     * 支持数字和字符 或者 是 字符串带单位的形式
     */
    @Input()
    set width(val) {
        if (typeof val === 'number') {
           this.chartWidth = String(val) + 'px';
        } else if (typeof val === 'string' && (/^\d*$/g).test(val)) {
            this.chartWidth = val + 'px';
        } else {
            this.chartWidth = val;
        }
    }
    get width() {
        return this.chartWidth;
    }

    @Input()
    set height(val) {
        if (typeof val === 'number') {
           this.chartHeight = String(val) + 'px';
        } else if (typeof val === 'string' && (/^\d*$/g).test(val)) {
            this.chartHeight = val + 'px';
        } else {
            this.chartHeight = val;
        }
    }
    get height() {
        return this.chartHeight;
    }

    chartOption: any;

    constructor() {}

    onChartInit(ec) {
        this.chartInstance = ec;
    }
    ngOnInit(): void {
    }

    ngOnChanges(changes: SimpleChanges) {

        this._updateOption();
    }

    private _updateOption() {
      // ...
    }
}   
jamessawyer commented 6 years ago

和这个问题 - when init echarts on DEV env, warn can't get dom width or height 比较像

xieziyu commented 6 years ago

请尝试给你的app-line-echarts固定宽度

jamessawyer commented 6 years ago

@xieziyu 给固定宽度就达不到宽度自适应的效果了,还有就是依然会有警告,我准备放弃用tabset组件了,准备直接使用按钮的方式。

xieziyu commented 6 years ago

这个问题和tabset组件的实现机制有关系。可以试一下一些workaround: 1、使用ngx-bootstrap的tabset组件 or 2、利用chartInstance的resize()函数 or 3、利用空的options或者*ngIf等其他方式延缓app-total-line渲染时间点到tab切换完成之后

2、3方法我觉得只是理论上可行的,但并不推荐这么做。重要的是要理解为什么tabset组件中,echarts无法获取到父容器的clientWidth或者clientHeight,然后以此改进。

jamessawyer commented 6 years ago

第2种方式使用过了,没有效果。第3种方式尝试使用setTimeout延迟echarts渲染,但是没起作用。tabset组件中为什么无法获取父容器宽高,但是最后还是渲染了,并且给了100px的宽,这是我最想不通的地方。这个暂时一下无法理解其中的原理,待进一步去学习了,谢谢大佬了 @xieziyu