使用JavaScript求三个集合的并集并实现页面及维恩图展示问题
三个集合并集计算与维恩图展示解决方案
原代码问题分析
你当前的代码直接对输入框的value调用concat是错误的——输入框返回的是字符串,不是数组,无法直接用数组方法处理。必须先把输入的字符串解析成数组,再计算并集。
1. 修正并集计算逻辑
假设用户输入的集合元素用逗号分隔(比如1,2,3),以下是修复后的计算代码:
function myFunction1() { // 封装输入解析函数:把输入字符串转成去空后的数组 const parseInputSet = (elementId) => { return document.getElementById(elementId).value .split(',') .map(item => item.trim()) .filter(item => item !== ''); // 过滤空字符串 }; // 获取三个集合的数组形式 const setA = parseInputSet("myseta"); const setB = parseInputSet("mysetb"); const setC = parseInputSet("mysetc"); // 用ES6 Set快速计算并集(自动去重) const unionSet = [...new Set([...setA, ...setB, ...setC])]; // 把结果展示到页面指定区域 document.getElementById("result").textContent = `并集结果:${unionSet.join(', ')}`; document.getElementById("union").textContent = unionSet.join(', '); // 渲染维恩图 renderVennDiagram(setA, setB, setC, unionSet); }
代码说明
parseInputSet:统一处理输入,把逗号分隔的字符串转成干净的数组,去掉空格和空项new Set([...setA, ...setB, ...setC]):合并三个数组后用Set去重,再转回数组,比filter+indexOf效率更高- 用
textContent替代innerHTML更安全(避免XSS风险)
2. 页面基础结构
确保HTML里有对应的输入、结果展示和维恩图容器:
<!-- 输入区域 --> <div> <input type="text" id="myseta" placeholder="集合A(逗号分隔,如1,2,3)"> <input type="text" id="mysetb" placeholder="集合B(逗号分隔,如2,3,4)"> <input type="text" id="mysetc" placeholder="集合C(逗号分隔,如3,4,5)"> <button onclick="myFunction1()">计算并集</button> </div> <!-- 结果展示 --> <div id="result"></div> <div id="union"></div> <!-- 维恩图容器 --> <div id="venn-container" style="width: 600px; height: 400px; margin-top: 20px;"></div>
3. 原生Canvas实现维恩图渲染
不用第三方库,直接用Canvas绘制三个相交圆,并根据元素所属集合标记位置:
function renderVennDiagram(setA, setB, setC, union) { const container = document.getElementById("venn-container"); container.innerHTML = ''; // 清空旧内容 // 创建Canvas const canvas = document.createElement('canvas'); canvas.width = container.offsetWidth; canvas.height = container.offsetHeight; container.appendChild(canvas); const ctx = canvas.getContext('2d'); // 圆的基础参数 const centerX = canvas.width / 2; const centerY = canvas.height / 2; const radius = 120; // 绘制三个相交的圆(带半透明填充) // 集合A(左) ctx.beginPath(); ctx.arc(centerX - radius, centerY, radius, 0, Math.PI * 2); ctx.strokeStyle = '#ff4444'; ctx.fillStyle = 'rgba(255, 68, 68, 0.1)'; ctx.fill(); ctx.stroke(); // 集合B(右) ctx.beginPath(); ctx.arc(centerX + radius, centerY, radius, 0, Math.PI * 2); ctx.strokeStyle = '#44aa44'; ctx.fillStyle = 'rgba(68, 170, 68, 0.1)'; ctx.fill(); ctx.stroke(); // 集合C(下) ctx.beginPath(); ctx.arc(centerX, centerY + radius, radius, 0, Math.PI * 2); ctx.strokeStyle = '#4444ff'; ctx.fillStyle = 'rgba(68, 68, 255, 0.1)'; ctx.fill(); ctx.stroke(); // 绘制元素文本的工具函数 const drawItem = (text, x, y, color) => { ctx.fillStyle = color; ctx.font = '14px Arial'; ctx.textAlign = 'center'; ctx.fillText(text, x, y); }; // 遍历并集元素,根据所属集合定位 union.forEach(item => { const inA = setA.includes(item); const inB = setB.includes(item); const inC = setC.includes(item); let x, y, color; if (inA && inB && inC) { // 三集合交集 x = centerX; y = centerY; color = '#ff8800'; } else if (inA && inB) { // A&B交集 x = centerX; y = centerY - radius/2; color = '#ff6666'; } else if (inA && inC) { // A&C交集 x = centerX - radius/2; y = centerY + radius/2; color = '#ff66bb'; } else if (inB && inC) { // B&C交集 x = centerX + radius/2; y = centerY + radius/2; color = '#66ffbb'; } else if (inA) { // 仅A x = centerX - radius - 20; y = centerY; color = '#ff4444'; } else if (inB) { // 仅B x = centerX + radius + 20; y = centerY; color = '#44aa44'; } else if (inC) { // 仅C x = centerX; y = centerY + radius + 20; color = '#4444ff'; } drawItem(item, x, y, color); }); }
维恩图说明
- 三个圆分别对应集合A(红)、B(绿)、C(蓝)
- 元素根据所属集合被放在对应区域,颜色区分归属:
- 橙色:同时属于三个集合
- 浅红/浅绿/浅紫:属于两个集合的交集
- 原色:仅属于单个集合
内容的提问来源于stack exchange,提问作者JLMR
相关产品推荐
相关产品推荐

