扫雷

描述:当前是关于Echarts图表中的 散点图 示例。
 
            var markUrl = "/asset/get/s/data-1502962358603-HkJ6fkX_b.png";

var xDotCnt = 20;
var yDotCnt = 16;
var mineCnt = 50;
var markedCnt = 0;
var startTime = null;

var mines = [];
var isMarking = false;

var series = [{
    name: 'isNotOpen',
    type: 'scatter',
    symbol: 'rect',
    symbolSize: 23,
    data: [],
    itemStyle: {
        normal: {
            color: '#c0c0c0',
            shadowColor: '#747474',
            shadowOffsetX: 3,
            shadowOffsetY: 3
        }
    }
}, {
    name: 'mines',
    type: 'scatter',
    symbol: 'path://M1.04147922,4 C1.11795272,3.5441717 1.29721854,3.12319909 1.55462604,2.76173282 L0.818019485,2.02512627 L1.52512627,1.31801948 L2.26173282,2.05462604 C2.62319909,1.79721854 3.0441717,1.61795272 3.5,1.54147922 L3.5,0.5 L4.5,0.5 L4.5,1.54147922 C4.9558283,1.61795272 5.37680091,1.79721854 5.73826718,2.05462604 L6.47487373,1.31801948 L7.18198052,2.02512627 L6.44537396,2.76173282 C6.70278146,3.12319909 6.88204728,3.5441717 6.95852078,4 L8,4 L8,5 L6.95852078,5 C6.88204728,5.4558283 6.70278146,5.87680091 6.44537396,6.23826718 L7.18198052,6.97487373 L6.47487373,7.68198052 L5.73826718,6.94537396 C5.37680091,7.20278146 4.9558283,7.38204728 4.5,7.45852078 L4.5,8.5 L3.5,8.5 L3.5,7.45852078 C3.0441717,7.38204728 2.62319909,7.20278146 2.26173282,6.94537396 L1.52512627,7.68198052 L0.818019485,6.97487373 L1.55462604,6.23826718 C1.29721854,5.87680091 1.11795272,5.4558283 1.04147922,5 L0,5 L0,4 L1.04147922,4 Z M3,5 C3.55228475,5 4,4.55228475 4,4 C4,3.44771525 3.55228475,3 3,3 C2.44771525,3 2,3.44771525 2,4 C2,4.55228475 2.44771525,5 3,5 Z',
    symbolSize: [16, 16],
    data: [],
    itemStyle: {
        normal: {
            color: '#000'
        }
    },
    z: 10
}, {
    type: 'scatter',
    name: 'marker',
    data: [],
    symbol: 'image://' + markUrl,
    symbolSize: 20,
    z: 100
}];

var numColors = ['#0B02B7', '#147A14', '#B61A1D', '#0A0677',
    '#6A030C', '#187C79', '#000', '#7A7A7A'];
for (var i = -1; i < numColors.length; ++i) {
    series.push({
        name: 'isOpen-' + (i + 1),
        type: 'scatter',
        symbol: 'rect',
        symbolSize: 24,
        data: [],
        itemStyle: {
            normal: {
                color: '#ccc'
            }
        },
        label: {
            normal: {
                show: true,
                formatter: function (param) {
                    return param.data[2] || '';
                },
                textStyle: {
                    color: numColors[i]
                }
            }
        },
        z: 5
    });
}
series.push({
    type: 'scatter',
    name: '标记',
    data: []
});

option = {
    grid: {
        width: 500,
        height: 500,
        top:50,
        left: 0,
        backgroundColor: '#eee',
        borderColor: '#fefefe',
        show: true
    },
    xAxis: {
        min: -0.5,
        max: xDotCnt - 0.5,
        type: 'value',
        show: false
    },
    yAxis: {
        min: -0.5,
        max: yDotCnt - 0.5,
        type: 'value',
        inverse: true,
        show: false
    },
    series: series,
    title: [{
        text: '扫雷 ——'
    }, {
        text: '剩余雷数:' + mineCnt,
        top: 0,
        left: 85
    }],
    animation: false,
    legend: {
        show: true,
        itemWidth: 25,
        itemHeight: 25,
        left: 300,
        data: [{
            name: '标记',
            icon: 'image://' + markUrl
        }],
        selected: {
            '标记': false
        }
    }
};

setTimeout(function() {
    mines = initMines();
    setOption();
}, 0);

var btn = document.createElement('button');
btn.style.position = 'absolute';
btn.style.top = '15px';
btn.style.left = '430px';
btn.style.marginLeft = '10px';
btn.setAttribute('onclick', 'restart()');
btn.innerHTML = '重新开始';
document.body.appendChild(btn);

myChart.on('click', function (param) {
    var x = param.data[0];
    var y = param.data[1];
    
    if (isMarking) {
        var s = series[2];
        var hasMarked = false;
        console.log(s.data);
        for (var i = 0, len = s.data.length; i < len; ++i) {
            if (s.data[i][0] === x && s.data[i][1] === y) {
                // Unmark
                s.data[i] = '-';
                hasMarked = true;
                mines[y][x].isMarked = false;
                --markedCnt;
                break;
            }
        }
        
        if (!hasMarked && !mines[y][x].isOpen) {
            // Mark
            s.data.push([x, y]);
            mines[y][x].isMarked = true;
            ++markedCnt;
        }
        
        myChart.setOption({
            series: s,
            title: [{
            }, {
                text: '剩余雷数:' + (mineCnt - markedCnt)
            }]
        });
    }
    else {
        var mine = mines[y][x];
        if (mine.isMarked) {
            // Do nothing when click on marked mine
            return;
        }
        if (mine.isMine) {
            gameOver(x, y);
        }
        else {
            clearSeries();
            open(x, y);
            setOption();
            checkWin();
        }
    }
});

