Spaces:
Running
Running
Update static/index.html
Browse files- static/index.html +67 -15
static/index.html
CHANGED
|
@@ -1097,21 +1097,73 @@ function renderChartPage(){
|
|
| 1097 |
const info=document.createElement('span');info.className='page-info';info.textContent=`第${currentChartPage+1}/${totalPgs}頁,共${total}種方法`;pag.appendChild(info);
|
| 1098 |
}
|
| 1099 |
}
|
| 1100 |
-
function renderSingleChart(canvas,hist,predVal,nextYear,methodName,color){
|
| 1101 |
-
|
| 1102 |
-
const
|
| 1103 |
-
|
| 1104 |
-
const
|
| 1105 |
-
const
|
| 1106 |
-
|
| 1107 |
-
|
| 1108 |
-
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1115 |
});
|
| 1116 |
}
|
| 1117 |
function chartOptions(){
|
|
|
|
| 1097 |
const info=document.createElement('span');info.className='page-info';info.textContent=`第${currentChartPage+1}/${totalPgs}頁,共${total}種方法`;pag.appendChild(info);
|
| 1098 |
}
|
| 1099 |
}
|
| 1100 |
+
function renderSingleChart(canvas, hist, predVal, nextYear, methodName, color) {
|
| 1101 |
+
// 取得使用者選擇的圖形類型,預設為複合圖
|
| 1102 |
+
const chartStyle = document.getElementById('chartStyleSelect').value || 'mixed';
|
| 1103 |
+
|
| 1104 |
+
const labels = [...hist.map(d=>d.year)];
|
| 1105 |
+
const hv = [...hist.map(d=>d.value)];
|
| 1106 |
+
const hasP = !isNaN(predVal);
|
| 1107 |
+
const allLabels = hasP ? [...labels, nextYear] : [...labels];
|
| 1108 |
+
|
| 1109 |
+
// 【複合圖專用】將歷史與預測分離成不同長條
|
| 1110 |
+
const barData = hasP ? [...hv, null] : [...hv];
|
| 1111 |
+
const predBar = new Array(allLabels.length).fill(null);
|
| 1112 |
+
if(hasP) predBar[predBar.length-1] = predVal;
|
| 1113 |
+
|
| 1114 |
+
// 【連續圖專用】將歷史與預測接在一起
|
| 1115 |
+
const lineData = [...hv];
|
| 1116 |
+
if(hasP) lineData.push(predVal);
|
| 1117 |
+
|
| 1118 |
+
// 動態判定最後一個預測點的顏色與大小
|
| 1119 |
+
const pointColors = allLabels.map((_,i) => i===allLabels.length-1 && hasP ? 'rgba(230,180,80,1)' : color.line);
|
| 1120 |
+
const bgColors = allLabels.map((_,i) => i===allLabels.length-1 && hasP ? 'rgba(230,180,80,0.5)' : color.bar);
|
| 1121 |
+
const borderColors = allLabels.map((_,i) => i===allLabels.length-1 && hasP ? 'rgba(230,180,80,0.9)' : color.line);
|
| 1122 |
+
const pointRadii = allLabels.map((_,i) => i===allLabels.length-1 && hasP ? 7 : 4);
|
| 1123 |
+
|
| 1124 |
+
let datasets = [];
|
| 1125 |
+
|
| 1126 |
+
// 根據下拉選單決定要丟給 Chart.js 什麼資料結構
|
| 1127 |
+
if (chartStyle === 'mixed') {
|
| 1128 |
+
datasets = [
|
| 1129 |
+
{type:'bar', label:'歷史數值', data:barData, backgroundColor:color.bar, borderColor:color.line, borderWidth:1, order:2},
|
| 1130 |
+
{type:'bar', label:`預測值 (${methodName})`, data:predBar, backgroundColor:'rgba(230,180,80,0.5)', borderColor:'rgba(230,180,80,0.9)', borderWidth:2, order:2},
|
| 1131 |
+
{type:'line', label:'趨勢線', data:lineData, borderColor:color.line, backgroundColor:color.bar.replace('.4','.08'), borderWidth:2, fill:true, tension:0.3,
|
| 1132 |
+
pointRadius:pointRadii, pointBackgroundColor:pointColors, order:1}
|
| 1133 |
+
];
|
| 1134 |
+
} else if (chartStyle === 'line' || chartStyle === 'area') {
|
| 1135 |
+
datasets = [{
|
| 1136 |
+
type: 'line',
|
| 1137 |
+
label: '數值',
|
| 1138 |
+
data: lineData,
|
| 1139 |
+
borderColor: color.line,
|
| 1140 |
+
backgroundColor: color.bar.replace('.4', chartStyle === 'area' ? '.2' : '.0'), // 面積圖調整透明度
|
| 1141 |
+
borderWidth: 2,
|
| 1142 |
+
fill: chartStyle === 'area',
|
| 1143 |
+
tension: 0.3,
|
| 1144 |
+
pointRadius: pointRadii,
|
| 1145 |
+
pointBackgroundColor: pointColors,
|
| 1146 |
+
pointBorderColor: pointColors,
|
| 1147 |
+
segment: {
|
| 1148 |
+
// ★ 魔法在這裡:讓最後一段連接預測值的線段變成金色與虛線
|
| 1149 |
+
borderColor: ctx => ctx.p0DataIndex === allLabels.length - 2 ? 'rgba(230,180,80,1)' : color.line,
|
| 1150 |
+
borderDash: ctx => ctx.p0DataIndex === allLabels.length - 2 ? [5, 5] : undefined
|
| 1151 |
+
}
|
| 1152 |
+
}];
|
| 1153 |
+
} else if (chartStyle === 'bar') {
|
| 1154 |
+
datasets = [{
|
| 1155 |
+
type: 'bar',
|
| 1156 |
+
label: '數值',
|
| 1157 |
+
data: lineData,
|
| 1158 |
+
backgroundColor: bgColors,
|
| 1159 |
+
borderColor: borderColors,
|
| 1160 |
+
borderWidth: 1
|
| 1161 |
+
}];
|
| 1162 |
+
}
|
| 1163 |
+
|
| 1164 |
+
return new Chart(canvas, {
|
| 1165 |
+
data: { labels: allLabels, datasets: datasets },
|
| 1166 |
+
options: chartOptions()
|
| 1167 |
});
|
| 1168 |
}
|
| 1169 |
function chartOptions(){
|