|
|
<template> <!-- <div ref="qxnlzhqEchartsRef" id="qxnlzhqEcharts"></div> --> <div class="qxjmqbox"> <div ref="KlineCanvs" class="qxjmqEcharts"></div> </div> </template>
<script setup> import { ref, onMounted, onBeforeUnmount, toRef } from "vue"; import * as echarts from "echarts"; import { color } from "echarts/lib/export";
defineExpose({ initQXNLZHEcharts });
const KlineCanvs = ref(null); let KlineCanvsChart = null; const heatmapData = ref([]); // 存储热力图数据
// 假数据
const rawData2 = ref([]); const lineData3 = ref([]); function initQXNLZHEcharts(kline, qxnlzhqData) { // qxnlzhqData[9][9] = 1;
// qxnlzhqData[2][9] = 1;
rawData2.value = qxnlzhqData; // 处理热力图数据
const processedHeatmap = []; rawData2.value.forEach((item, dateIndex) => { const [date, d1, d2, d3, d4, d5, d6, d7, d8, d9] = item; processedHeatmap.push([ dateIndex, 0, d4, d8 == 1 ? "green" : "transparent", ]); // 数据1
processedHeatmap.push([ dateIndex, 1, d3, d7 == 1 ? "purple" : "transparent", ]); // 数据2
processedHeatmap.push([dateIndex, 2, d2, d6 == 1 ? "red" : "transparent"]); // 数据3
processedHeatmap.push([ dateIndex, 3, d1, d5 == 1 ? "yellow" : "transparent", ]); // 数据4
}); heatmapData.value = processedHeatmap; // 处理折线图数据
lineData3.value = rawData2.value.map((item) => item[9]); console.log("热力图数据:", heatmapData.value); console.log("折线图数据:", lineData3.value); const data = kline; // 切割数据方法
const spliteDate = (a) => { const categoryData = []; let value = []; for (let i = 0; i < a.length; i++) { // 使用非破坏性的方法,避免修改原数组
categoryData.push(a[i][0]); value.push(a[i].slice(1)); // 使用 slice 而不是 splice
} return { categoryData, value }; }; const dealData = spliteDate(data); // 给配置项
const KlineOption = { tooltip: { trigger: 'item', // 触发类型 坐标轴触发
axisPointer: { type: 'cross', // 十字准星效果
crossStyle: { color: '#999' } }, formatter: function (params) { const date = params.name // 开收低高分别取参数的第2到第5个数
const open = params.data[1] const close = params.data[2] const low = params.data[3] const high = params.data[4] return `日期: ${date}<br/>开盘价: ${open}<br/>收盘价: ${close}<br/>最低价: ${low}<br/>最高价: ${high}`
} },
//控制坐标轴
grid: [ { top: "5%", height: window.innerWidth <= 768 ? "30%" : "40%" }, { top: window.innerWidth <= 768 ? "35%" :"45%", height: "35%" }, { top: window.innerWidth <= 768 ? "70%" : "80%", height: "2%" }, ],
visualMap: [ { show: false, // 不显示控制条
seriesIndex: 1, // 作用于热力图的系列
min: 0, max: 2000, // 根据您的数据范围调整
calculable: true, orient: "horizontal", left: "center", bottom: "15%", inRange: { color: ["transparent"], }, }, ], // 横坐标内容
xAxis: [ { type: "category", gridIndex: 0, data: dealData.categoryData, axisPointer: { show: true, type: "line", label: { show: true, backgroundColor: 'rgba(0,191,255)', color: 'black' }, }, axisTick: { show: false }, // 隐藏刻度线
axisLabel: { show: false, rotate: 45 }, // 隐藏刻度标签
axisLine: { show: true, lineStyle: { color: "white", }, }, }, { type: "category", gridIndex: 1, data: dealData.categoryData, axisTick: { show: false }, // 隐藏刻度线
axisLabel: { show: false, rotate: 45 }, // 隐藏刻度标签
splitLine: { show: true, lineStyle: { color: "white", // 间隔线类型实线
type: "solid", }, interval: 0, }, }, { type: "category", gridIndex: 2, data: dealData.categoryData, axisLine: { lineStyle: { color: "white" } }, axisPointer: { show: false, label: { show: false, }, type: "line", }, axisTick: { show: true, alignWithLabel: true, // 刻度线与标签对齐
lineStyle: { color: "white", // 与十字线颜色保持一致
width: 1, type: "dashed" // 与十字线样式保持一致
} }, }, ], yAxis: [ { scale: true, axisLabel: { formatter: function (value) { return value; }, }, axisLine: { show: true, lineStyle: { color: "white" }, }, splitLine: { show: false, }, axisPointer: { show: true, label: { show: true, backgroundColor: 'rgba(0,255,127)', color: 'black' }, type: "line", }, }, { gridIndex: 1, type: "category", data: [0, 1, 2, 3], // 倒序显示
axisLine: { lineStyle: { color: "white" } }, axisLabel: { show: false, // 显示刻度标签
color: "#fff", // 白色文字
backgroundColor: "transparent", fontSize: 12, margin: 8, }, axisPointer: { show: true, label: { show: false, }, type: "line", }, axisTick: { show: false }, // 隐藏刻度线
splitLine: { show: true, lineStyle: { color: "#8392A5", width: 1, type: "solid", },
interval: 0, // 强制显示间隔
}, }, { gridIndex: 2, type: "value", axisLine: { show: true, lineStyle: { color: "white" }, }, splitLine: { show: !1, }, axisTick: { show: false }, // 隐藏刻度线
axisLabel: { show: false }, // 隐藏刻度标签
axisPointer: { show: false, label: { show: false, }, type: "line", }, }, ], // 下拉条
dataZoom: [ { textStyle: { color: "white", // 字体颜色
}, handleIcon: "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", handleSize: "80%", dataBackground: { areaStyle: { color: "#8392A5", }, lineStyle: { opacity: 0.8, color: "#8392A5", }, }, xAxisIndex: [0, 1, 2], handleStyle: { color: "#fff", shadowBlur: 3, shadowColor: "rgba(0, 0, 0, 0.6)", shadowOffsetX: 2, shadowOffsetY: 2, }, start: 50, // 默认展示后半部分数据
end: 100, bottom: "8%", // 下移数据缩放滑块
}, // {
// show: true,
// type: "slider",
// xAxisIndex: [0, 1, 2],
// bottom: "0%",
// textStyle: {
// color: "white",
// },
// },
{ type: "inside", xAxisIndex: [0, 1, 2], filterMode: "filter", }, ], series: [ { type: "candlestick", name: "\u65e5K", // 数据
data: dealData.value, itemStyle: { normal: { color0: "red", // 阴线颜色
color: "#0CF49B", // 阳线颜色
borderColor0: "#FD1050", // 阴线边框颜色
borderColor: "#0CF49B", // 阳线边框颜色
}, }, }, // 副图热力矩阵
{ name: "热力矩阵", type: "heatmap", gridIndex: 1, xAxisIndex: 1, yAxisIndex: 1, data: processedHeatmap, coordinateSystem: "cartesian2d", tooltip: { trigger: "item", axisPointer: { type: 'cross', // 十字准星效果
crossStyle: { color: '#999' } }, // 覆盖全局 tooltip 配置
formatter: function (params) { return `${params.value[2]}`; // 直接取数据中的第3个元素(数值)
} }, label: { normal: { show: true, color: "#fff", // 文本颜色
formatter: function (params) { const value = params.value[2]; // 数值
const colorType = params.value[3]; // 颜色类型
// 使用 rich 富文本格式
return `{${colorType}|${value}}`; }, rich: { green: { color: "#27ae60", fontWeight: "bold" }, purple: { color: "#8e44ad", fontWeight: "bold" }, red: { color: "#FF0000", fontWeight: "bold" }, yellow: { color: "#FFFF00", fontWeight: "bold" }, normal: { color: "#fff" }, }, }, }, itemStyle: { normal: { color: "transparent", borderWidth: 2, }, }, emphasis: { itemStyle: { shadowBlur: 10, shadowColor: "rgba(0, 0, 0, 0.5)", }, }, }, { name: "凸起", type: "line", xAxisIndex: 2, yAxisIndex: 2, data: lineData3.value, color: "black", lineStyle: { normal: { color: "red", }, },
symbol: "none", emphasis: { showSymbol: true, }, }, ], };
// 创造echarts图
if (KlineCanvsChart) { KlineCanvsChart.dispose(); } KlineCanvsChart = echarts.init(KlineCanvs.value); KlineCanvsChart.setOption(KlineOption);
// 防抖函数,避免频繁触发resize
const debounce = (func, wait) => { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; };
// 监听窗口大小变化,参考股市温度计的实现
const resizeHandler = debounce(() => { if (KlineCanvsChart && !KlineCanvsChart.isDisposed()) { try { KlineCanvsChart.resize(); console.log('情绪解码器图表已重新调整大小'); } catch (error) { console.error('情绪解码器图表resize失败:', error); } } }, 100); // 100ms防抖延迟
// 移除之前的监听器(如果存在)
if (window.emotionDecodResizeHandler) { window.removeEventListener('resize', window.emotionDecodResizeHandler); }
// 添加新的监听器
window.addEventListener('resize', resizeHandler);
// 存储resize处理器以便后续清理
window.emotionDecodResizeHandler = resizeHandler;
// 添加容器大小监听器
if (KlineCanvs.value && window.ResizeObserver) { const containerObserver = new ResizeObserver(debounce(() => { if (KlineCanvsChart && !KlineCanvsChart.isDisposed()) { try { KlineCanvsChart.resize(); console.log('情绪解码器容器大小变化,图表已调整'); } catch (error) { console.error('情绪解码器容器resize失败:', error); } } }, 100));
containerObserver.observe(KlineCanvs.value); window.emotionDecodContainerObserver = containerObserver; } } const windowHeight = ref(window.innerHeight); const updateHeight = () => { windowHeight.value = window.innerHeight; // 更新响应式变量
};
// 组件挂载时添加窗口高度监听
onMounted(() => { // 避免重复添加监听器
if (!window.emotionDecodHeightHandler) { window.addEventListener("resize", updateHeight); window.emotionDecodHeightHandler = updateHeight; } }); onBeforeUnmount(() => { // 组件卸载时销毁图表
if (KlineCanvsChart) { KlineCanvsChart.dispose(); KlineCanvsChart = null; }
// 移除窗口resize监听器
if (window.emotionDecodResizeHandler) { window.removeEventListener('resize', window.emotionDecodResizeHandler); window.emotionDecodResizeHandler = null; }
// 移除窗口高度监听器
if (window.emotionDecodHeightHandler) { window.removeEventListener('resize', window.emotionDecodHeightHandler); window.emotionDecodHeightHandler = null; }
// 清理容器观察器
if (window.emotionDecodContainerObserver) { window.emotionDecodContainerObserver.disconnect(); window.emotionDecodContainerObserver = null; } }); </script> <style scoped> .qxjmqbox { height: auto; width: 100%; margin: 0 auto; }
.qxjmqEcharts { width: 100%; height: 542px; margin: 0; /* top: 5rem; */ box-sizing: border-box; overflow: hidden; }
/* 手机端适配样式 */ @media only screen and (max-width: 768px) { .qxjmqEcharts { width: 100%; height: 400px; margin: 0; /* top: 5rem; */ }
.qxjmqbox { height: auto; width: 90%; }
} </style>
|