npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ball-collision

v1.4.0

Published

canvas 绘制小球撞击动画

Downloads

2

Readme

ball-collision

小球撞击动画,canvas 绘制。

Introduction

  • 纯 js 库

  • 支持 typescript

  • canvas、window.requestAnimationFrame 绘制动画。

    移动端对 canvas、window.requestAnimationFrame 的兼容性较好,一般不用担心。具体的兼容性细节如下:

    1. canvas 兼容 IE 9 及 9 以上;
    2. requestAnimationFrame 兼容 IE 10 及 10 以上(如果有需要,可以自行引入 raf 增强兼容性,示例:在全局代码比较早的位置 import 'raf/polyfill');
  • canvas 在移动端高清屏的模糊问题内部已处理,不会有图片模糊的困扰。

  • 针对移动端所有尺寸屏幕,内部实现了类似 REM 的缩放机制,会自动做缩放处理。

    如果需要在 PC 端关闭缩放效果(移动端不支持关闭缩放),请配置 scaleInPC 参数为 false。

  • 如果你的页面并不总是与设备屏幕等宽,例如:你的移动端页面,在 PC 端展示时,有设置最大宽度、剩余空间留白。

    那么此时,你必须要配置 docEl 参数,该参数的 clientWidth 应当等于实际的页面宽度。(否则 canvas 画布会与页面等宽,样式展示上会有偏差。)

  • 可以使用参数 designWidth(默认:375)指定设计稿,小球的半径、圆心位置等数值,均是指定设计稿中的数值。

  • 浏览器 resize 或移动端 orientationchange 事件触发时,默认会重新绘制。

    默认情况下,仅浏览器窗口的宽度变化时触发重新绘制。配置参数 resetOnlyWidth: false 将会在宽、高任意有变化时重新绘制。画布的大小仅与窗口宽度关联是,建议开启。

    配置参数 resetOnResize: false 可以移除窗口变化时重新绘制。画布的宽、高与窗口大小无关联时,建议关闭。

Example

  1. 气泡撞击

    example/index.html

  2. 位置、背景色、尺寸等全随机

    example/random.html

Installation

yarn

yarn add @eleven.fe/ball-collision

npm

npm i @eleven.fe/ball-collision

Options

interface CollisionConfig {
  /** 画板 HTMLElement */
  canvas: HTMLCanvasElement | any;
  /** 指定的小球集合,允许单独指定配置 */
  balls: BallSetting[];
  /** 最小位移速度,单位:px,默认:-2 */
  speedMin?: number;
  /** 最大位移速度,单位:px,默认:2 */
  speedMax?: number;
  /** canvas 画布背景颜色,默认:'transparent' 透明(合法的颜色值或 'random') */
  bgColor?: string;
  /** 页面节点(或可以视作页面实际承载容器的节点),默认:document.documentElement */
  docEl?: HTMLElement | any;
  /** 设计稿的宽度,默认:375(balls 中配置的小球尺寸,应当与此处的设计稿宽度匹配) */
  designWidth?: number;
  /** PC端是否动缩放,默认:true,即在移动端和 PC 端都会自动缩放,如果 PC 端不需要缩放可以配置为 false 关闭 */
  scaleInPC?: boolean;
  /** 浏览器 resize 或移动端 orientationchange 事件触发时,是否重置画布,默认:true */
  resetOnResize?: boolean;
  /** 浏览器 resize 或移动端 orientationchange 事件触发时,仅宽度有变化时,才会 reset,默认:true */
  resetOnlyWidth?: boolean;
}
interface BallSetting {
  /** 圆心 x 坐标 */
  x: number;
  /** 圆心 y 坐标 */
  y: number;
  /** 小球半径 */
  r: number;
  /** 小球对应图片(Image) */
  img?: HTMLImageElement;
  /** 小球对应图片的 src(BASE64或 http 链接) */
  imgSrc?: string;
  /** 小球背景色(合法的颜色值或 'random') */
  bgColor?: string;
  /** 水平位移速度 */
  velX?: number;
  /** 垂直位移速度 */
  velY?: number;
  /** 最小位移速度 */
  speedMin?: number;
  /** 最大位移速度 */
  speedMax?: number;
}

