昨天突然想起上学时玩的文曲星(电子词典),里面有个猜数字的小游戏,于是拿 ECharts 试着做了一下,大体思路如下:
- 用基于直角坐标系上的 heatmap 做虚拟按键
- 用 graphic.elements[i]-text 和 graphic.elements[i]-rect 做文本框、提示框
- 监听 heatmap 的点击事件,输入数字、猜数
heatmap 虚拟按键实现
heatmap 数据准备
// 准备 heatmap 的按钮数据,用 '-1' 作为退格按钮、'-2'作为猜数按钮 var btnData = (function() { var res = []; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { if (j > 0) { res.push([i, j, '' + (j * 3 + i - 2)]); } else { res.push([i, j, '' + (0 - i)]); } } } return res; })();
heatmap 所在 x、y 坐标轴数据
var categoryX = ['0', '1', '2']; var categoryY = ['0', '1', '2', '3'];
heatmap 部分配置项
option = { title: { text: '文曲星词典猜数字游戏' }, tooltip: { show: false }, grid: { width: '30%', height: '60%', left: '10px', top: '30%' }, xAxis: { show: false, type: 'category', data: categoryX, splitArea: { show: true } }, yAxis: { show: false, type: 'category', data: categoryY, splitArea: { show: true } }, series: [{ id: 'btnPanel', type: 'heatmap', label: { normal: { show: true, formatter: function(params) { if (params.data[2] < 0) { return params.data[2] == -1 ? '?' : '猜'; } return params.data[2]; } } }, data: btnData }] };
- grid:直角坐标系位置等配置
- tooltip:隐藏提示框
- xAxis 和 yAxis:x 轴和 y 轴配置
- series[i]-heatmap:热力图配置,其中 label.formatter 使用回调函数把 '-1' 和 '-2' 分别换成 '←' 和 '猜',data 绑定之前准备好的heatmap 数据
graphic 输入框、提示框实现
输入框、提示框生成函数( 4个方块数字框 + 提示框),这个函数返回的 JSON 对象用于 option.graphic 配置
// 输入框、提示框生成函数( 4个方块数字框 + 提示框) function graphicObj(arr, msg) { var res = []; for (var i = 0; i < 4; i++) { res.push({ type: 'group', id: 'textGroup' + i, left: 50 + i * 60, top: 50, children: [{ type: 'rect', z: 100, left: 'center', top: 'center', shape: { width: 40, height: 50 }, style: { fill: '#fff', stroke: '#999', lineWidth: 2, shadowBlur: 8, shadowOffsetX: 3, shadowOffsetY: 3, shadowColor: 'rgba(0,0,0,0.3)' } }, { type: 'text', z: 100, top: 'middle', left: 'center', style: { text: typeof(arr[arr.length - 4 + i]) === 'undefined' ? '' : arr[arr.length - 4 + i], font: '20px "STHeiti", sans-serif' } } ] }); } res.push({ type: 'text', z: 100, top: '50', left: '400', style: { text: msg, font: '20px "STHeiti", sans-serif' } }); return res; }
- graphic.elements[i]-group:可以有子节点的容器
- graphic.elements[i]-text:文本块
- graphic.elements[i]-rect:矩形块
- 一个文本块和一个矩形块组成一个数字显示框,一起放到容器内部,通过容器整体定位
- 循环 4 次,生成 4 个包含文本块的容器,排成一行显示
- 单独添加一个文本块用于显示提示信息
- (偷懒没有按百分比定位)
交互部分实现
监听 heatmap 上的点击事件
// 点击热力图时调用 btnClick 函数 myChart.on('click', function(params) { if (params.seriesId === 'btnPanel' && times > 0) { btnClick(params.data[2]); } });
- params:用于传入图表的点击事件的基本参数
- params.seriesId:对应 option.series[i]-id
- params.data:对应 option.series[i]-data,此处 params.data[0] 对应 xAxis坐标,params.data[1] 对应 yAxis 坐标,params.data[2] 是该坐标对应的数值(也就是此前生成的按钮数据)
- times:用于记录还剩下几次猜数字机会
btnClick 函数定义
// 按钮点击响应函数 function btnClick(btnID) { if (btnID === '-1') { inputList.pop(); } else if (btnID === '-2') { return inputList.length === 4 ? guess(inputList) : alert('请先填入 4 个数字再猜!'); } else { inputList.length === 4 ? inputList[3] = btnID : inputList.push(btnID); } myChart.setOption({ graphic: graphicObj(inputList, msgList.join('\n')) }); }
- inputList:预先定义好的,用于存放猜数列表的数组变量
- <表达式1> ? <表达式2> : <表达式3> 三元表达式,如果<表达式1> 为真,则执行<表达式2>,否则执行<表达式3>
- btnID:传入的按钮数据
- 当 btnID 等于 '-1' 时,删除 inputList 最后一个数字
- 当 btnID 等于 '-2' 时,猜数字或提示不足 4 位数字
- 当 btnID 等于其他值时(0 到 9),在 inputList 末尾插入或替换一个数字
- myChart.setOption(option):更新图表,默认将 option 与之前的图标配置项合并
- myChart.setOption(option, false):更新图表,用此 option 替换原配置项
guess 函数定义
猜数函数 function guess(arr) { if (arr.length != 4) { return alert('请猜4位数字'); } var info; var A = 0; var B = 0; times--; for (var i = 0; i < 4; i++) { if (secretNumList.indexOf(arr[i]) === i) { A++; } else if (secretNumList.indexOf(arr[i]) != -1) { B++; } } if (A === 4) { info = arr.join('') + ' 猜中了!!!'; times = 0; } else { info = arr.join('') + ' ' + A + 'A' + B + 'B , 你还有' + times + '次机会...'; } msgList.push(info); inputList = []; myChart.setOption({ graphic: graphicObj(inputList, msgList.join('\n')) }); }
- 变量 A:数字和位置都猜对的数量
- 变量 B:仅数字猜对但位置猜错的数量
- 通过 for 循环分别匹配每一位所猜数字,根据匹配结果 A++ 或者 B++
- Array.indexOf(item) 方法,从 array 里查找 item ,如果存在则返回匹配的 Index ,否则 返回 -1
- 匹配完成后,如果 A === 4 则猜对了,否则通过类似 0A1B 的方式提示猜数的结果,通过 myChart.setOtion() 更新图表的提示区
点击「扩展链接」查看 ECharts Gallery 例子(建议PC查看)