0

我用 Lightweight Charts 创建了这个漂亮的图表。 在此处输入图像描述

我现在面临的问题是,在 x 轴上的标记(灰色工具提示)中,显示的时间似乎偏离了 2 小时。

我觉得这是一个时区问题,因为我是 UTC+2 的 CEST,但我不知道这是如何发生的,在哪里发生以及如何解决它。

这是生成图表部分的 Vue SFC 的代码

<template>
    <v-container
        fluid
        id="chart"
    >
        <v-btn-toggle
            v-model="interval"
            tile
            group
            @change="refresh"
        >
            <v-btn value="day">
                Intraday
            </v-btn>

            <v-btn value="week">
                Woche
            </v-btn>

            <v-btn value="month">
                Monat
            </v-btn>

            <v-btn value="year">
                Jahr
            </v-btn>

            <v-btn value="fiveyears">
                5 Jahre
            </v-btn>
        </v-btn-toggle>
        <Alert
            :message="errorMessage"
            type="error"
        ></Alert>
    </v-container>
</template>

<script>
    import { createChart, TickMarkType } from 'lightweight-charts';
    import ChartService from '@/service/ChartService'
    import Alert from '@/components/Alert'
    import FormatterService from "../../service/FormatterService";

    export default {
        name: "ShareChart",

        components: {
            Alert
        },

        props: [
          'quote',
          'bus'
        ],

        data() {
            return {
                errorMessage: '',
                chart: null,
                interval: 'day',
                series: null,
                format: null
            }
        },

        methods: {
            create() {
                const chart = createChart(
                    document.getElementById('chart'),
                    {
                        height: 200,
                        localization: {
                            locale: 'de-DE',
                            dateFormat: 'dd.MM.yyyy',
                            priceFormatter: price => this.format.eur(price)
                        },
                        handleScale: false,
                        handleScroll: false
                    });

                chart.applyOptions({
                    timeScale: {
                        timeVisible: true,
                        tickMarkFormatter: (time, tickMarkType) => {
                            time = new Date(time*1000)
                            let opt = {}

                            switch(tickMarkType) {
                                case TickMarkType.Year:
                                    opt = {
                                       year: 'numeric'
                                    }
                                    break
                                case TickMarkType.Month:
                                    opt = {
                                        month: 'short'
                                    }
                                    break
                                case TickMarkType.DayOfMonth:
                                    opt = {
                                        day: '2-digit'
                                    }
                                    break
                                case TickMarkType.Time:
                                    opt = {
                                        hour: '2-digit',
                                        minute: '2-digit'
                                    }
                                    break
                                case TickMarkType.TimeWithSeconds:
                                    opt = {
                                        hour: '2-digit',
                                        minute: '2-digit',
                                        seconds: '2-digit'
                                    }
                            }

                            return time.toLocaleString('de-DE', opt)
                        },
                    },
                })

                this.chart = chart
            },

            async getData() {
                let res = null

                try {
                    res = await ChartService.get(
                        this.interval,
                        {
                            isin: this.quote.isin,
                            date: new Date().toISOString(),
                            currency: this.quote.currency,
                            mic: this.quote.mic
                        }
                    )
                } catch (e) {
                    this.errorMessage = e
                    return null
                }

                return res.quotes
            },

            draw(datasets) {
                if(!this.chart) return
                if(!datasets) return

                if (this.series) this.chart.removeSeries(this.series);

                this.series = this.chart.addAreaSeries()

                let chartData = []

                for(let ds of datasets) {
                    chartData.push({
                        time: new Date(ds.date).getTime()/1000,
                        value: ds.value
                    })
                }

                this.series.setData(chartData)
                this.setAreaColors(datasets[0].value, datasets[datasets.length-1].value)
                this.setTimeRange()
            },

            setAreaColors(open, close) {
                let red = 0
                let green = 200

                if(open > close) {
                    red = 250
                    green = 0
                }

                this.series.applyOptions({
                    lineColor: 'rgb('+red+', '+green+', 0)',
                    topColor: 'rgba('+red+', '+green+', 0, 1)',
                    bottomColor: 'rgba('+red+', '+green+', 0, 0)'
                });
            },

            setTimeRange() {
                if(this.interval != 'day') {
                    return this.chart.timeScale().fitContent()
                }

                const fromTime = new Date()
                fromTime.setHours(8, 0, 0)

                const toTime = new Date()
                toTime.setHours(20, 0, 0)
                // TODO: Ignores timezones

                this.chart.timeScale().setVisibleRange({
                    from: fromTime.getTime() / 1000,
                    to: toTime.getTime() / 1000,
                });
            },

            async refresh() {
                const quotes = await this.getData()
                this.draw(quotes)
            }
        },

        mounted() {
            this.format = new FormatterService({
                currency: this.quote.currency
            })

            this.create()
            this.refresh()
        },

        watch: {
            quote: function () {
                this.refresh()
            }
        }
    }
</script>

<style scoped>

</style>

setTimeRange() 函数的目的是将“盘中”图表的可见时间范围设置为当地时间上午 8 点到晚上 8 点。如果在该时间范围内没有任何数据,它应该显示空白,这也不起作用。

有人可以帮忙吗?

4

1 回答 1

0

感谢@timocov 向我指出项目 github 上的一个相关问题。原来这是一个已知的错误。

这就是我解决它的方法:

chart.applyOptions({
    timeScale: {
        timeVisible: true,
        tickMarkFormatter: (time, tickMarkType) => {
            time = this.getTimezoneCorrectedTime(time)
                [
        ...]
        }
    }
})

getTimezoneCorrectedTime(utcTime, returnAsUnixTimestamp = false) {
    if(utcTime instanceof Date) {
        utcTime = utcTime.getTime()/1000
    }

    const timezoneOffsetMinutes = new Date().getTimezoneOffset()
    const correctedTime = utcTime+(timezoneOffsetMinutes*60)

    if(returnAsUnixTimestamp) return correctedTime

    return new Date(correctedTime*1000)
}
于 2021-07-15T05:22:08.227 回答