Добро пожаловать, чтобы следовать:История DevUI с открытым исходным кодом, и добавил кDevUIГрядет строительство экологии с открытым исходным кодом!
предисловие
echarts
это очень мощная библиотека диаграмм, в дополнение к нашим общим функциям диаграмм,echarts
Существует функция пользовательской графики, эта функция позволяет нам очень просто рисовать на холсте какую-то нетрадиционную графику, исходя из этого, давайте пофантазируем.
Адрес мини-игры Flappy Bird (узнайте, сколько вы можете играть):
дурак cursed.GitHub.IO/E chart-flap…
Давайте реализуем это шаг за шагом.
1 Нарисуйте движущуюся птицу в системе координат
Сначала создайте контейнер echart, затем найдите изображение пиксельной птицы в Интернете и измените форму рассеяния диаграммы рассеяния на птицу, настроив изображение.
const myChart = echarts.init(document.getElementById('main'));
option = {
series: [
{
name: 'bird',
type: 'scatter',
symbolSize: 50,
symbol: 'image://bird.png',
data: [
[50, 80]
],
animation: false
},
]
};
myChart.setOption(option);
Чтобы заставить птицу двигаться, вам нужно задать правильную скорость и нисходящее ускорение, а также обновлять положение птицы в каждом кадре сцены. Действие птицы, летящей вверх, может быть реализовано поворотом угла, а условие срабатывания полета вверх задается космическим событием.
option = {
series: [
{
xAxis: {
show: false,
type: 'value',
min: 0,
max: 200,
},
yAxis: {
show: false,
min: 0,
max: 100
},
name: 'bird',
type: 'scatter',
symbolSize: 50,
symbol: 'image://bird.png',
data: [
[50, 80]
],
animation: false
},
]
};
// 设置速度和加速度
let a = 0.05;
let vh = 0;
let vw = 0.5
timer = setInterval(() => {
// 小鸟位置和仰角调整
vh = vh - a;
option.series[0].data[0][1] += vh;
option.series[0].data[0][0] += vw;
option.series[0].symbolRotate = option.series[0].symbolRotate ? option.series[0].symbolRotate - 5 : 0;
// 坐标系范围调整
option.xAxis.min += vw;
option.xAxis.max += vw;
myChart.setOption(option);
}, 25);
Эффект следующий
2 Нарисуйте препятствия с помощью пользовательской графики
пользовательские серии echarts, логика рендеринга передается разработчикомrenderItem
реализация функции. Эта функция получает два параметра params и api. params содержит текущую информацию о данных и информацию о системе координат. api представляет собой набор методов, которые могут вызывать разработчики. Обычно используемые методы:
-
api.value(...), что означает вынуть
dataItem
значение в . Напримерapi.value(0)
Указывает на удаление текущегоdataItem
Значение первого измерения в . -
api.coord(...), что означает выполнение вычисления преобразования координат. Например
var point = api.coord([api.value(0), api.value(1)])
выражатьdataItem
Значения в преобразуются в точки в системе координат. -
api.size(...), вы можете получить длину, соответствующую диапазону значений в системе координат.
-
api.style(...), вы можете получить
series.itemStyle
информация о стиле, определенная в .
Гибко используя вышеуказанные API, вы можете преобразовывать данные данных, переданные пользователем, в положение пикселя в нужной системе координат.
renderItem
функция возвращаетecharts
серединаgraphic
класс, вы можете комбинировать разнообразную графику в нужную вам форму,графический тип. Для препятствий в нашей игре нам нужно использовать только прямоугольники для их рисования Мы используем следующие два класса.
-
тип: группа, комбинированный класс, вы можете объединить несколько классов графики в один график и поместить подкласс в дочерние элементы.
-
type: rect, класс прямоугольника, путем определения точки координат верхнего левого угла прямоугольника, а также ширины и высоты прямоугольника для определения графики.
// 数据项定义为[x坐标,下方水管上侧y坐标, 上方水管下侧y坐标]
data: [
[150, 50, 80],
...
]
renderItem: function (params, api) {
// 获取每个水管主体矩形的起始坐标点
let start1 = api.coord([api.value(0) - 10, api.value(1)]);
let start2 = api.coord([api.value(0) - 10, 100]);
// 获取两个水管头矩形的起始坐标点
let startHead1 = api.coord([api.value(0) - 12, api.value(1)]);
let startHead2 = api.coord([api.value(0) - 12, api.value(2) + 8])
// 水管头矩形的宽高
let headSize = api.size([24, 8])
// 水管头矩形的宽高
let rect = api.size([20, api.value(1)]);
let rect2 = api.size([20, 100 - api.value(2)]);
// 坐标系配置
const common = {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
// 水管形状
const rectShape = echarts.graphic.clipRectByRect(
{
x: start1[0],
y: start1[1],
width: rect[0],
height: rect[1]
},common
);
const rectShape2 = echarts.graphic.clipRectByRect(
{
x: start2[0],
y: start2[1],
width: rect2[0],
height: rect2[1]
},
common
)
// 水管头形状
const rectHeadShape = echarts.graphic.clipRectByRect(
{
x: startHead1[0],
y: startHead1[1],
width: headSize[0],
height: headSize[1]
},common
);
const rectHeadShape2 = echarts.graphic.clipRectByRect(
{
x: startHead2[0],
y: startHead2[1],
width: headSize[0],
height: headSize[1]
},common
);
// 返回一个group类,由四个矩形组成
return {
type: 'group',
children: [{
type: 'rect',
shape: rectShape,
style: {
...api.style(),
lineWidth: 1,
stroke: '#000'
}
}, {
type: 'rect',
shape: rectShape2,
style: {
...api.style(),
lineWidth: 1,
stroke: '#000'
}
},
{
type: 'rect',
shape: rectHeadShape,
style: {
...api.style(),
lineWidth: 1,
stroke: '#000'
}
},
{
type: 'rect',
shape: rectHeadShape2,
style: {
...api.style(),
lineWidth: 1,
stroke: '#000'
}
}]
};
},
Определение цвета, мы использовали, чтобы сделать водопровод блестящимecharts
линейный градиентный объект.
itemStyle: {
// 渐变色对象
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [{
offset: 0, color: '#ddf38c' // 0% 处的颜色
}, {
offset: 1, color: '#587d2a' // 100% 处的颜色
}],
global: false // 缺省为 false
},
borderWidth: 3
},
Кроме того, используйте цикл for для случайной генерации данных для нескольких столбцов одновременно.
function initObstacleData() {
// 添加minHeight防止空隙太小
let minHeight = 20;
let start = 150;
obstacleData = [];
for (let index = 0; index < 50; index++) {
const height = Math.random() * 30 + minHeight;
const obstacleStart = Math.random() * (90 - minHeight);
obstacleData.push(
[
start + 50 * index,
obstacleStart,
obstacleStart + height > 100 ? 100 : obstacleStart + height
]
)
}
}
Затем залейте фон картинкой из игры, и мы нарисуем всю игровую сцену:
3 Выполните обнаружение столкновений
Поскольку данные о траектории полета и препятствиях очень просты, мы можем упростить логику столкновения до квадрата изображения птицы и оценить, входят ли правый верхний и правый нижний углы в диапазон пользовательской графики.
Для диапазона столкновений по определенным координатам, поскольку столбец фиксируется на 50 значениях координат на сетку, а ширина также фиксирована, диапазон столкновений по абсциссам можно упростить до(x / 50 % 1) < 0.6
в определенном диапазоне, в зависимости отMath.floor(x / 50)
После получения соответствующих данных можно определить, перекрываются ли координаты двух углов с площадью столбца. Судя по кадру анимации, если он перекрывается, останавливаем воспроизведение анимации и игра окончена.
// centerCoord为散点坐标点
function judgeCollision(centerCoord) {
if (centerCoord[1] < 0 || centerCoord[1] > 100) {
return false;
}
let coordList = [
[centerCoord[0] + 15, centerCoord[1] + 1],
[centerCoord[0] + 15, centerCoord[1] - 1],
]
for (let i = 0; i < 2; i++) {
const coord = coordList[i];
const index = coord[0] / 50;
if (index % 1 < 0.6 && obstacleData[Math.floor(index) - 3]) {
if (obstacleData[Math.floor(index) - 3][1] > coord[1] || obstacleData[Math.floor(index) - 3][2] < coord[1]) {
return false;
}
}
}
return false
}
function initAnimation() {
// 动画设置
timer = setInterval(() => {
// 小鸟速度和仰角调整
vh = vh - a;
option.series[0].data[0][1] += vh;
option.series[0].data[0][0] += vw;
option.series[0].symbolRotate = option.series[0].symbolRotate ? option.series[0].symbolRotate - 5 : 0;
// 坐标系范围调整
option.xAxis.min += vw;
option.xAxis.max += vw;
// 碰撞判断
const result = judgeCollision(option.series[0].data[0])
if(result) { // 产生碰撞后结束动画
endAnimation();
}
myChart.setOption(option);
}, 25);
}
Суммировать
echarts
Он предоставляет мощные возможности настройки графического рисунка. Чтобы правильно использовать эту возможность, вы должны понимать логику преобразования между точками координат данных и точками координат пикселей. Это важный шаг для визуализации данных на холсте.
Используйте эту функцию с пользой, и вы больше не будете бояться странных требований к диаграмме продукта.
Адрес источника:GitHub.com/дурак ругает/о…
DevUI набирает участников
В настоящее времяVue DevUIиNg DevUIМы набираем большое количество участников сообщества, добро пожаловать к нам!
Добавьте помощника WeChat:devui-official
, пригласить вас в группу технического обмена DevUI.
Добро пожаловать, чтобы следовать:История DevUI с открытым исходным кодом, и добавил кDevUIГрядет строительство экологии с открытым исходным кодом!