123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- import { Component, AfterViewInit, ViewChild, ElementRef, OnDestroy, ChangeDetectorRef } from '@angular/core';
- import * as echarts from 'echarts';
- import { CsvReaderService } from './csv-reader-service';
- import { IonicModule,ModalController } from '@ionic/angular';
- import { CommonModule } from '@angular/common';
- import { FormsModule, ReactiveFormsModule } from '@angular/forms'; // 导入 FormsModule 和 ReactiveFormsModule
- @Component({
- selector: 'app-market-forecast',
- templateUrl: './market-forecast.component.html',
- styleUrls: ['./market-forecast.component.scss'],
- standalone: true,
- imports: [IonicModule, CommonModule,FormsModule, ReactiveFormsModule]
- })
- export class MarketForecastComponent implements AfterViewInit, OnDestroy {
- @ViewChild('chartContainer', { static: false }) priceChartContainer!: ElementRef;
- @ViewChild('indexChartContainer', { static: false }) indexChartContainer!: ElementRef;
- isModalOpen = false;
- userEntries: { price?: string; index?: string }[] = [];
- private currentChart?: echarts.ECharts;
- public currentChartType: 'price' | 'index' = 'price'; // 明确限定类型
- constructor(private csvReaderService: CsvReaderService, private cdr: ChangeDetectorRef,private modalCtrl: ModalController) { }
- openDataEntryModal() {
- this.isModalOpen = true;
- this.userEntries.push({}); // 初始化至少一条记录
- }
- closeModal() {
- this.isModalOpen = false;
- }
- addEntry() {
- this.userEntries.push({});
- }
- onSubmit(form: any) {
- if (form.valid) {
- const jsonData = {
- "价格": this.userEntries.map(entry => entry.price).filter(Boolean),
- "指数": this.userEntries.map(entry => entry.index).filter(Boolean)
- };
- console.log(JSON.stringify(jsonData, null, 2));
- // 在这里你可以将 jsonData 发送到服务器或进行其他操作
- this.closeModal();
- }
- }
- ngAfterViewInit(): void {
- this.cdr.detectChanges(); // 确保变更检测运行以更新视图
- requestAnimationFrame(() => {
- this.selectChart(this.currentChartType);
- });
- }
- loadPredictChartData(): void {
- this.csvReaderService.getPredictData().subscribe(data => {
- this.updatePredictChart(data);
- });
- }
- updatePredictChart(data: any[]): void {
- if (!this.currentChart || !data) return;
- const dates = data.map(d => d['日期'].getTime());
- const prices = data.map(d => d['数值']);
- const indices = data.map(d => d['指数']);
- const xAxisConfig = {
- type: 'value',
- boundaryGap: false,
- name: '价格',
- min: Math.min(...prices), // 动态设置最小值
- max: Math.max(...prices), // 动态设置最大值
- axisLabel: {
- formatter: '{value}',
- rotate: -90 // 将 X 轴标签旋转 -90 度
- },
- axisLine: { show: true },
- axisTick: { show: true },
- axisPointer: {
- label: {
- formatter: function (params: any) {
- return params.value;
- }
- }
- }
- };
- const option = {
- title: { text: '预测脐橙价格', left: 'center' },
- tooltip: { trigger: 'axis' },
- xAxis: xAxisConfig,
- yAxis: {
- type: 'time',
- boundaryGap: false,
- name: '',
- axisLabel: {
- formatter: function (value: any) {
- const date = new Date(value);
- return `${date.getMonth() + 1}-${date.getDate()}`;
- },
- rotate: -90 // 将 Y 轴标签旋转 -90 度
- },
- axisLine: { show: true },
- axisTick: { show: true },
- axisPointer: {
- label: {
- formatter: function (params: any) {
- const date = new Date(params.value);
- return `${date.getMonth() + 1}-${date.getDate()}`;
- }
- }
- }
- },
- series: [{
- name: '预测价格',
- type: 'line',
- data: data.map((item, index) => [prices[index], dates[index]]),
- itemStyle: {
- color: 'red'
- }
- }],
- dataZoom: [
- {
- type: 'slider',
- show: true,
- yAxisIndex: [0],
- start: 50,
- end: 100
- },
- {
- type: 'inside',
- yAxisIndex: [0],
- start: 50,
- end: 100
- }
- ],
- graphic: [
- {
- type: 'text',
- left: 'middle',
- top: 'bottom',
- style: {
- text: '预测价格',
- textAlign: 'center',
- fontSize: 14,
- rotation: -Math.PI / 2, // 旋转 -90 度
- transformOrigin: 'center'
- }
- }
- ]
- };
- this.currentChart.setOption(option);
- }
- predictChart(){
- this.cdr.detectChanges(); // 触发变更检测以更新视图
- this.csvReaderService.getPredictData().subscribe(data => {
- this.clearChart();
- this.initChart();
- this.updatePredictChart(data); // 更新预测图表
- });
- }
- selectChart(type: 'price' | 'index'): void {
- this.currentChartType = type;
- this.cdr.detectChanges(); // 触发变更检测以更新视图
- // 延迟初始化以确保视图更新完毕
- setTimeout(() => {
- requestAnimationFrame(() => {
- this.clearChart();
- this.initChart();
- this.loadChartData();
- });
- }, 0);
- }
- initChart() {
- let chartContainerEl: HTMLElement | null = null;
- if (this.currentChartType === 'price') {
- chartContainerEl = this.priceChartContainer?.nativeElement;
- } else if (this.currentChartType === 'index') {
- chartContainerEl = this.indexChartContainer?.nativeElement;
- }
- // 检查图表容器是否已准备好,并且有非零尺寸
- if (chartContainerEl && chartContainerEl.offsetWidth > 0 && chartContainerEl.offsetHeight > 0) {
- this.currentChart = echarts.init(chartContainerEl);
- } else {
- console.warn('Chart container is not ready or has zero size.');
- // 如果图表容器尚未准备好,设置一个短暂的延时并再次尝试
- setTimeout(() => this.initChart(), 100);
- }
- }
- loadChartData(): void {
- this.csvReaderService.getOrangeData().subscribe(data => {
- this.updateChart(data);
- });
- }
-
- updateChart(data: any[]): void {
- if (!this.currentChart) return;
- const dates = data.map(d => d['日期'].getTime());
- const prices = data.map(d => d['数值']);
- const indices = data.map(d => d['指数']);
- const xAxisConfig = {
- type: 'value',
- boundaryGap: false,
- name: '',
- min: this.currentChartType === 'price' ? 6 : 90,
- max: this.currentChartType === 'price' ? 15 : 120,
- axisLabel: {
- formatter: function (value: any) {
- return value.toString();
- },
- rotate: -90 // 将 X 轴标签旋转 -90 度
- },
- axisLine: {
- show: true
- },
- axisTick: {
- show: true
- },
- axisPointer: {
- label: {
- formatter: function (params: any) {
- return params.value;
- }
- }
- }
- };
- const yAxisConfig = {
- type: 'time',
- boundaryGap: false,
- name: '',
- axisLabel: {
- formatter: function (value: any) {
- const date = new Date(value);
- return `${date.getMonth() + 1}-${date.getDate()}`;
- },
- rotate: -90 // 将 Y 轴标签旋转 -90 度
- },
- axisLine: {
- show: true
- },
- axisTick: {
- show: true
- },
- axisPointer: {
- label: {
- formatter: function (params: any) {
- const date = new Date(params.value);
- return `${date.getMonth() + 1}-${date.getDate()}`;
- }
- }
- }
- };
- const dataZoomConfig = [
- {
- type: 'slider',
- show: true,
- yAxisIndex: [0],
- start: 50,
- end: 100
- },
- {
- type: 'inside',
- yAxisIndex: [0],
- start: 50,
- end: 100
- }
- ];
- let option;
- if (this.currentChartType === 'price') {
- option = {
- title: { text: '每日脐橙价格', left: 'center' },
- tooltip: { trigger: 'axis' },
- xAxis: xAxisConfig,
- yAxis: yAxisConfig,
- series: [{
- name: '价格',
- type: 'line',
- data: data.map((item, index) => [prices[index], dates[index]]),
- itemStyle: {
- color: 'orange'
- }
- }],
- dataZoom: dataZoomConfig,
- graphic: [
- {
- type: 'text',
- left: 'middle',
- top: 'bottom',
- style: {
- text: '价格',
- textAlign: 'center',
- fontSize: 14,
- rotation: -Math.PI / 2, // 旋转 -90 度
- transformOrigin: 'center'
- }
- }
- ]
- };
- } else {
- option = {
- title: { text: '脐橙价格指数', left: 'center' },
- tooltip: { trigger: 'axis' },
- xAxis: xAxisConfig,
- yAxis: yAxisConfig,
- series: [{
- name: '指数',
- type: 'line',
- data: data.map((item, index) => [indices[index], dates[index]])
- }],
- dataZoom: dataZoomConfig,
- graphic: [
- {
- type: 'text',
- left: 'middle',
- top: 'bottom',
- style: {
- text: '指数',
- textAlign: 'center',
- fontSize: 14,
- rotation: -Math.PI / 2, // 旋转 -90 度
- transformOrigin: 'center'
- }
- }
- ]
- };
- }
- this.currentChart.setOption(option);
- }
- clearChart(): void {
- if (this.currentChart) {
- this.currentChart.dispose();
- this.currentChart = undefined;
- }
- }
- ngOnDestroy(): void {
- this.clearChart();
- }
-
- }
|