myChart.on('legendselectchanged', function (e) {
    isMarking = e.selected['标记'];
});


function open(x, y) {
    if (!startTime) {
        startTime = new Date();
    }
    
    var mine = mines[y][x];
    if (!mine.isOpen) {
        mine.isOpen = true;
        
        if (mine.mineNeighbors === 0) {
            // Open neighbors
            if (x > 0) {
                open(x - 1, y);
                if (y > 0) {
                    open(x - 1, y - 1);
                }
                if (y < yDotCnt - 1) {
                    open(x - 1, y + 1);
                }
            }
            if (y > 0) {
                open(x, y - 1);
            }
            if (y < yDotCnt - 1) {
                open(x, y + 1);
            }
            if (x < xDotCnt - 1) {
                open(x + 1, y);
                if (y > 0) {
                    open(x + 1, y - 1);
                }
                if (y < yDotCnt - 1) {
                    open(x + 1, y + 1);
                }
            }
        }
    }
}

function gameOver(x, y) {
    // Show mines series
    var mineData = [];
    for (var j = 0; j < yDotCnt; ++j) {
        for (var i = 0; i < xDotCnt; ++i) {
            if (mines[j][i].isMine) {
                mineData.push([i, j]);
            }
        }
    }
    series[1].data = mineData;
    
    if (x !== null) {
        // Set backgroundColor of (x, y) to be red
        var data = getSeries(mines[y][x].mineNeighbors).data;
        data.push({
            value: [x, y],
            itemStyle: {
                normal: {
                    color: '#f00'
                }
            }
        });
    }
    
    myChart.setOption({
        series: series
    });
}

window.restart = function () {
    initMines();
    setOption();
    
    series[2].data = [];
    
    isMarking = false;
    markedCnt = 0;
    startTime = null;
    
    myChart.setOption({
        series: series,
        legend: {
            selected: {
                '标记': false
            }
        },
        title: [{
        }, {
            text: '剩余雷数:' + mineCnt
        }]
    })
};

function initMines() {
    mines = [];
    for (var y = 0; y < yDotCnt; ++y) {
        var line = [];
        for (var x = 0; x < xDotCnt; ++x) {
            line.push({
                isMine: false,
                isOpen: false,
                mineNeighbors: 0
            });
        }
        mines.push(line);
    }
    
    for (var i = 0; i < mineCnt; ++i) {
        var x = Math.ceil(Math.random() * xDotCnt) - 1;
        var y = Math.ceil(Math.random() * yDotCnt) - 1;
        if (mines[y][x].isMine) {
            // Reassign the same mine
            --i;
            continue;
        }
        
        mines[y][x].isMine = true;
        if (x > 0) {
            ++mines[y][x - 1].mineNeighbors;
            if (y > 0) {
                ++mines[y - 1][x - 1].mineNeighbors;
            }
            if (y < yDotCnt - 1) {
                ++mines[y + 1][x - 1].mineNeighbors;
            }
        }
        if (y > 0) {
            ++mines[y - 1][x].mineNeighbors;
        }
        if (y < yDotCnt - 1) {
            ++mines[y + 1][x].mineNeighbors;
        }
        if (x < xDotCnt - 1) {
            ++mines[y][x + 1].mineNeighbors;
            if (y > 0) {
                ++mines[y - 1][x + 1].mineNeighbors;
            }
            if (y < yDotCnt - 1) {
                ++mines[y + 1][x + 1].mineNeighbors;
            }
        }
    }
    return mines;
}


function setOption() {
    clearSeries();
    var notOpenData = series[0].data;
    
    for (var y = 0; y < yDotCnt; ++y) {
        for (var x = 0; x < xDotCnt; ++x) {
            var mine = mines[y][x];
            if (mine.isOpen) {
                var data = getSeries(mine.mineNeighbors).data;
                data.push([x, y, mine.mineNeighbors]);
            }
            else {
                notOpenData.push([x, y]);
            }
        }
    }
    
    myChart.setOption({
        series: series
    });
}

function clearSeries() {
    for (var i = 0; i < series.length; ++i) {
        if (i === 2) {
            continue;
        }
        series[i].data = [];
    }
}

function getSeries(neighbors) {
    return series[3 + neighbors];
}

function checkWin() {
    var isWin = true;
    for (var i = 0; i < xDotCnt && isWin; ++i) {
        for (var j = 0; j < yDotCnt; ++j) {
            var mine = mines[j][i];
            if (!mine.isMine && !mine.isOpen) {
                console.log(i, j, mine);
                isWin = false;
                break;
            }
        }
    }
    if (isWin) {
        var end = new Date();
        var sec = (end - startTime) / 1000;
        alert('赢啦!用时 ' + sec + '秒,很不错哦!');
        gameOver(null);
    }
}