Methods

destroy()

销毁 animation frame,移除事件监听等,建议在(react、vue)组件卸载前调用一次。

Getting Started

先准备一个 canvas 标签,并设置 css 样式。

<!-- 先准备一个 canvas 标签。css 样式可以随意指定,画布内容会随之缩放。 -->
<canvas id="canvas_wrapper" class="canvas-wrapper"></canvas>
初始化示例一:普通配置
import BallCollision from '@eleven.fe/ball-collision'

/**
 * 1、配置 x、y、r 时,注意不要让小球的位置重叠
 * 2、移动端设备,不需要考虑设备像素比,
 *    即:x、y、r 等不需要乘 2、乘 3(因为,内部已自动做了canvas的适配)
 * 3、所有配置的位置、尺寸等数值,与指定的宽度设计稿相匹配,可以通过 designWidth 参数指定设计稿宽度,默认:375。
 */
const balls = [
  {
    x: 50, // 圆心 x 坐标,单位:px
    y: 50, // 圆心 y 坐标,单位:px
    r: 45, // 小球半径,单位:px
    bgColor: 'random', // 背景色可以指定,也可以随机
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png'
  },
  {
    x: 125,
    y: 140,
    r: 45,
    bgColor: 'random',
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png'
  },
  ...
]

// 初始化
new BallCollision({
  canvas: document.getElementById('canvas_wrapper'),
  balls: balls,
  speedMin: -2, // 单位:px
  speedMax: 2, // 单位:px
  bgColor: 'transparent', // bgColor支持随机,也可以指定(合法的颜色值)
  scaleInPC: true, // scaleInPC PC端是否动缩放,默认:true,即在移动端和 PC 端都会自动缩放,如果 PC 端不需要缩放可以配置为 false 关闭
})
初始化示例二:通过 img 参数指定图片
import BallCollision from '@eleven.fe/ball-collision'

const img = new Image()

img.onload = function() {
  // 图片 load 完成
  createCollision()
}
img.src = 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png'


function createCollision() {
  /**
   * 1、配置 x、y、r 时,注意不要让小球的位置重叠
   * 2、移动端设备,不需要考虑设备像素比,
   *    即:x、y、r 等不需要乘 2、乘 3(因为,内部已自动做了canvas的适配)
   * 3、所有配置的位置、尺寸等数值,与指定的宽度设计稿相匹配,可以通过 designWidth 参数指定设计稿宽度,默认:375。
   */
  const balls = [
    {
      x: 50, // 圆心 x 坐标,单位:px
      y: 50, // 圆心 y 坐标,单位:px
      r: 45, // 小球半径,单位:px
      bgColor: 'random', // 背景色可以指定,也可以随机
      img,
    },
    {
      x: 125,
      y: 140,
      r: 45,
      bgColor: 'random',
      img,
    },
    ...
  ]

  // 初始化
  new BallCollision({
    canvas: document.getElementById('canvas_wrapper'),
    balls: balls,
    speedMin: -2, // 单位:px
    speedMax: 2, // 单位:px
    bgColor: 'transparent', // bgColor支持随机,也可以指定(合法的颜色值)
    scaleInPC: true, // scaleInPC PC端是否动缩放,默认:true,即在移动端和 PC 端都会自动缩放,如果 PC 端不需要缩放可以配置为 false 关闭
  })
}
初始化示例三:小球位置、大小、背景色随机
import BallCollision from '@eleven.fe/ball-collision';

