新增SPC Vue控制图项目
This commit is contained in:
187
spc-vue/src/utils/chartOptions.ts
Normal file
187
spc-vue/src/utils/chartOptions.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { EChartsOption } from "echarts";
|
||||
import type { ControlLimitChart, CpkResult } from "../types/spc";
|
||||
|
||||
const chartColors = ["#0f766e", "#b45309", "#991b1b", "#2563eb"];
|
||||
|
||||
// 生成从 1 开始的子组序号,用于控制图横轴。
|
||||
export function sequenceLabels(length: number): string[] {
|
||||
return Array.from({ length }, (_, index) => String(index + 1));
|
||||
}
|
||||
|
||||
// 生成固定值线,用于 CL、UCL、LCL。
|
||||
function constantSeries(length: number, value: number): number[] {
|
||||
return Array.from({ length }, () => value);
|
||||
}
|
||||
|
||||
// 找出越过控制限的点,作为红色散点叠加在控制图上。
|
||||
function outOfLimitPoints(values: readonly number[], upper: number, lower: number): Array<[number, number]> {
|
||||
return values
|
||||
.map((value, index) => ({ value, index }))
|
||||
.filter((point) => point.value > upper || point.value < lower)
|
||||
.map((point) => [point.index, point.value]);
|
||||
}
|
||||
|
||||
// 创建单张控制图配置,包含数据线、中心线、上下控制限和越界点。
|
||||
export function createControlLimitOption(chart: ControlLimitChart): EChartsOption {
|
||||
const labels = sequenceLabels(chart.values.length);
|
||||
const outliers = outOfLimitPoints(chart.values, chart.upper, chart.lower);
|
||||
|
||||
return {
|
||||
color: chartColors,
|
||||
tooltip: { trigger: "axis" },
|
||||
legend: { top: 0, right: 0 },
|
||||
grid: { left: 56, right: 28, top: 46, bottom: 44 },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
name: "子组",
|
||||
data: labels,
|
||||
boundaryGap: false,
|
||||
axisLabel: { color: "#667085" }
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
name: chart.valueName,
|
||||
scale: true,
|
||||
axisLabel: { color: "#667085" },
|
||||
splitLine: { lineStyle: { color: "#e5e7eb" } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: chart.valueName,
|
||||
type: "line",
|
||||
data: [...chart.values],
|
||||
symbolSize: 6,
|
||||
lineStyle: { width: 2 }
|
||||
},
|
||||
{
|
||||
name: "CL",
|
||||
type: "line",
|
||||
data: constantSeries(chart.values.length, chart.center),
|
||||
symbol: "none",
|
||||
lineStyle: { type: "dashed", width: 1.5 }
|
||||
},
|
||||
{
|
||||
name: "UCL",
|
||||
type: "line",
|
||||
data: constantSeries(chart.values.length, chart.upper),
|
||||
symbol: "none",
|
||||
lineStyle: { type: "dotted", width: 1.5 }
|
||||
},
|
||||
{
|
||||
name: "LCL",
|
||||
type: "line",
|
||||
data: constantSeries(chart.values.length, chart.lower),
|
||||
symbol: "none",
|
||||
lineStyle: { type: "dotted", width: 1.5 }
|
||||
},
|
||||
{
|
||||
name: "越界点",
|
||||
type: "scatter",
|
||||
data: outliers,
|
||||
symbolSize: 10,
|
||||
itemStyle: { color: "#dc2626" }
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// 创建过程能力指标柱状图,便于快速查看 Cp/Cpk/Pp/Ppk 门槛。
|
||||
export function createCapabilityBarOption(cpk: CpkResult): EChartsOption {
|
||||
const labels = ["Cp", "Cpk", "Pp", "Ppk", "CPU", "CPL"];
|
||||
|
||||
return {
|
||||
color: ["#0f766e"],
|
||||
tooltip: { trigger: "axis" },
|
||||
grid: { left: 48, right: 24, top: 36, bottom: 42 },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: labels,
|
||||
axisLabel: { color: "#667085" }
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisLabel: { color: "#667085" },
|
||||
splitLine: { lineStyle: { color: "#e5e7eb" } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "能力指标",
|
||||
type: "bar",
|
||||
data: labels.map((label) => cpk[label as keyof CpkResult] as number),
|
||||
barMaxWidth: 34,
|
||||
itemStyle: {
|
||||
color: (params) => {
|
||||
const value = Number(params.value);
|
||||
if (value >= 1.33) return "#15803d";
|
||||
if (value >= 1) return "#b45309";
|
||||
return "#b91c1c";
|
||||
}
|
||||
},
|
||||
markLine: {
|
||||
symbol: "none",
|
||||
data: [
|
||||
{ yAxis: 1, name: "1.00" },
|
||||
{ yAxis: 1.33, name: "1.33" }
|
||||
],
|
||||
label: { color: "#667085" },
|
||||
lineStyle: { color: "#b45309", type: "dashed" }
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// 创建直方图和正态曲线配置,用来核对分布和规格限位置。
|
||||
export function createHistogramOption(cpk: CpkResult): EChartsOption {
|
||||
return {
|
||||
color: ["#0f766e", "#b45309"],
|
||||
tooltip: { trigger: "axis" },
|
||||
legend: { top: 0, right: 0 },
|
||||
grid: { left: 52, right: 48, top: 46, bottom: 42 },
|
||||
xAxis: {
|
||||
type: "value",
|
||||
name: "测量值",
|
||||
axisLabel: { color: "#667085" }
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
name: "频数",
|
||||
axisLabel: { color: "#667085" },
|
||||
splitLine: { lineStyle: { color: "#e5e7eb" } }
|
||||
},
|
||||
{
|
||||
type: "value",
|
||||
name: "正态曲线",
|
||||
axisLabel: { color: "#667085" },
|
||||
splitLine: { show: false }
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "频数",
|
||||
type: "bar",
|
||||
data: cpk.Xk.map((value, index) => [value, cpk.YkCount[index]]),
|
||||
barMaxWidth: 28,
|
||||
markLine: {
|
||||
symbol: "none",
|
||||
data: [
|
||||
{ xAxis: cpk.LSL, name: "LSL" },
|
||||
{ xAxis: cpk.USL, name: "USL" },
|
||||
{ xAxis: cpk.SL, name: "SL" }
|
||||
],
|
||||
label: { color: "#667085" },
|
||||
lineStyle: { color: "#991b1b", type: "dashed" }
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "正态曲线",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
symbolSize: 4,
|
||||
data: cpk.NormalDistributionX.map((value, index) => [value, cpk.NormalDistributionY[index]])
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user