plainheart commented on issue #21703:
URL: https://github.com/apache/echarts/issues/21703#issuecomment-5057042404

   Hi @cnlnr, we can 100% implement this right now using a combination of 
`type: 'line'` (for the continuous curved boundaries), `type: 'custom'` (for 
the current phase bar), and driving the reactive state logic outside the 
renderer via standard mathematical evaluation functions. Here is a working demo 
based on this approach and generated with AI assistance.
   
   https://codepen.io/plainheart/pen/EaZeKXJ
   
   <details>
   <summary>Click To View Code</summary>
   
   ```html
   <!DOCTYPE html>
   <html lang="zh-CN">
   <head>
       <meta charset="UTF-8">
       <title>ECharts 曲界线柱状图 (Phase-Bar Diagram)</title>
       <style>
           body { background-color: #0b0f19; color: #fff; font-family: 
sans-serif; margin: 20px; }
           .container { max-width: 800px; margin: 0 auto; background: #121826; 
padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); }
           h3 { margin-top: 0; text-align: center; font-weight: normal; color: 
#e1e7f0; }
           h5 { text-align: center; color: #737d8c; margin-top: -10px; 
margin-bottom: 20px; font-weight: normal; font-size: 13px; }
           #chart { width: 100%; height: 420px; }
           .controls { display: flex; flex-direction: column; gap: 15px; 
margin-top: 20px; border-top: 1px solid #1f293d; padding-top: 20px; }
           .control-row { display: flex; align-items: center; justify-content: 
space-between; }
           .control-row label { width: 160px; color: #8e9aa8; font-size: 14px; }
           .control-row input { flex: 1; margin: 0 15px; cursor: pointer; }
           .control-row span { width: 90px; text-align: right; font-weight: 
bold; font-family: monospace; font-size: 14px; }
           .result-panel { background: #1a2336; padding: 15px; border-radius: 
6px; margin-top: 20px; display: flex; justify-content: space-between; 
align-items: center; border-left: 4px solid #3b82f6; transition: border-color 
0.3s; }
           .result-panel span { font-size: 14px; color: #8e9aa8; }
           .result-panel strong { font-size: 18px; transition: color 0.3s; }
       </style>
        <script 
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js";></script>
   </head>
   <body>
   
   <div class="container">
       <h3>曲界线柱状图 (Phase-Bar Diagram)</h3>
       <h5>动态调整气压与温度,观察柱体顶点跨越曲界线时的状态变更</h5>
   
       <div id="chart"></div>
   
       <div class="controls">
           <div class="control-row">
               <label>压强 (Pressure / P):</label>
               <input type="range" id="pressInput" min="0" max="10" step="0.01" 
value="1.00">
               <span id="pressVal">1.00 atm</span>
           </div>
           <div class="control-row">
               <label>温度 (Temperature / T):</label>
               <input type="range" id="tempInput" min="-50" max="450" step="1" 
value="25">
               <span id="tempVal">25 °C</span>
           </div>
       </div>
   
       <div class="result-panel" id="resultBorder">
           <span>当前物理状态判定 (Current Phase Determination)</span>
           <strong id="phaseResult">液态 (Liquid)</strong>
       </div>
   </div>
   
   <script>
       const chartDom = document.getElementById('chart');
       const myChart = echarts.init(chartDom);
   
       const domainP = { min: 0, max: 10 };
       const domainT = { min: -50, max: 450 };
   
       const triplePoint = { p: 0.8, t: 0.01 };
       const criticalPoint = { p: 7.5, t: 374 };
   
       const PHASE_CONFIG = {
           SOLID: { name: '固态 (Solid)', color: '#38bdf8', border: '#0284c7' },
           LIQUID: { name: '液态 (Liquid)', color: '#3b82f6', border: '#1d4ed8' },
           GAS: { name: '气态 (Gas)', color: '#e3b341', border: '#d97706' },
           SUPERCRITICAL: { name: '超临界流体 (Supercritical)', color: '#bc8cff', 
border: '#8957e5' }
       };
   
       // 弯曲界线函数方程
       function getSublimationT(p) {
           if (p > triplePoint.p) return null;
           return domainT.min + (triplePoint.t - domainT.min) * Math.pow(p / 
triplePoint.p, 0.6);
       }
   
       // 汽化线:从三相点延伸到临界点
       function getVaporizationT(p) {
           if (p < triplePoint.p || p > criticalPoint.p) return null;
           const normP = (p - triplePoint.p) / (criticalPoint.p - 
triplePoint.p);
           return triplePoint.t + (criticalPoint.t - triplePoint.t) * 
Math.pow(normP, 0.45);
       }
   
       // 熔化线:从三相点向右上方延伸(实际随P增大而轻微下降)
       function getMeltingT(p) {
           if (p < triplePoint.p) return null;
           return triplePoint.t - 3.5 * Math.log(p / triplePoint.p + 1);
       }
   
       // 物理相态判定
       function evaluatePhase(p, t) {
           if (p >= criticalPoint.p && t >= criticalPoint.t) {
               return PHASE_CONFIG.SUPERCRITICAL;
           }
           if (p < triplePoint.p) {
               const subT = getSublimationT(p);
               return t < subT ? PHASE_CONFIG.SOLID : PHASE_CONFIG.GAS;
           } else {
               const meltT = getMeltingT(p);
               if (t < meltT) return PHASE_CONFIG.SOLID;
   
               if (p <= criticalPoint.p) {
                   const vapT = getVaporizationT(p);
                   return t < vapT ? PHASE_CONFIG.LIQUID : PHASE_CONFIG.GAS;
               } else {
                   return PHASE_CONFIG.LIQUID;
               }
           }
       }
   
       // 生成平滑的高密度数据线段
       const subData = [];   // 升华线 (0 -> 三相点)
       const vapData = [];   // 汽化线 (三相点 -> 临界点)
       const meltData = [];  // 熔化线 (三相点 -> 10)
   
       for (let p = 0; p <= 10; p += 0.01) {
           const sT = getSublimationT(p);
           if (sT !== null) subData.push([p, sT]);
   
           const vT = getVaporizationT(p);
           if (vT !== null) vapData.push([p, vT]);
   
           const mT = getMeltingT(p);
           if (mT !== null) meltData.push([p, mT]);
       }
   
       function updateChart() {
           const p = parseFloat(document.getElementById('pressInput').value);
           const t = parseFloat(document.getElementById('tempInput').value);
   
           document.getElementById('pressVal').innerText = p.toFixed(2) + ' 
atm';
           document.getElementById('tempVal').innerText = t + ' °C';
   
           const currentPhase = evaluatePhase(p, t);
           
           const resultEl = document.getElementById('phaseResult');
           const borderEl = document.getElementById('resultBorder');
           resultEl.innerText = currentPhase.name;
           resultEl.style.color = currentPhase.color;
           borderEl.style.borderColor = currentPhase.border;
   
           const option = {
               backgroundColor: 'transparent',
               animation: false,
                        textStyle: {
                                fontFamily: 'monospace'
                        },
               grid: { left: '5%', right: '6%', bottom: '8%', top: '8%', 
containLabel: true },
               xAxis: {
                   type: 'value',
                   min: domainP.min,
                   max: domainP.max,
                                boundaryGap: [0, 0],
                   interval: 2,
                   axisLabel: { color: '#8b949e', formatter: (val) => val + ' 
atm' },
                   splitLine: { show: true, lineStyle: { color: '#30363d' } },
                   axisLine: { show: true, lineStyle: { color: '#30363d' } }
               },
               yAxis: {
                   type: 'value',
                   min: domainT.min,
                   max: domainT.max,
                   interval: 50,
                   axisLabel: {
                                    color: '#8b949e',
                                        formatter: (value) => value + ' °C'
                                },
                   splitLine: {
                                    show: true,
                                        lineStyle: { color: '#30363d' }
                                },
                   axisLine: { show: true, lineStyle: { color: '#30363d' } }
               },
               series: [
                   // 升华线
                   {
                       name: '升华边界',
                       type: 'line',
                       data: subData,
                       showSymbol: false,
                       lineStyle: { color: '#38bdf8', width: 2, type: 'dashed' 
},
                       z: 2
                   },
                   // 汽化线:黄色实线段
                   {
                       name: '汽化边界',
                       type: 'line',
                       data: vapData,
                       showSymbol: false,
                       lineStyle: { color: '#e3b341', width: 2.5 },
                       z: 2
                   },
                   // 熔化线
                   {
                       name: '熔化边界',
                       type: 'line',
                       data: meltData,
                       showSymbol: false,
                       lineStyle: { color: '#00e676', width: 2 },
                       z: 2
                   },
                   // 特征点标记(三相点、临界点)
                   {
                       name: '特征点',
                       type: 'scatter',
                       data: [
                           { value: [triplePoint.p, triplePoint.t], itemStyle: 
{ color: '#ff4d4f' }, label: { formatter: '三相点 (Triple Point)', color: 
'#00e676', position: 'right' } },
                           { value: [criticalPoint.p, criticalPoint.t], 
itemStyle: { color: '#bc8cff' }, label: { formatter: '临界点 (Critical Point)', 
color: '#bc8cff', position: 'right' } }
                       ],
                       symbolSize: 7,
                       label: { show: true, fontSize: 11, offset: [5, 0] },
                       z: 4
                   },
                   // 状态主柱体
                   {
                                        name: '当前状态',
                                        type: 'custom',
                                        data: [[p, t]],
                                        renderItem: function (params, api) {
                                                const currentPoint = 
api.coord([api.value(0), api.value(1)]); 
                                                const bottomPoint = 
api.coord([api.value(0), domainT.min]);   
                                                const barWidth = 16;
                                                return {
                                                        type: 'rect',
                                                        shape: {
                                                                x: 
currentPoint[0] - barWidth / 2,
                                                                y: 
currentPoint[1],
                                                                width: barWidth,
                                                                height: 
bottomPoint[1] - currentPoint[1]
                                                        },
                                                        style: api.style({
                                                                fill: 
currentPhase.color,
                                                                stroke: 
currentPhase.border,
                                                                lineWidth: 1.5
                                                        })
                                                };
                                        },
                                        label: {
                                                show: true,
                                                position: 'top',
                                                color: '#fff',
                                                backgroundColor: '#0b0f19',
                                                padding: [4,6],
                                                borderWidth: 1,
                                                borderColor: 
currentPhase.border,
                                                formatter: t + '°C',
                                                offset: [0, -4]
                                        },
                                        z: 3
                                }
               ]
           };
   
           myChart.setOption(option);
       }
   
       document.getElementById('pressInput').addEventListener('input', 
updateChart);
       document.getElementById('tempInput').addEventListener('input', 
updateChart);
   
       updateChart()
   
       window.addEventListener('resize', () => myChart.resize());
   </script>
   </body>
   </html>
   ```
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to