55 lines
1.7 KiB
Vue
55 lines
1.7 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
|
|
import type { MarketDetailSeries } from './market-detail';
|
|
|
|
const props = defineProps<{
|
|
series: MarketDetailSeries;
|
|
availableViews: { kline: boolean; intraday: boolean };
|
|
}>();
|
|
|
|
const width = 720;
|
|
const height = 260;
|
|
const padding = 24;
|
|
|
|
const path = computed(() => {
|
|
if (!props.series.length || !props.availableViews.kline) return '';
|
|
const closes = props.series.map((point) => point.close);
|
|
const min = Math.min(...closes);
|
|
const max = Math.max(...closes);
|
|
const range = max - min || 1;
|
|
const xStep = (width - padding * 2) / Math.max(props.series.length - 1, 1);
|
|
return props.series
|
|
.map((point, index) => {
|
|
const x = padding + index * xStep;
|
|
const y = height - padding - ((point.close - min) / range) * (height - padding * 2);
|
|
return `${index === 0 ? 'M' : 'L'} ${x.toFixed(2)} ${y.toFixed(2)}`;
|
|
})
|
|
.join(' ');
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<section class="detail-chart-panel" aria-labelledby="detail-kline-title">
|
|
<div class="detail-section-heading">
|
|
<div>
|
|
<span class="section-kicker">走势</span>
|
|
<h2 id="detail-kline-title">日 K 线</h2>
|
|
</div>
|
|
<span class="detail-chart-note">TDX · {{ series.length }} 点</span>
|
|
</div>
|
|
<div v-if="!path" class="detail-chart-empty">当前没有可用的 K 线数据</div>
|
|
<svg
|
|
v-else
|
|
class="detail-chart"
|
|
viewBox="0 0 720 260"
|
|
role="img"
|
|
aria-label="日 K 线收盘价走势"
|
|
>
|
|
<line x1="24" y1="236" x2="696" y2="236" class="detail-chart-axis" />
|
|
<path :d="path" class="detail-chart-line" />
|
|
</svg>
|
|
<p v-if="!availableViews.intraday" class="detail-chart-boundary">当前数据源未提供分时数据</p>
|
|
</section>
|
|
</template>
|