⚲
專案
一般
配置概況
登入
註冊
網站首頁
專案清單
說明
搜尋
:
Grafana報表系統
全部的專案
Grafana報表系統
概觀
活動
議題清單
新聞
下載 (9.05 KB)
工作單 #199
» P9802003-Daily Risk Prediction Results (_) Business Chart.json
marlboro chu, 2025-06-30 02:03
{
"result"
:
{
"id"
:
635
,
"orgId"
:
1
,
"folderId"
:
136
,
"folderUid"
:
"bemeqa2prz7k0d"
,
"uid"
:
"feop1zzhg3xfkf"
,
"name"
:
"P9802003-Daily Risk Prediction Results (%) Business Chart"
,
"kind"
:
1
,
"type"
:
"volkovlabs-echarts-panel"
,
"description"
:
""
,
"model"
:
{
"datasource"
:
{
"type"
:
"elasticsearch"
,
"uid"
:
"f45b49c9-ba56-43c8-b278-a87adffdb57c"
},
"description"
:
""
,
"fieldConfig"
:
{
"defaults"
:
{
},
"overrides"
:
[
]
},
"gridPos"
:
{
"h"
:
9
,
"w"
:
12
,
"x"
:
12
,
"y"
:
20
},
"id"
:
9802003
,
"options"
:
{
"baidu"
:
{
"callback"
:
"bmapReady"
,
"key"
:
""
},
"editor"
:
{
"format"
:
"auto"
},
"editorMode"
:
"visual"
,
"gaode"
:
{
"key"
:
""
,
"plugin"
:
"AMap.Scale,AMap.ToolBar"
},
"getOption"
:
"const series = context.panel.data.series.map((s) => {
\n
const sData = s.fields.find((f) => f.type === 'number').values.buffer || s.fields.find((f) => f.type === 'number').values;
\n
const sTime = s.fields.find((f) => f.type === 'time').values.buffer || s.fields.find((f) => f.type === 'time').values;
\n
\n
return {
\n
name: s.refId,
\n
type: 'line',
\n
showSymbol: false,
\n
areaStyle: {
\n
opacity: 0.1,
\n
},
\n
lineStyle: {
\n
width: 1,
\n
},
\n
data: sData.map((d, i) => [sTime[i], d.toFixed(2)]),
\n
};
\n
});
\n\n
/**
\n
* Enable Data Zoom by default
\n
*/
\n
setTimeout(() => context.panel.chart.dispatchAction({
\n
type: 'takeGlobalCursor',
\n
key: 'dataZoomSelect',
\n
dataZoomSelectActive: true,
\n
}), 500);
\n\n
/**
\n
* Update Time Range on Zoom
\n
*/
\n
context.panel.chart.on('datazoom', function (params) {
\n
const startValue = params.batch[0]?.startValue;
\n
const endValue = params.batch[0]?.endValue;
\n
locationService.partial({ from: startValue, to: endValue });
\n
});
\n\n
return {
\n
backgroundColor: 'transparent',
\n
tooltip: {
\n
trigger: 'axis',
\n
},
\n
legend: {
\n
left: '0',
\n
bottom: '0',
\n
data: context.panel.data.series.map((s) => s.refId),
\n
textStyle: {
\n
color: 'rgba(128, 128, 128, .9)',
\n
},
\n
},
\n
toolbox: {
\n
feature: {
\n
dataZoom: {
\n
yAxisIndex: 'none',
\n
icon: {
\n
zoom: 'path://',
\n
back: 'path://',
\n
},
\n
},
\n
saveAsImage: {},
\n
}
\n
},
\n
xAxis: {
\n
type: 'time',
\n
},
\n
yAxis: {
\n
type: 'value',
\n
min: 'dataMin',
\n
},
\n
grid: {
\n
left: '2%',
\n
right: '2%',
\n
top: '2%',
\n
bottom: 24,
\n
containLabel: true,
\n
},
\n
series,
\n
};"
,
"google"
:
{
"callback"
:
"gmapReady"
,
"key"
:
""
},
"map"
:
"none"
,
"renderer"
:
"canvas"
,
"themeEditor"
:
{
"config"
:
"{}"
,
"name"
:
"default"
},
"visualEditor"
:
{
"code"
:
"let allTimestampsSet = new Set();
\n
let seriesMap = {};
\n
let yAxisMax = 100;
\n\n
context.panel.data.series.forEach(serie => {
\n
const name = serie.name.toLowerCase();
\n
const timeField = serie.fields.find(f => f.name === 'Time');
\n
const valueField = serie.fields.find(f => f.name !== 'Time');
\n\n
const times = timeField.values.toArray();
\n
const values = valueField.values.toArray();
\n\n
// 將 timestamp 存入 set
\n
times.forEach(ts => allTimestampsSet.add(ts));
\n\n
// 建立 timestamp -> value 的對照表(Map)
\n
let valueMap = new Map();
\n
for (let i = 0; i < times.length; i++) {
\n
valueMap.set(times[i], values[i]);
\n
}
\n\n
seriesMap[name] = valueMap;
\n
});
\n\n
// 2. 整理 x 軸時間並排序(升冪)
\n
let allTimestamps = Array.from(allTimestampsSet).sort();
\n\n
// 3. 把 timestamp 轉為 MM/dd 格式
\n
let xAxisData = allTimestamps.map(ts => {
\n
const d = new Date(ts);
\n
return `${(d.getMonth() + 1).toString().padStart(2, '0')}/${d.getDate().toString().padStart(2, '0')}`;
\n
});
\n\n
// 4. 為每個 series 組出對齊的 y 資料
\n
function getSeriesData(name) {
\n
const valueMap = seriesMap[name] || new Map();
\n
return allTimestamps.map(ts => valueMap.get(ts) ?? 0); // 若沒對到則補 0
\n
}
\n\n
let dataLow = getSeriesData('01');
\n
let dataMid = getSeriesData('02');
\n
let dataHigh = getSeriesData('03');
\n\n
const dataTotal = dataMid.map((val, idx) => {
\n
return val + (dataHigh[idx] || 0) + (dataLow[idx] || 0);
\n
});
\n\n\n
const dataHighPercentage = dataHigh.map((val, idx) => {
\n
let total = dataTotal[idx] || 1;
\n
return +(val / total * 100).toFixed(2);
\n
});
\n\n
const dataMidPercentage = dataMid.map((val, idx) => {
\n
let total = dataTotal[idx] || 1;
\n
return +(val / total * 100).toFixed(2);
\n
});
\n\n
const dataLowPercentage = dataLow.map((val, idx) => {
\n
let total = dataTotal[idx] || 1;
\n
return +(val / total * 100).toFixed(2);
\n
});
\n\n
// let max = Math.max(...dataLow);
\n
// if (max > yAxisMax) yAxisMax = Math.ceil(max * 1.1);
\n
// max = Math.max(...dataMid);
\n
// if (max > yAxisMax) yAxisMax = Math.ceil(max * 1.1);
\n
// max = Math.max(...dataHigh);
\n
// if (max > yAxisMax) yAxisMax = Math.ceil(max * 1.1);
\n\n
// const magnitude = Math.pow(10, Math.floor(Math.log10(yAxisMax)));
\n
// yAxisMax = Math.ceil(yAxisMax / magnitude) * magnitude;
\n\n
const seriesConfig = [
\n\n
{
\n
name: 'low',
\n
data: dataLowPercentage,
\n
//color: 'rgb(55, 135, 45)'
\n
color: 'rgb(86, 166, 75)'
\n
},
\n
{
\n
name: 'mid',
\n
data: dataMidPercentage,
\n
color: 'rgb(242, 204, 12)'
\n
},
\n
{
\n
name: 'high',
\n
data: dataHighPercentage,
\n
color: 'rgb(196, 22, 42)'
\n
}
\n
];
\n\n
const seriesData = seriesConfig.map(cfg => ({
\n
name: cfg.name,
\n
type: 'bar',
\n
barWidth: '98%',
\n
data: cfg.data,
\n
stack: 'line',
\n
itemStyle: {
\n
color: cfg.color
\n
}
\n
}));
\n\n
option = {
\n
tooltip: {
\n
trigger: 'axis',
\n
axisPointer: {
\n
type: 'line' // 或 'line',視覺效果不同
\n
},
\n
formatter: function (params) {
\n
let tooltipText = params[0].axisValue + '<br/>';
\n
params.forEach(item => {
\n
tooltipText += `${item.marker} ${item.seriesName}: ${item.data}%<br/>`;
\n
});
\n
return tooltipText;
\n
}
\n
},
\n
legend: {
\n
left: 'left',
\n
bottom: '0%',
\n
itemHeight: 5,
\n
itemWidth: 15,
\n
padding: [10, 20, 16, 20]
\n
},
\n
xAxis: {
\n
type: 'category',
\n
data: xAxisData
\n
},
\n
yAxis: {
\n
type: 'value',
\n
// axisLabel: {
\n
// formatter: value => value + '%'
\n
// }
\n
min: 0,
\n
max: 100,
\n
axisLabel: {
\n
formatter: value => value + '%'
\n
}
\n
},
\n
grid: {
\n
left: '2%',
\n
right: '2%',
\n
bottom: '15%',
\n
top: '10%',
\n
containLabel: true
\n
},
\n
series: seriesData
\n
};
\n\n
return option;
\n
"
,
"dataset"
:
[
],
"series"
:
[
]
}
},
"pluginVersion"
:
"6.6.0"
,
"targets"
:
[
{
"alias"
:
""
,
"bucketAggs"
:
[
{
"field"
:
"resultInfo__decisionCode"
,
"id"
:
"2"
,
"settings"
:
{
"min_doc_count"
:
"1"
,
"missing"
:
"未回應"
,
"order"
:
"desc"
,
"orderBy"
:
"1"
,
"size"
:
"0"
},
"type"
:
"terms"
},
{
"field"
:
"create_datetime"
,
"id"
:
"4"
,
"settings"
:
{
"interval"
:
"1d"
,
"min_doc_count"
:
"0"
,
"timeZone"
:
"Asia/Taipei"
,
"trimEdges"
:
"0"
},
"type"
:
"date_histogram"
}
],
"datasource"
:
{
"type"
:
"elasticsearch"
,
"uid"
:
"f45b49c9-ba56-43c8-b278-a87adffdb57c"
},
"metrics"
:
[
{
"id"
:
"1"
,
"type"
:
"count"
}
],
"query"
:
"${decision_query:raw} AND resultInfo__decisionCode : *"
,
"refId"
:
"A"
,
"timeField"
:
"create_datetime"
},
{
"alias"
:
""
,
"bucketAggs"
:
[
{
"field"
:
"create_datetime"
,
"id"
:
"2"
,
"settings"
:
{
"interval"
:
"1d"
,
"timeZone"
:
"Asia/Taipei"
},
"type"
:
"date_histogram"
}
],
"datasource"
:
{
"type"
:
"elasticsearch"
,
"uid"
:
"f45b49c9-ba56-43c8-b278-a87adffdb57c"
},
"hide"
:
false
,
"metrics"
:
[
{
"id"
:
"1"
,
"type"
:
"count"
}
],
"query"
:
"${decision_query:raw} "
,
"refId"
:
"B"
,
"timeField"
:
"create_datetime"
}
],
"title"
:
"B-02. Daily Risk Level Distribution (Percentage)"
,
"type"
:
"volkovlabs-echarts-panel"
},
"version"
:
2
,
"meta"
:
{
"folderName"
:
"R98-Library"
,
"folderUid"
:
"bemeqa2prz7k0d"
,
"connectedDashboards"
:
2
,
"created"
:
"2025-06-12T10:57:48+08:00"
,
"updated"
:
"2025-06-12T13:26:26+08:00"
,
"createdBy"
:
{
"avatarUrl"
:
"/avatar/ce6412d58e966caaa26cac12eb99734b"
,
"id"
:
1
,
"name"
:
"admin"
},
"updatedBy"
:
{
"avatarUrl"
:
"/avatar/ce6412d58e966caaa26cac12eb99734b"
,
"id"
:
1
,
"name"
:
"admin"
}
}
}
}
« 上一頁
1
…
20
21
22
23
24
…
30
下一頁 »
(22-22/30)
載入中...