const _canvas = document.getElementById('canvas_wrapper');
const _docEl = document.querySelector('.wrapper');
const ua = window.navigator.userAgent;
const isIOS = /(ipad|iphone|ipod)/i.test(ua);
const isAndroid = /android/i.test(ua);
const isWinPhone = /windows phone/i.test(ua);
const isMobile = isIOS || isAndroid || isWinPhone;
const designWidth = 375;
const scaleInPC = false;
const scaleRate = !scaleInPC && !isMobile ? 1 : _docEl.clientWidth / designWidth;

// 初始化
new BallCollision({
  canvas: _canvas,
  balls: createRandomBalls(10, 30, 50),
  speedMin: -5, // 单位:px
  speedMax: 5, // 单位:px
  bgColor: 'random', // bgColor支持随机,也可以指定(合法的颜色值)
  docEl: _docEl,
  designWidth: designWidth, // 设计稿的宽度,默认:375(所有配置的尺寸、位置等,都是指定宽度的设计稿数值)
  scaleInPC: scaleInPC, // PC 端是否自动缩放(默认:true,在移动端和PC端都会自动缩放,如果 PC 端不需要缩放可以配置为 false 关闭)
});

/**
 * 随机生成小球位置、大小、颜色
 * @param {Number} ballCount 小球数量
 * @param {Number} ballMin 小球半径最小值
 * @param {Number} ballMax 小球半径最大值
 */
function createRandomBalls(ballCount, ballMin, ballMax) {
  const rectCanvas = _canvas.getBoundingClientRect();
  let balls = [];

  while (balls.length < ballCount) {
    balls.push(createBall(balls, ballMin, ballMax, rectCanvas));
  }
  return balls;
}

function createBall(balls, ballMin, ballMax, rectCanvas) {
  const r = random(ballMin, ballMax);
  // 缩放是随机时需要特别考虑的因素
  const x = random(r, rectCanvas.width / scaleRate - r);
  const y = random(r, rectCanvas.height / scaleRate - r);
  const bgColor = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')';

  // 随机比较麻烦的是:考虑初始的位置重叠问题
  for (let i = 0; i < balls.length; i++) {
    const dx = balls[i].x - x;
    const dy = balls[i].y - y;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance < balls[i].r + r) {
      return createBall(balls, ballMin, ballMax, rectCanvas);
    }
  }

  return {
    x: x,
    y: y,
    r: r,
    bgColor: bgColor,
  };
}

function random(min, max) {
  return Math.floor(Math.random() * (max - min) * 100) / 100 + min;
}

Using in React & Hooks & Typescript

import React, { useRef, useEffect } from 'react';
import styled from 'styled-components';
import BallCollision, { BallSetting } from '@eleven.fe/ball-collision';

const CanvasWrapper = styled.canvas`
  width: 100%;
  height: 100vh;
`;

// 小球初始配置
const balls: BallSetting[] = [
  {
    x: 50, // 圆心 x 坐标,单位:px
    y: 50, // 圆心 y 坐标,单位:px
    r: 45, // 小球半径,单位:px
    bgColor: 'random', // 背景色随机
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png',
  },
  {
    x: 125,
    y: 140,
    r: 45,
    bgColor: 'random',
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png',
  },
  {
    x: 200,
    y: 60,
    r: 45,
    bgColor: 'random',
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png',
  },
  {
    x: 220,
    y: 160,
    r: 45,
    bgColor: 'random',
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png',
  },
  {
    x: 160,
    y: 260,
    r: 45,
    bgColor: 'random',
    imgSrc: 'https://mat1.gtimg.com/sports/nba/logo/1602/13.png',
  },
];

export default function Ball() {
  let canvasEl = useRef < HTMLCanvasElement > null;

  useEffect(() => {
    // 初始化
    canvasEl &&
      new BallCollision({
        canvas: canvasEl,
        balls,
        speedMin: -2,
        speedMax: 2,
        bgColor: 'random',
      });
  }, []);

  return (
    <>
      <CanvasWrapper
        ref={(el: any) => {
          canvasEl = el;
        }}
      />
    </>
  );
}