How do I fix my echart charts that are using bigint?

4 weeks ago 13
ARTICLE AD BOX

I am working on a website dedicated to performing calculations of 3n + 1 (the Collatz conjecture) and creating various visualizations of this data.

I encountered a problem related to the numerical precision of values displayed on my charts. One of my working charts is shown in this prototype and is intended to display, with the maximum possible accuracy, the data from a list containing the results of the 3n + 1 calculations.

However, I ran into an undesirable issue: ECharts does not support BigInt, and since I am not very familiar with compilation or similar low-level solutions, I temporarily resorted to using logarithms (log10).

Eventually, I came to the conclusion that two charts are needed:

a mathematically exact chart, and

a logarithmic chart.

I found this website — Collatz Graph — where a mathematically exact chart was rendered on a (although it unfortunately breaks when numbers become extremely large). That result is roughly what I would like to achieve using ECharts.

I asked ChatGPT, Qwen, and Claude for help, but even they were unable to solve my problem, which is admittedly quite non-standard.

To clearly demonstrate the issue, I published a CodePen containing the code responsible for generating the chart (Codepen chart error example), but I am very dissatisfied with the result.

Also, I pinned some images to show you the difference between my chart and chart from Collatz Graph Vercel app and from my prototype (the white one with red lines is from the vercel app and the dark one is Echarts chart from my example / prototype. The original (first) number is 27.Echarts chart (mine) Collatz graph vercel app

As you can see, they are very different, however, my graphics that is forced to use log10 for Bigint numbers lack precision as in the CGVA (collatz graph vercel app)

I am quite bad at creating charts, so I am asking professionals for help.

What exactly I want is to create two graphs of displaying the calculation results: Mathematically accurate chart and Logarithmic one. It look like I have created a Logarithmic one, but I've faced problems that don't allow me to create a Mathematically Accurate chart.

idk how to describe my problem if not like that :_)

Code:

const inp = document.getElementById('input'); const runBtn = document.querySelector('.play'); const chartEl = document.getElementById('chart'); chartEl.style.width = '500px'; chartEl.style.height = '300px'; /* ===== input filter (NUMBERS ONLY (so you can input infinite amount of nums)) ===== */ inp.addEventListener('beforeinput', e => { if (e.data && !/^[0-9]+$/.test(e.data)) { e.preventDefault(); } }); /* ===== Collatz calculations BigInt ONLY ===== */ function collatzBigInt(n) { const spisok = []; if (n === 0n) return spisok; while (true) { spisok.push(n); if (n === 1n) break; if (n % 2n === 0n) { n = n / 2n; } else { n = n * 3n + 1n; } if (spisok.length > 20000) break; } return spisok; }; /* ===== graph compiler (BigInt -> Number) ===== */ function graphLogSize(value) { const s = value.toString(); const k = 15; if (s.length <= k) { return Math.log10(Number(s)); } const lead = Number(s.slice(0, k)); return Math.log10(lead) + (s.length - k); } /* ===== make nums short (for tooltip) ===== */ function toolTipShorten(value) { const s = value.toString(); if (s.length <= 15) return s; return s.slice(0, 6) + '...' + s.slice(-6); } // now its like 12345678901234567890 (big number) -> 123456...567890 /* ===== y-axis formatter (almost like function above this but for Yaxis) ===== */ function formatOriginalForAxis(value, sig = 2) { const s = value.toString(); if (s.length <= sig) return s; const exp = s.length - 1; const lead = Number(s.slice(0, sig)); const mant = (lead / Math.pow(10, sig - 1)).toFixed(2).replace(/\.0+$/, ''); return `${mant}e+${exp}`; } /* ===== ECharts ===== */ const chart = echarts.init(chartEl, 'dark'); function renderGraph(spisok) { const nums = spisok.map(graphLogSize); const option = { title: { text: 'Linear chart' }, // tooltip (for chosen dot's info) tooltip: { trigger: 'axis', formatter(params) { const i = params[0].dataIndex; const v = spisok[i]; const even = v % 2n === 0n; return ` Step: ${i}<br> Value: ${toolTipShorten(v)}<br> Operation: ${even ? '/ 2' : '* 3 + 1'} `; } }, // zoom, save and all that stuff toolbox: { feature: { dataZoom: { yAxisIndex: 'none' }, restore: {}, saveAsImage: {} } }, dataZoom: [ { type: 'inside', start: 0, end: 100 }, { start: 0, end: 10 } ], // horizontal axis xAxis: { type: 'category', boundaryGap: false, data: spisok.map((_, i) => i) }, // vertical axis yAxis: { type: 'value', axisLabel: { formatter(v) { const real = Math.pow(10, v); // small nums - normal if (real < 1000) { return Math.round(real).toString(); } // medium size nums - shorten if (real < 1e6) { return real.toFixed(0); } // big nums - smth like 1e324 const exp = Math.floor(v); const mant = Math.pow(10, v - exp).toFixed(2).replace(/\.0+$/, ''); return `${mant}e+${exp}`; } } }, // doesnt matter i guess series: [{ type: 'line', data: nums, showSymbol: true, symbolSize: 6 }] }; chart.setOption(option, true); } /* ===== run ===== */ runBtn.addEventListener('click', () => { if (!inp.value) return; const n = BigInt(inp.value); const spisok = collatzBigInt(n); renderGraph(spisok); }); <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>lalal</title> <style> .chart-block { width: 500px; height: 300px; border: 2px solid black; margin-top: 20px; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/6.0.0/echarts.min.js"></script> </head> <body> <input type="text" class="inp" id="input" value="27" placeholder="Number"> <button class="play" id="run">Run</button> <div class="chart-block" id="chart"></div> <script src="html.js" defer></script> </body> </html>
Read Entire Article