feat: 优化行情展示代码
This commit is contained in:
@@ -34,35 +34,128 @@
|
|||||||
'2025-01-08': [112, 118, 110, 121],
|
'2025-01-08': [112, 118, 110, 121],
|
||||||
'2025-01-09': [118, 121, 117, 123],
|
'2025-01-09': [118, 121, 117, 123],
|
||||||
'2025-01-10': [121, 119, 118, 122],
|
'2025-01-10': [121, 119, 118, 122],
|
||||||
};
|
}
|
||||||
|
|
||||||
// Derive arrays for the chart from the KV map
|
// 全局配置(颜色、尺寸、间距等),集中管理,便于统一调整
|
||||||
const dates = Object.keys(data).sort();
|
const CONFIG = {
|
||||||
// For custom rendering, augment with category index: [idx, open, close, low, high]
|
colors: {up: '#000000FF', down: '#00000045'},
|
||||||
const ohlcData = dates.map((d, i) => [i, ...data[d]]);
|
grid: {left: '2%', right: '2%', top: 40, bottom: 110},
|
||||||
|
zoom: {bottom: 16, height: 50},
|
||||||
|
linewidth: {stem: 1.5, openTick: 1.2, closeTick: 1.6, closeLine: 1.5},
|
||||||
|
tick: {min: 4, max: 10, scale: 0.4},
|
||||||
|
}
|
||||||
|
|
||||||
// Styling and helpers
|
// 通用 tooltip 格式化(按索引回读原始 O/H/L/C)
|
||||||
const UP_COLOR = '#000000'; // up: black
|
function makeTooltipFormatter(dataMap, dates) {
|
||||||
const DOWN_COLOR = '#9e9e9e'; // down: gray
|
return function (params) {
|
||||||
|
let p = Array.isArray(params) ? params[0] : params
|
||||||
|
let idx = p.dataIndex
|
||||||
|
let d = dates[idx]
|
||||||
|
let ohlc = dataMap[d] || []
|
||||||
|
let o = ohlc[0], c = ohlc[1], l = ohlc[2], h = ohlc[3]
|
||||||
|
let chg = (c - o)
|
||||||
|
let chgPct = o ? (chg / o * 100) : 0
|
||||||
|
let sign = chg >= 0 ? '+' : ''
|
||||||
|
return [
|
||||||
|
d,
|
||||||
|
'O: ' + o,
|
||||||
|
'C: ' + c,
|
||||||
|
'H: ' + h,
|
||||||
|
'L: ' + l,
|
||||||
|
'Chg: ' + sign + chg.toFixed(2) + ' (' + sign + chgPct.toFixed(2) + '%)',
|
||||||
|
].join('<br/>')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用基础配置构建(legend/tooltip/grid/xAxis/yAxis/dataZoom)
|
||||||
|
function buildBaseOption(dates, series, formatter) {
|
||||||
|
return {
|
||||||
|
animation: false,
|
||||||
|
legend: {show: false},
|
||||||
|
tooltip: {trigger: 'axis', axisPointer: {type: 'cross'}, formatter},
|
||||||
|
grid: CONFIG.grid,
|
||||||
|
xAxis: {type: 'category', data: dates, boundaryGap: true, axisLine: {onZero: false}},
|
||||||
|
yAxis: {scale: true},
|
||||||
|
dataZoom: [
|
||||||
|
{type: 'inside', xAxisIndex: 0, start: 0, end: 100},
|
||||||
|
{
|
||||||
|
show: true,
|
||||||
|
type: 'slider',
|
||||||
|
xAxisIndex: 0,
|
||||||
|
bottom: CONFIG.zoom.bottom,
|
||||||
|
height: CONFIG.zoom.height,
|
||||||
|
start: 0,
|
||||||
|
end: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range Band + Close Line(高低区间带 + 收盘线):趋势与波动范围直观
|
||||||
|
function buildRangeCloseOption(dataMap) {
|
||||||
|
const dates = Object.keys(dataMap).sort()
|
||||||
|
const lowArr = dates.map(d => dataMap[d][2])
|
||||||
|
const highArr = dates.map(d => dataMap[d][3])
|
||||||
|
const closeArr = dates.map(d => dataMap[d][1])
|
||||||
|
const rangeArr = highArr.map((h, i) => h - lowArr[i])
|
||||||
|
|
||||||
|
const series = [
|
||||||
|
{
|
||||||
|
name: 'Low',
|
||||||
|
type: 'line',
|
||||||
|
data: lowArr,
|
||||||
|
stack: 'range',
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: {width: 0},
|
||||||
|
emphasis: {disabled: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Range',
|
||||||
|
type: 'line',
|
||||||
|
data: rangeArr,
|
||||||
|
stack: 'range',
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: {width: 0},
|
||||||
|
areaStyle: {color: CONFIG.colors.down, opacity: 0.6},
|
||||||
|
z: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Close',
|
||||||
|
type: 'line',
|
||||||
|
data: closeArr,
|
||||||
|
symbol: 'none',
|
||||||
|
lineStyle: {color: CONFIG.colors.up, width: CONFIG.linewidth.closeLine},
|
||||||
|
z: 3,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return buildBaseOption(dates, series, makeTooltipFormatter(dataMap, dates))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal OHLC(竖线 + 左/右短横):信息等价于K线但形态简洁
|
||||||
|
function buildOHLCMinimalOption(dataMap) {
|
||||||
|
const dates = Object.keys(dataMap).sort()
|
||||||
|
const ohlcData = dates.map((d, i) => [i, ...dataMap[d]])
|
||||||
|
|
||||||
|
// 自定义渲染:竖线=高低区间;左短横=开盘;右短横=收盘;颜色=涨跌
|
||||||
function renderOHLCMinimal(params, api) {
|
function renderOHLCMinimal(params, api) {
|
||||||
var idx = api.value(0);
|
let idx = api.value(0)
|
||||||
var open = api.value(1);
|
let open = api.value(1)
|
||||||
var close = api.value(2);
|
let close = api.value(2)
|
||||||
var low = api.value(3);
|
let low = api.value(3)
|
||||||
var high = api.value(4);
|
let high = api.value(4)
|
||||||
var up = close >= open;
|
let up = close >= open
|
||||||
|
|
||||||
var x = api.coord([idx, 0])[0];
|
let x = api.coord([idx, 0])[0]
|
||||||
var highPoint = api.coord([idx, high]);
|
let highPoint = api.coord([idx, high])
|
||||||
var lowPoint = api.coord([idx, low]);
|
let lowPoint = api.coord([idx, low])
|
||||||
var openPoint = api.coord([idx, open]);
|
let openPoint = api.coord([idx, open])
|
||||||
var closePoint = api.coord([idx, close]);
|
let closePoint = api.coord([idx, close])
|
||||||
|
|
||||||
var band = api.size([1, 0])[0];
|
let band = api.size([1, 0])[0]
|
||||||
// Keep dash length unchanged from the previous baseline
|
let tick = Math.max(CONFIG.tick.min, Math.min(CONFIG.tick.max, band * CONFIG.tick.scale))
|
||||||
var tick = Math.max(4, Math.min(10, band * 0.4));
|
let color = up ? CONFIG.colors.up : CONFIG.colors.down
|
||||||
var color = up ? UP_COLOR : DOWN_COLOR;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'group',
|
type: 'group',
|
||||||
@@ -70,38 +163,34 @@
|
|||||||
{
|
{
|
||||||
type: 'line',
|
type: 'line',
|
||||||
shape: {x1: x, y1: highPoint[1], x2: x, y2: lowPoint[1]},
|
shape: {x1: x, y1: highPoint[1], x2: x, y2: lowPoint[1]},
|
||||||
style: { stroke: color, lineWidth: 1, opacity: 0.9 },
|
style: {stroke: color, lineWidth: CONFIG.linewidth.stem, opacity: 0.9},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: 'line',
|
||||||
shape: {x1: x - tick, y1: openPoint[1], x2: x, y2: openPoint[1]},
|
shape: {x1: x - tick, y1: openPoint[1], x2: x, y2: openPoint[1]},
|
||||||
style: { stroke: color, lineWidth: 1.2, opacity: 0.95 },
|
style: {stroke: color, lineWidth: CONFIG.linewidth.openTick, opacity: 0.95},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: 'line',
|
||||||
shape: {x1: x, y1: closePoint[1], x2: x + tick, y2: closePoint[1]},
|
shape: {x1: x, y1: closePoint[1], x2: x + tick, y2: closePoint[1]},
|
||||||
style: { stroke: color, lineWidth: 1.6, opacity: 0.95 },
|
style: {stroke: color, lineWidth: CONFIG.linewidth.closeTick, opacity: 0.95},
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTooltip(params) {
|
const series = [
|
||||||
var p = Array.isArray(params) ? params[0] : params;
|
{
|
||||||
var v = p.data; // [idx, open, close, low, high]
|
name: 'ohlc',
|
||||||
var d = dates[v[0]];
|
type: 'custom',
|
||||||
var o = v[1], c = v[2], l = v[3], h = v[4];
|
renderItem: renderOHLCMinimal,
|
||||||
var chg = (c - o);
|
encode: {x: 0, y: [1, 2, 3, 4]},
|
||||||
var chgPct = o ? (chg / o * 100) : 0;
|
data: ohlcData,
|
||||||
var sign = chg >= 0 ? '+' : '';
|
z: 10,
|
||||||
return [
|
},
|
||||||
d,
|
]
|
||||||
'O: ' + o,
|
|
||||||
'C: ' + c,
|
return buildBaseOption(dates, series, makeTooltipFormatter(dataMap, dates))
|
||||||
'H: ' + h,
|
|
||||||
'L: ' + l,
|
|
||||||
'Chg: ' + sign + chg.toFixed(2) + ' (' + sign + chgPct.toFixed(2) + '%)'
|
|
||||||
].join('<br/>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
@@ -112,50 +201,23 @@
|
|||||||
body: {
|
body: {
|
||||||
type: 'tabs',
|
type: 'tabs',
|
||||||
tabsMode: 'vertical',
|
tabsMode: 'vertical',
|
||||||
// amis expects `tabs` to be an array. Using an object causes `.map` errors at runtime.
|
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
title: '测试',
|
title: 'Charts',
|
||||||
body: {
|
// 在一个 Tab 中展示两张图,便于同屏对比
|
||||||
type: 'chart',
|
body: [
|
||||||
height: 800,
|
|
||||||
// ECharts candlestick example
|
|
||||||
config: {
|
|
||||||
animation: false,
|
|
||||||
// Minimal style: hide legend for a cleaner look
|
|
||||||
legend: { show: false },
|
|
||||||
tooltip: { trigger: 'axis', axisPointer: { type: 'cross' }, formatter: formatTooltip },
|
|
||||||
grid: { left: '10%', right: '8%', top: 50, bottom: 80 },
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
// Use computed arrays directly to avoid template interpolation issues
|
|
||||||
data: dates,
|
|
||||||
boundaryGap: true,
|
|
||||||
axisLine: { onZero: false },
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
scale: true,
|
|
||||||
},
|
|
||||||
dataZoom: [
|
|
||||||
// Inside zoom for wheel/gesture; default selects all
|
|
||||||
{ type: 'inside', xAxisIndex: 0, start: 0, end: 100 },
|
|
||||||
// Slider placed under the x-axis; default selects all
|
|
||||||
{ show: true, type: 'slider', xAxisIndex: 0, bottom: 16, height: 26, start: 0, end: 100 },
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
{
|
||||||
name: 'ohlc',
|
type: 'chart',
|
||||||
type: 'custom',
|
height: 500,
|
||||||
// Minimal OHLC: neutral stem (high-low) + short dashes at open/close
|
config: buildRangeCloseOption(data),
|
||||||
renderItem: renderOHLCMinimal,
|
},
|
||||||
encode: { x: 0, y: [1, 2, 3, 4] },
|
{
|
||||||
data: ohlcData,
|
type: 'chart',
|
||||||
z: 10,
|
height: 500,
|
||||||
|
config: buildOHLCMinimalOption(data),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user