pixel-flow-vue 1.0.10 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -107
- package/dist/index.d.ts +19 -20
- package/dist/pixel-flow-vue.js +61 -77
- package/dist/pixel-flow-vue.js.map +1 -1
- package/dist/pixel-flow-vue.umd.cjs +1 -1
- package/dist/pixel-flow-vue.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +18 -25
package/README.md
CHANGED
|
@@ -1,57 +1,37 @@
|
|
|
1
1
|
# pixel-flow-vue
|
|
2
2
|
|
|
3
|
-
> A lightweight **Vue 3** pixel-flow animation plugin with full **TypeScript** support.
|
|
3
|
+
> A lightweight **Vue 3** canvas pixel-flow animation plugin with full **TypeScript** support.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/pixel-flow-vue)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](https://vuejs.org/)
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## ✨ Features
|
|
12
|
-
|
|
13
|
-
- 🎨 **Pixel-art style** flowing particle animation via Canvas
|
|
14
|
-
- ⚡ **Vite + Rollup** built — ESM & UMD bundles included
|
|
15
|
-
- 🔷 **Full TypeScript** types exported out of the box
|
|
16
|
-
- 🎛️ Highly configurable: colors, speed, particle count, pixel size
|
|
17
|
-
- 🪄 `start()` / `stop()` control via component `ref`
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 📦 Installation
|
|
8
|
+
## Install
|
|
22
9
|
|
|
23
10
|
```bash
|
|
24
11
|
npm install pixel-flow-vue
|
|
25
|
-
# or
|
|
26
|
-
pnpm add pixel-flow-vue
|
|
27
|
-
# or
|
|
28
|
-
yarn add pixel-flow-vue
|
|
29
12
|
```
|
|
30
13
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## 🚀 Quick Start
|
|
14
|
+
## Usage
|
|
34
15
|
|
|
35
16
|
### Global registration
|
|
36
17
|
|
|
37
18
|
```ts
|
|
38
19
|
// main.ts
|
|
39
20
|
import { createApp } from 'vue'
|
|
40
|
-
import App from './App.vue'
|
|
41
21
|
import PixelFlowVue from 'pixel-flow-vue'
|
|
42
22
|
import 'pixel-flow-vue/style.css'
|
|
23
|
+
import App from './App.vue'
|
|
43
24
|
|
|
44
25
|
createApp(App).use(PixelFlowVue).mount('#app')
|
|
45
26
|
```
|
|
46
27
|
|
|
47
28
|
```vue
|
|
48
|
-
<!-- anywhere in your app -->
|
|
49
29
|
<template>
|
|
50
30
|
<PixelFlow :width="800" :height="450" />
|
|
51
31
|
</template>
|
|
52
32
|
```
|
|
53
33
|
|
|
54
|
-
### On-demand
|
|
34
|
+
### On-demand (Composition API)
|
|
55
35
|
|
|
56
36
|
```vue
|
|
57
37
|
<template>
|
|
@@ -64,9 +44,10 @@ createApp(App).use(PixelFlowVue).mount('#app')
|
|
|
64
44
|
:speed="1.5"
|
|
65
45
|
:pixel-size="5"
|
|
66
46
|
@ready="onReady"
|
|
47
|
+
@tick="onTick"
|
|
67
48
|
/>
|
|
68
|
-
<button @click="flowRef?.stop()">
|
|
69
|
-
<button @click="flowRef?.start()">
|
|
49
|
+
<button @click="flowRef?.stop()">Pause</button>
|
|
50
|
+
<button @click="flowRef?.start()">Resume</button>
|
|
70
51
|
</template>
|
|
71
52
|
|
|
72
53
|
<script setup lang="ts">
|
|
@@ -75,107 +56,55 @@ import { PixelFlow } from 'pixel-flow-vue'
|
|
|
75
56
|
import type { PixelFlowInstance } from 'pixel-flow-vue'
|
|
76
57
|
|
|
77
58
|
const flowRef = ref<PixelFlowInstance | null>(null)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.log('Pixel flow is ready!')
|
|
81
|
-
}
|
|
59
|
+
const onReady = () => console.log('ready!')
|
|
60
|
+
const onTick = (frame: number) => {}
|
|
82
61
|
</script>
|
|
83
62
|
```
|
|
84
63
|
|
|
85
|
-
###
|
|
64
|
+
### Headless (no component)
|
|
86
65
|
|
|
87
66
|
```ts
|
|
88
67
|
import { createPixelFlow } from 'pixel-flow-vue'
|
|
89
68
|
|
|
90
|
-
const canvas = document.querySelector<HTMLCanvasElement>('#
|
|
91
|
-
const stop = createPixelFlow({
|
|
92
|
-
|
|
93
|
-
colors: ['#ff2fa0', '#ffdd00'],
|
|
94
|
-
particleCount: 80,
|
|
95
|
-
speed: 2,
|
|
96
|
-
pixelSize: 6,
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
// Later: stop the animation
|
|
100
|
-
stop()
|
|
69
|
+
const canvas = document.querySelector<HTMLCanvasElement>('#c')!
|
|
70
|
+
const stop = createPixelFlow({ canvas, particleCount: 80, speed: 2 })
|
|
71
|
+
// stop() ← call to cancel
|
|
101
72
|
```
|
|
102
73
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
## 🎛️ Props
|
|
106
|
-
|
|
107
|
-
| Prop | Type | Default | Description |
|
|
108
|
-
| --------------- | ---------- | --------------------------------------------------- | ------------------------------ |
|
|
109
|
-
| `width` | `number` | `600` | Canvas width (px) |
|
|
110
|
-
| `height` | `number` | `400` | Canvas height (px) |
|
|
111
|
-
| `colors` | `string[]` | `['#00f5ff','#7b2fff','#ff2fa0','#ffdd00']` | Particle color palette |
|
|
112
|
-
| `particleCount` | `number` | `120` | Number of particles |
|
|
113
|
-
| `speed` | `number` | `1` | Speed multiplier (0.1 ~ 5) |
|
|
114
|
-
| `pixelSize` | `number` | `4` | Base pixel block size (px) |
|
|
115
|
-
| `background` | `string` | `'#0d0d0d'` | Canvas background color |
|
|
116
|
-
| `autoPlay` | `boolean` | `true` | Start animation on mount |
|
|
74
|
+
## Props
|
|
117
75
|
|
|
118
|
-
|
|
76
|
+
| Prop | Type | Default | Description |
|
|
77
|
+
|-----------------|------------|---------------------------------------------|--------------------------|
|
|
78
|
+
| `width` | `number` | `600` | Canvas width (px) |
|
|
79
|
+
| `height` | `number` | `400` | Canvas height (px) |
|
|
80
|
+
| `colors` | `string[]` | `['#00f5ff','#7b2fff','#ff2fa0','#ffdd00']` | Particle color palette |
|
|
81
|
+
| `particleCount` | `number` | `120` | Number of particles |
|
|
82
|
+
| `speed` | `number` | `1` | Speed multiplier 0.1–5 |
|
|
83
|
+
| `pixelSize` | `number` | `4` | Pixel block size (px) |
|
|
84
|
+
| `background` | `string` | `'#0d0d0d'` | Canvas background color |
|
|
85
|
+
| `autoPlay` | `boolean` | `true` | Auto-start on mount |
|
|
119
86
|
|
|
120
|
-
##
|
|
87
|
+
## Events
|
|
121
88
|
|
|
122
|
-
| Event | Payload | Description
|
|
123
|
-
|
|
124
|
-
| `ready` | — | Fired when
|
|
125
|
-
| `tick` | `frame: number`| Fired
|
|
89
|
+
| Event | Payload | Description |
|
|
90
|
+
|---------|----------------|-----------------------------|
|
|
91
|
+
| `ready` | — | Fired when animation starts |
|
|
92
|
+
| `tick` | `frame: number`| Fired every animation frame |
|
|
126
93
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
## 🔌 Exposed Methods (via `ref`)
|
|
94
|
+
## Exposed Methods
|
|
130
95
|
|
|
131
96
|
| Method | Description |
|
|
132
|
-
|
|
97
|
+
|-----------|--------------------------|
|
|
133
98
|
| `start()` | Start / restart the loop |
|
|
134
99
|
| `stop()` | Stop the animation loop |
|
|
135
100
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
## 📁 Package Exports
|
|
139
|
-
|
|
140
|
-
| Import path | Description |
|
|
141
|
-
| ------------------------- | --------------------- |
|
|
142
|
-
| `pixel-flow-vue` | Plugin + component |
|
|
143
|
-
| `pixel-flow-vue/style.css`| Component styles |
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## 🔧 Development
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
# Clone and install
|
|
151
|
-
git clone https://github.com/your-username/pixel-flow-vue.git
|
|
152
|
-
cd pixel-flow-vue
|
|
153
|
-
pnpm install
|
|
154
|
-
|
|
155
|
-
# Start dev server (playground)
|
|
156
|
-
pnpm dev
|
|
157
|
-
|
|
158
|
-
# Build for production
|
|
159
|
-
pnpm build
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## 📤 Publishing to npm
|
|
101
|
+
## Publish to npm
|
|
165
102
|
|
|
166
103
|
```bash
|
|
167
|
-
# 1. Log in to npm
|
|
168
104
|
npm login
|
|
169
|
-
|
|
170
|
-
# 2. Build
|
|
171
|
-
pnpm build
|
|
172
|
-
|
|
173
|
-
# 3. Publish
|
|
174
105
|
npm publish --access public
|
|
175
106
|
```
|
|
176
107
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
## 📄 License
|
|
108
|
+
## License
|
|
180
109
|
|
|
181
|
-
[MIT](LICENSE)
|
|
110
|
+
[MIT](LICENSE)
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ declare type __VLS_WithDefaults<P, D> = {
|
|
|
27
27
|
}> : P[K];
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* 创建像素粒子流动画。
|
|
32
|
+
* @returns 停止函数,调用后取消动画循环。
|
|
33
|
+
*/
|
|
30
34
|
export declare function createPixelFlow(options: PixelFlowOptions): () => void;
|
|
31
35
|
|
|
32
36
|
export declare const PixelFlow: DefineComponent<ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
|
|
@@ -39,8 +43,8 @@ pixelSize: number;
|
|
|
39
43
|
background: string;
|
|
40
44
|
autoPlay: boolean;
|
|
41
45
|
}>>, {
|
|
42
|
-
start:
|
|
43
|
-
stop:
|
|
46
|
+
start: () => void;
|
|
47
|
+
stop: () => void;
|
|
44
48
|
}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
|
|
45
49
|
ready: () => void;
|
|
46
50
|
tick: (frame: number) => void;
|
|
@@ -67,25 +71,24 @@ background: string;
|
|
|
67
71
|
autoPlay: boolean;
|
|
68
72
|
}, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
|
|
69
73
|
|
|
70
|
-
/** PixelFlow
|
|
74
|
+
/** PixelFlow 组件通过 defineExpose 暴露的实例方法 */
|
|
71
75
|
export declare interface PixelFlowInstance {
|
|
72
|
-
/** 开始 / 重启动画 */
|
|
73
76
|
start: () => void;
|
|
74
|
-
/** 暂停动画 */
|
|
75
77
|
stop: () => void;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
/**
|
|
80
|
+
/** pixel-flow-vue — 公共类型 */
|
|
81
|
+
/** createPixelFlow 配置项 */
|
|
79
82
|
export declare interface PixelFlowOptions {
|
|
80
|
-
/** 目标
|
|
83
|
+
/** 目标 HTMLCanvasElement */
|
|
81
84
|
canvas: HTMLCanvasElement;
|
|
82
|
-
/**
|
|
85
|
+
/** 粒子颜色数组,默认 4 种霓虹色 */
|
|
83
86
|
colors?: string[];
|
|
84
|
-
/**
|
|
87
|
+
/** 粒子数量,默认 120 */
|
|
85
88
|
particleCount?: number;
|
|
86
|
-
/** 速度倍率 (0.1
|
|
89
|
+
/** 速度倍率 (0.1~5),默认 1 */
|
|
87
90
|
speed?: number;
|
|
88
|
-
/**
|
|
91
|
+
/** 像素块大小 (px),默认 4 */
|
|
89
92
|
pixelSize?: number;
|
|
90
93
|
/** 每帧回调 */
|
|
91
94
|
onTick?: () => void;
|
|
@@ -101,22 +104,18 @@ declare interface Props {
|
|
|
101
104
|
width?: number;
|
|
102
105
|
/** 画布高度,默认 400 */
|
|
103
106
|
height?: number;
|
|
104
|
-
/**
|
|
107
|
+
/** 粒子颜色数组 */
|
|
105
108
|
colors?: string[];
|
|
106
109
|
/** 粒子数量,默认 120 */
|
|
107
110
|
particleCount?: number;
|
|
108
|
-
/**
|
|
111
|
+
/** 速度倍率,默认 1 */
|
|
109
112
|
speed?: number;
|
|
110
|
-
/**
|
|
113
|
+
/** 像素块大小,默认 4 */
|
|
111
114
|
pixelSize?: number;
|
|
112
|
-
/** 背景色,默认
|
|
115
|
+
/** 背景色,默认 #0d0d0d */
|
|
113
116
|
background?: string;
|
|
114
|
-
/**
|
|
117
|
+
/** 挂载后自动开始,默认 true */
|
|
115
118
|
autoPlay?: boolean;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
|
-
declare function start(): void;
|
|
119
|
-
|
|
120
|
-
declare function stop_2(): void;
|
|
121
|
-
|
|
122
121
|
export { }
|
package/dist/pixel-flow-vue.js
CHANGED
|
@@ -1,62 +1,55 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
function
|
|
1
|
+
import { defineComponent as k, ref as A, onMounted as C, onUnmounted as z, watch as P, openBlock as S, createElementBlock as _, normalizeStyle as D } from "vue";
|
|
2
|
+
function F(n) {
|
|
3
3
|
const {
|
|
4
4
|
canvas: i,
|
|
5
|
-
colors:
|
|
5
|
+
colors: d = ["#00f5ff", "#7b2fff", "#ff2fa0", "#ffdd00"],
|
|
6
6
|
particleCount: a = 120,
|
|
7
7
|
speed: f = 1,
|
|
8
8
|
pixelSize: h = 4,
|
|
9
|
-
onTick:
|
|
10
|
-
} =
|
|
11
|
-
if (!
|
|
12
|
-
const e =
|
|
13
|
-
let
|
|
9
|
+
onTick: o
|
|
10
|
+
} = n, u = i.getContext("2d");
|
|
11
|
+
if (!u) throw new Error("[pixel-flow-vue] Cannot get 2D context");
|
|
12
|
+
const e = u;
|
|
13
|
+
let s = 0, x = !0;
|
|
14
14
|
function m() {
|
|
15
|
-
const t = i.width, o = i.height;
|
|
16
15
|
return {
|
|
17
|
-
x: Math.random() *
|
|
18
|
-
y: Math.random() *
|
|
19
|
-
vx: (Math.random() - 0.5) * f *
|
|
20
|
-
vy: (Math.random() - 0.5) * f *
|
|
21
|
-
color:
|
|
22
|
-
size: h * (0.
|
|
16
|
+
x: Math.random() * i.width,
|
|
17
|
+
y: Math.random() * i.height,
|
|
18
|
+
vx: (Math.random() - 0.5) * f * 2,
|
|
19
|
+
vy: (Math.random() - 0.5) * f * 2,
|
|
20
|
+
color: d[Math.floor(Math.random() * d.length)],
|
|
21
|
+
size: h * (0.4 + Math.random() * 0.8),
|
|
23
22
|
alpha: Math.random(),
|
|
24
23
|
alphaDir: Math.random() > 0.5 ? 1 : -1
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
|
-
const
|
|
26
|
+
const l = Array.from({ length: a }, m);
|
|
28
27
|
function v(t) {
|
|
29
|
-
|
|
30
|
-
t.x += t.vx * f, t.y += t.vy * f, (t.x < 0 || t.x > o) && (t.vx *= -1), (t.y < 0 || t.y > r) && (t.vy *= -1), t.alpha += 0.012 * t.alphaDir, t.alpha >= 1 && (t.alpha = 1, t.alphaDir = -1), t.alpha <= 0.1 && (t.alpha = 0.1, t.alphaDir = 1);
|
|
28
|
+
t.x += t.vx * f, t.y += t.vy * f, (t.x < 0 || t.x > i.width) && (t.vx *= -1), (t.y < 0 || t.y > i.height) && (t.vy *= -1), t.alpha += 0.012 * t.alphaDir, t.alpha >= 1 && (t.alpha = 1, t.alphaDir = -1), t.alpha <= 0.1 && (t.alpha = 0.1, t.alphaDir = 1);
|
|
31
29
|
}
|
|
32
30
|
function M(t) {
|
|
33
|
-
e.globalAlpha = t.alpha, e.fillStyle = t.color, e.fillRect(
|
|
34
|
-
Math.round(t.x),
|
|
35
|
-
Math.round(t.y),
|
|
36
|
-
Math.round(t.size),
|
|
37
|
-
Math.round(t.size)
|
|
38
|
-
);
|
|
31
|
+
e.globalAlpha = t.alpha, e.fillStyle = t.color, e.fillRect(Math.round(t.x), Math.round(t.y), Math.round(t.size), Math.round(t.size));
|
|
39
32
|
}
|
|
40
|
-
function
|
|
41
|
-
for (let
|
|
42
|
-
for (let
|
|
43
|
-
const
|
|
44
|
-
w < 80 && (e.globalAlpha = (1 - w / 80) * 0.
|
|
33
|
+
function b() {
|
|
34
|
+
for (let r = 0; r < l.length; r++)
|
|
35
|
+
for (let c = r + 1; c < l.length; c++) {
|
|
36
|
+
const p = l[r].x - l[c].x, g = l[r].y - l[c].y, w = Math.sqrt(p * p + g * g);
|
|
37
|
+
w < 80 && (e.globalAlpha = (1 - w / 80) * 0.22, e.strokeStyle = l[r].color, e.lineWidth = 0.7, e.beginPath(), e.moveTo(l[r].x, l[r].y), e.lineTo(l[c].x, l[c].y), e.stroke());
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
|
-
function
|
|
48
|
-
if (!
|
|
49
|
-
const
|
|
50
|
-
e.globalAlpha = 0.
|
|
51
|
-
for (const
|
|
52
|
-
v(
|
|
53
|
-
|
|
40
|
+
function y() {
|
|
41
|
+
if (!x) return;
|
|
42
|
+
const { width: t, height: r } = i;
|
|
43
|
+
e.globalAlpha = 0.15, e.fillStyle = "#000", e.fillRect(0, 0, t, r), e.globalAlpha = 1;
|
|
44
|
+
for (const c of l)
|
|
45
|
+
v(c), M(c);
|
|
46
|
+
b(), o == null || o(), s = requestAnimationFrame(y);
|
|
54
47
|
}
|
|
55
|
-
return
|
|
56
|
-
|
|
48
|
+
return y(), function() {
|
|
49
|
+
x = !1, cancelAnimationFrame(s);
|
|
57
50
|
};
|
|
58
51
|
}
|
|
59
|
-
const
|
|
52
|
+
const R = ["width", "height"], B = /* @__PURE__ */ k({
|
|
60
53
|
__name: "PixelFlow",
|
|
61
54
|
props: {
|
|
62
55
|
width: { default: 600 },
|
|
@@ -69,61 +62,52 @@ const B = ["width", "height"], q = /* @__PURE__ */ b({
|
|
|
69
62
|
autoPlay: { type: Boolean, default: !0 }
|
|
70
63
|
},
|
|
71
64
|
emits: ["ready", "tick"],
|
|
72
|
-
setup(
|
|
73
|
-
const a =
|
|
74
|
-
let
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
background: a.background
|
|
78
|
-
}));
|
|
79
|
-
function d() {
|
|
80
|
-
if (!h.value) return;
|
|
81
|
-
l == null || l();
|
|
82
|
-
const m = {
|
|
65
|
+
setup(n, { expose: i, emit: d }) {
|
|
66
|
+
const a = n, f = d, h = A(null);
|
|
67
|
+
let o = null, u = 0;
|
|
68
|
+
function e() {
|
|
69
|
+
h.value && (o == null || o(), o = F({
|
|
83
70
|
canvas: h.value,
|
|
84
71
|
colors: a.colors,
|
|
85
72
|
particleCount: a.particleCount,
|
|
86
73
|
speed: a.speed,
|
|
87
74
|
pixelSize: a.pixelSize,
|
|
88
|
-
onTick: () => f("tick", ++
|
|
89
|
-
};
|
|
90
|
-
l = R(m), f("ready");
|
|
75
|
+
onTick: () => f("tick", ++u)
|
|
76
|
+
}), f("ready"));
|
|
91
77
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
78
|
+
function s() {
|
|
79
|
+
o == null || o(), o = null;
|
|
94
80
|
}
|
|
95
|
-
return
|
|
96
|
-
a.autoPlay &&
|
|
97
|
-
}), z(() =>
|
|
98
|
-
u();
|
|
99
|
-
}), C(
|
|
81
|
+
return C(() => {
|
|
82
|
+
a.autoPlay && e();
|
|
83
|
+
}), z(() => s()), P(
|
|
100
84
|
() => [a.particleCount, a.speed, a.pixelSize, a.colors],
|
|
101
85
|
() => {
|
|
102
|
-
|
|
86
|
+
o && e();
|
|
103
87
|
},
|
|
104
88
|
{ deep: !0 }
|
|
105
|
-
), i({ start:
|
|
89
|
+
), i({ start: e, stop: s }), (x, m) => (S(), _("canvas", {
|
|
106
90
|
ref_key: "canvasRef",
|
|
107
91
|
ref: h,
|
|
108
|
-
width:
|
|
109
|
-
height:
|
|
110
|
-
style:
|
|
111
|
-
class: "pixel-flow
|
|
112
|
-
}, null, 12,
|
|
92
|
+
width: n.width,
|
|
93
|
+
height: n.height,
|
|
94
|
+
style: D({ display: "block", background: n.background }),
|
|
95
|
+
class: "pixel-flow"
|
|
96
|
+
}, null, 12, R));
|
|
113
97
|
}
|
|
114
|
-
}),
|
|
115
|
-
const
|
|
98
|
+
}), X = (n, i) => {
|
|
99
|
+
const d = n.__vccOpts || n;
|
|
116
100
|
for (const [a, f] of i)
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
},
|
|
120
|
-
install(
|
|
121
|
-
|
|
101
|
+
d[a] = f;
|
|
102
|
+
return d;
|
|
103
|
+
}, q = /* @__PURE__ */ X(B, [["__scopeId", "data-v-02bb9f54"]]), I = {
|
|
104
|
+
install(n) {
|
|
105
|
+
n.component("PixelFlow", q);
|
|
122
106
|
}
|
|
123
107
|
};
|
|
124
108
|
export {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
109
|
+
q as PixelFlow,
|
|
110
|
+
F as createPixelFlow,
|
|
111
|
+
I as default
|
|
128
112
|
};
|
|
129
113
|
//# sourceMappingURL=pixel-flow-vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pixel-flow-vue.js","sources":["../src/core/pixelFlow.ts","../src/components/PixelFlow.vue","../src/index.ts"],"sourcesContent":["import type { PixelFlowOptions } from '../types'\n\n// -------------------------------------------------------\n// 粒子结构\n// -------------------------------------------------------\ninterface Particle {\n x: number\n y: number\n vx: number\n vy: number\n color: string\n size: number\n alpha: number\n alphaDir: number\n}\n\n// -------------------------------------------------------\n// 工厂函数:createPixelFlow\n// 返回一个 stop 函数,调用后停止动画循环\n// -------------------------------------------------------\nexport function createPixelFlow(options: PixelFlowOptions): () => void {\n const {\n canvas,\n colors = ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount = 120,\n speed = 1,\n pixelSize = 4,\n onTick,\n } = options\n\n const rawCtx = canvas.getContext('2d')\n if (!rawCtx) throw new Error('[pixel-flow-vue] Failed to get 2D context')\n // After the null-check, rebind as non-nullable so TypeScript is satisfied\n // inside every nested closure (TS cannot narrow across function boundaries).\n const ctx: CanvasRenderingContext2D = rawCtx\n\n let rafId = 0\n let running = true\n\n // ---- 初始化粒子 ----\n function makeParticle(): Particle {\n const w = canvas.width\n const h = canvas.height\n return {\n x: Math.random() * w,\n y: Math.random() * h,\n vx: (Math.random() - 0.5) * speed * 1.5,\n vy: (Math.random() - 0.5) * speed * 1.5,\n color: colors[Math.floor(Math.random() * colors.length)],\n size: pixelSize * (0.5 + Math.random() * 0.8),\n alpha: Math.random(),\n alphaDir: Math.random() > 0.5 ? 1 : -1,\n }\n }\n\n const particles: Particle[] = Array.from({ length: particleCount }, makeParticle)\n\n // ---- 更新单个粒子 ----\n function updateParticle(p: Particle): void {\n const w = canvas.width\n const h = canvas.height\n\n p.x += p.vx * speed\n p.y += p.vy * speed\n\n // 边界回弹\n if (p.x < 0 || p.x > w) p.vx *= -1\n if (p.y < 0 || p.y > h) p.vy *= -1\n\n // 呼吸透明度\n p.alpha += 0.012 * p.alphaDir\n if (p.alpha >= 1) { p.alpha = 1; p.alphaDir = -1 }\n if (p.alpha <= 0.1) { p.alpha = 0.1; p.alphaDir = 1 }\n }\n\n // ---- 绘制单个像素块 ----\n function drawParticle(p: Particle): void {\n ctx.globalAlpha = p.alpha\n ctx.fillStyle = p.color\n ctx.fillRect(\n Math.round(p.x),\n Math.round(p.y),\n Math.round(p.size),\n Math.round(p.size),\n )\n }\n\n // ---- 连线:距离近的粒子之间画线 ----\n function drawConnections(): void {\n const maxDist = 80\n for (let i = 0; i < particles.length; i++) {\n for (let j = i + 1; j < particles.length; j++) {\n const dx = particles[i].x - particles[j].x\n const dy = particles[i].y - particles[j].y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < maxDist) {\n ctx.globalAlpha = (1 - dist / maxDist) * 0.25\n ctx.strokeStyle = particles[i].color\n ctx.lineWidth = 0.8\n ctx.beginPath()\n ctx.moveTo(particles[i].x, particles[i].y)\n ctx.lineTo(particles[j].x, particles[j].y)\n ctx.stroke()\n }\n }\n }\n }\n\n // ---- 动画主循环 ----\n function loop(): void {\n if (!running) return\n\n const w = canvas.width\n const h = canvas.height\n\n // 拖尾效果:半透明清屏\n ctx.globalAlpha = 0.18\n ctx.fillStyle = '#000'\n ctx.fillRect(0, 0, w, h)\n\n ctx.globalAlpha = 1\n\n // 更新 & 绘制\n for (const p of particles) {\n updateParticle(p)\n drawParticle(p)\n }\n\n drawConnections()\n\n onTick?.()\n rafId = requestAnimationFrame(loop)\n }\n\n loop()\n\n // ---- 返回 stop 函数 ----\n return function stop() {\n running = false\n cancelAnimationFrame(rafId)\n }\n}\n","<template>\n <canvas\n ref=\"canvasRef\"\n :width=\"width\"\n :height=\"height\"\n :style=\"canvasStyle\"\n class=\"pixel-flow-canvas\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, computed, watch } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport { createPixelFlow } from '../core/pixelFlow'\nimport type { PixelFlowOptions } from '../types'\n\n// ----------------------------------------------------------------\n// Props\n// ----------------------------------------------------------------\ninterface Props {\n /** 画布宽度,默认 600 */\n width?: number\n /** 画布高度,默认 400 */\n height?: number\n /** 像素粒子颜色列表 */\n colors?: string[]\n /** 粒子数量,默认 120 */\n particleCount?: number\n /** 粒子速度倍率 (0.1 ~ 5),默认 1 */\n speed?: number\n /** 像素大小,默认 4 */\n pixelSize?: number\n /** 背景色,默认 '#0d0d0d' */\n background?: string\n /** 是否自动播放,默认 true */\n autoPlay?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n width: 600,\n height: 400,\n colors: () => ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount: 120,\n speed: 1,\n pixelSize: 4,\n background: '#0d0d0d',\n autoPlay: true,\n})\n\n// ----------------------------------------------------------------\n// Emits\n// ----------------------------------------------------------------\nconst emit = defineEmits<{\n (e: 'ready'): void\n (e: 'tick', frame: number): void\n}>()\n\n// ----------------------------------------------------------------\n// Refs & state\n// ----------------------------------------------------------------\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\nlet stopFn: (() => void) | null = null\nlet frame = 0\n\nconst canvasStyle = computed<CSSProperties>(() => ({\n display: 'block',\n background: props.background,\n}))\n\n// ----------------------------------------------------------------\n// Start / Stop helpers\n// ----------------------------------------------------------------\nfunction start() {\n if (!canvasRef.value) return\n stopFn?.()\n\n const options: PixelFlowOptions = {\n canvas: canvasRef.value,\n colors: props.colors,\n particleCount: props.particleCount,\n speed: props.speed,\n pixelSize: props.pixelSize,\n onTick: () => emit('tick', ++frame),\n }\n\n stopFn = createPixelFlow(options)\n emit('ready')\n}\n\nfunction stop() {\n stopFn?.()\n stopFn = null\n}\n\n// ----------------------------------------------------------------\n// Lifecycle\n// ----------------------------------------------------------------\nonMounted(() => {\n if (props.autoPlay) start()\n})\n\nonUnmounted(() => {\n stop()\n})\n\nwatch(\n () => [props.particleCount, props.speed, props.pixelSize, props.colors],\n () => {\n if (stopFn) start() // 重启以应用新配置\n },\n { deep: true }\n)\n\n// ----------------------------------------------------------------\n// Expose public API\n// ----------------------------------------------------------------\ndefineExpose({ start, stop })\n</script>\n\n<style scoped>\n.pixel-flow-canvas {\n border-radius: 4px;\n}\n</style>\n","import type { App } from 'vue'\nimport PixelFlow from './components/PixelFlow.vue'\nexport type { PixelFlowOptions, PixelFlowInstance } from './types'\nexport { createPixelFlow } from './core/pixelFlow'\n\n// ----------------------------------------------------------------\n// Vue 插件安装函数\n// ----------------------------------------------------------------\nconst PixelFlowVue = {\n install(app: App) {\n app.component('PixelFlow', PixelFlow)\n },\n}\n\n// ----------------------------------------------------------------\n// 导出\n// ----------------------------------------------------------------\nexport { PixelFlow }\nexport default PixelFlowVue\n"],"names":["createPixelFlow","options","canvas","colors","particleCount","speed","pixelSize","onTick","rawCtx","ctx","rafId","running","makeParticle","w","h","particles","updateParticle","p","drawParticle","drawConnections","i","j","dx","dy","dist","loop","props","__props","emit","__emit","canvasRef","ref","stopFn","frame","canvasStyle","computed","start","stop","onMounted","onUnmounted","watch","__expose","_createElementBlock","PixelFlowVue","app","PixelFlow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pixel-flow-vue.js","sources":["../src/core/pixelFlow.ts","../src/components/PixelFlow.vue","../src/index.ts"],"sourcesContent":["import type { PixelFlowOptions } from '../types'\n\ninterface Particle {\n x: number; y: number\n vx: number; vy: number\n color: string\n size: number\n alpha: number\n alphaDir: 1 | -1\n}\n\n/**\n * 创建像素粒子流动画。\n * @returns 停止函数,调用后取消动画循环。\n */\nexport function createPixelFlow(options: PixelFlowOptions): () => void {\n const {\n canvas,\n colors = ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount = 120,\n speed = 1,\n pixelSize = 4,\n onTick,\n } = options\n\n // 在 null 检查之后重新赋值为非空类型,避免 TS18047 在嵌套函数中误报\n const maybeCtx = canvas.getContext('2d')\n if (!maybeCtx) throw new Error('[pixel-flow-vue] Cannot get 2D context')\n const ctx: CanvasRenderingContext2D = maybeCtx\n\n let rafId = 0\n let active = true\n\n /* ---- 粒子工厂 ---- */\n function spawn(): Particle {\n return {\n x: Math.random() * canvas.width,\n y: Math.random() * canvas.height,\n vx: (Math.random() - 0.5) * speed * 2,\n vy: (Math.random() - 0.5) * speed * 2,\n color: colors[Math.floor(Math.random() * colors.length)],\n size: pixelSize * (0.4 + Math.random() * 0.8),\n alpha: Math.random(),\n alphaDir: Math.random() > 0.5 ? 1 : -1,\n }\n }\n\n const particles: Particle[] = Array.from({ length: particleCount }, spawn)\n\n /* ---- 更新 ---- */\n function update(p: Particle): void {\n p.x += p.vx * speed\n p.y += p.vy * speed\n if (p.x < 0 || p.x > canvas.width) p.vx *= -1\n if (p.y < 0 || p.y > canvas.height) p.vy *= -1\n p.alpha += 0.012 * p.alphaDir\n if (p.alpha >= 1) { p.alpha = 1; p.alphaDir = -1 }\n if (p.alpha <= 0.1) { p.alpha = 0.1; p.alphaDir = 1 }\n }\n\n /* ---- 绘制像素块 ---- */\n function drawPixel(p: Particle): void {\n ctx.globalAlpha = p.alpha\n ctx.fillStyle = p.color\n ctx.fillRect(Math.round(p.x), Math.round(p.y), Math.round(p.size), Math.round(p.size))\n }\n\n /* ---- 连线 ---- */\n function drawLinks(): void {\n const MAX = 80\n for (let i = 0; i < particles.length; i++) {\n for (let j = i + 1; j < particles.length; j++) {\n const dx = particles[i].x - particles[j].x\n const dy = particles[i].y - particles[j].y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < MAX) {\n ctx.globalAlpha = (1 - dist / MAX) * 0.22\n ctx.strokeStyle = particles[i].color\n ctx.lineWidth = 0.7\n ctx.beginPath()\n ctx.moveTo(particles[i].x, particles[i].y)\n ctx.lineTo(particles[j].x, particles[j].y)\n ctx.stroke()\n }\n }\n }\n }\n\n /* ---- 主循环 ---- */\n function loop(): void {\n if (!active) return\n const { width: w, height: h } = canvas\n // 拖尾:半透明黑色蒙层\n ctx.globalAlpha = 0.15\n ctx.fillStyle = '#000'\n ctx.fillRect(0, 0, w, h)\n ctx.globalAlpha = 1\n\n for (const p of particles) { update(p); drawPixel(p) }\n drawLinks()\n\n onTick?.()\n rafId = requestAnimationFrame(loop)\n }\n\n loop()\n\n return function stop(): void {\n active = false\n cancelAnimationFrame(rafId)\n }\n}\n","<template>\n <canvas\n ref=\"canvasRef\"\n :width=\"width\"\n :height=\"height\"\n :style=\"{ display: 'block', background: background }\"\n class=\"pixel-flow\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\nimport { createPixelFlow } from '../core/pixelFlow'\nimport type { PixelFlowInstance } from '../types'\n\n// ---------- props ----------\ninterface Props {\n /** 画布宽度,默认 600 */\n width?: number\n /** 画布高度,默认 400 */\n height?: number\n /** 粒子颜色数组 */\n colors?: string[]\n /** 粒子数量,默认 120 */\n particleCount?: number\n /** 速度倍率,默认 1 */\n speed?: number\n /** 像素块大小,默认 4 */\n pixelSize?: number\n /** 背景色,默认 #0d0d0d */\n background?: string\n /** 挂载后自动开始,默认 true */\n autoPlay?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n width: 600,\n height: 400,\n colors: () => ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount: 120,\n speed: 1,\n pixelSize: 4,\n background: '#0d0d0d',\n autoPlay: true,\n})\n\n// ---------- emits ----------\nconst emit = defineEmits<{\n (e: 'ready'): void\n (e: 'tick', frame: number): void\n}>()\n\n// ---------- internal ----------\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\nlet stopFn: (() => void) | null = null\nlet frameCount = 0\n\nfunction start(): void {\n if (!canvasRef.value) return\n stopFn?.()\n stopFn = createPixelFlow({\n canvas: canvasRef.value,\n colors: props.colors,\n particleCount: props.particleCount,\n speed: props.speed,\n pixelSize: props.pixelSize,\n onTick: () => emit('tick', ++frameCount),\n })\n emit('ready')\n}\n\nfunction stop(): void {\n stopFn?.()\n stopFn = null\n}\n\nonMounted(() => { if (props.autoPlay) start() })\nonUnmounted(() => stop())\n\n// 配置变化时热重启\nwatch(\n () => [props.particleCount, props.speed, props.pixelSize, props.colors] as const,\n () => { if (stopFn) start() },\n { deep: true },\n)\n\n// ---------- expose ----------\ndefineExpose<PixelFlowInstance>({ start, stop })\n</script>\n\n<style scoped>\n.pixel-flow { border-radius: 4px; }\n</style>\n","/**\n * pixel-flow-vue\n * Vue 3 + TypeScript canvas pixel-flow animation plugin\n */\nimport type { App } from 'vue'\nimport PixelFlow from './components/PixelFlow.vue'\nimport { createPixelFlow } from './core/pixelFlow'\n\nexport type { PixelFlowOptions, PixelFlowInstance } from './types'\nexport { PixelFlow, createPixelFlow }\n\n// ---------- Vue plugin ----------\nconst PixelFlowVue = {\n install(app: App): void {\n app.component('PixelFlow', PixelFlow)\n },\n}\n\nexport default PixelFlowVue\n"],"names":["createPixelFlow","options","canvas","colors","particleCount","speed","pixelSize","onTick","maybeCtx","ctx","rafId","active","spawn","particles","update","p","drawPixel","drawLinks","i","j","dx","dy","dist","loop","w","h","props","__props","emit","__emit","canvasRef","ref","stopFn","frameCount","start","stop","onMounted","onUnmounted","watch","__expose","_createElementBlock","PixelFlowVue","app","PixelFlow"],"mappings":";AAeO,SAASA,EAAgBC,GAAuC;AACrE,QAAM;AAAA,IACJ,QAAAC;AAAA,IACA,QAAAC,IAAS,CAAC,WAAW,WAAW,WAAW,SAAS;AAAA,IACpD,eAAAC,IAAgB;AAAA,IAChB,OAAAC,IAAQ;AAAA,IACR,WAAAC,IAAY;AAAA,IACZ,QAAAC;AAAA,EAAA,IACEN,GAGEO,IAAWN,EAAO,WAAW,IAAI;AACvC,MAAI,CAACM,EAAU,OAAM,IAAI,MAAM,wCAAwC;AACvE,QAAMC,IAAgCD;AAEtC,MAAIE,IAAQ,GACRC,IAAS;AAGb,WAASC,IAAkB;AACzB,WAAO;AAAA,MACL,GAAG,KAAK,OAAA,IAAWV,EAAO;AAAA,MAC1B,GAAG,KAAK,OAAA,IAAWA,EAAO;AAAA,MAC1B,KAAK,KAAK,OAAA,IAAW,OAAOG,IAAQ;AAAA,MACpC,KAAK,KAAK,OAAA,IAAW,OAAOA,IAAQ;AAAA,MACpC,OAAOF,EAAO,KAAK,MAAM,KAAK,OAAA,IAAWA,EAAO,MAAM,CAAC;AAAA,MACvD,MAAMG,KAAa,MAAM,KAAK,WAAW;AAAA,MACzC,OAAO,KAAK,OAAA;AAAA,MACZ,UAAU,KAAK,WAAW,MAAM,IAAI;AAAA,IAAA;AAAA,EAExC;AAEA,QAAMO,IAAwB,MAAM,KAAK,EAAE,QAAQT,EAAA,GAAiBQ,CAAK;AAGzE,WAASE,EAAOC,GAAmB;AACjC,IAAAA,EAAE,KAAKA,EAAE,KAAKV,GACdU,EAAE,KAAKA,EAAE,KAAKV,IACVU,EAAE,IAAI,KAAKA,EAAE,IAAIb,EAAO,aAAU,MAAM,MACxCa,EAAE,IAAI,KAAKA,EAAE,IAAIb,EAAO,cAAU,MAAM,KAC5Ca,EAAE,SAAS,QAAQA,EAAE,UACjBA,EAAE,SAAS,MAAOA,EAAE,QAAQ,GAAKA,EAAE,WAAW,KAC9CA,EAAE,SAAS,QAAOA,EAAE,QAAQ,KAAKA,EAAE,WAAY;AAAA,EACrD;AAGA,WAASC,EAAUD,GAAmB;AACpC,IAAAN,EAAI,cAAcM,EAAE,OACpBN,EAAI,YAAcM,EAAE,OACpBN,EAAI,SAAS,KAAK,MAAMM,EAAE,CAAC,GAAG,KAAK,MAAMA,EAAE,CAAC,GAAG,KAAK,MAAMA,EAAE,IAAI,GAAG,KAAK,MAAMA,EAAE,IAAI,CAAC;AAAA,EACvF;AAGA,WAASE,IAAkB;AAEzB,aAASC,IAAI,GAAGA,IAAIL,EAAU,QAAQK;AACpC,eAASC,IAAID,IAAI,GAAGC,IAAIN,EAAU,QAAQM,KAAK;AAC7C,cAAMC,IAAOP,EAAUK,CAAC,EAAE,IAAIL,EAAUM,CAAC,EAAE,GACrCE,IAAOR,EAAUK,CAAC,EAAE,IAAIL,EAAUM,CAAC,EAAE,GACrCG,IAAO,KAAK,KAAKF,IAAKA,IAAKC,IAAKA,CAAE;AACxC,QAAIC,IAAO,OACTb,EAAI,eAAe,IAAIa,IAAO,MAAO,MACrCb,EAAI,cAAcI,EAAUK,CAAC,EAAE,OAC/BT,EAAI,YAAc,KAClBA,EAAI,UAAA,GACJA,EAAI,OAAOI,EAAUK,CAAC,EAAE,GAAGL,EAAUK,CAAC,EAAE,CAAC,GACzCT,EAAI,OAAOI,EAAUM,CAAC,EAAE,GAAGN,EAAUM,CAAC,EAAE,CAAC,GACzCV,EAAI,OAAA;AAAA,MAER;AAAA,EAEJ;AAGA,WAASc,IAAa;AACpB,QAAI,CAACZ,EAAQ;AACb,UAAM,EAAE,OAAOa,GAAG,QAAQC,MAAMvB;AAEhC,IAAAO,EAAI,cAAc,MAClBA,EAAI,YAAc,QAClBA,EAAI,SAAS,GAAG,GAAGe,GAAGC,CAAC,GACvBhB,EAAI,cAAc;AAElB,eAAWM,KAAKF;AAAa,MAAAC,EAAOC,CAAC,GAAGC,EAAUD,CAAC;AACnD,IAAAE,EAAA,GAEAV,KAAA,QAAAA,KACAG,IAAQ,sBAAsBa,CAAI;AAAA,EACpC;AAEA,SAAAA,EAAA,GAEO,WAAsB;AAC3B,IAAAZ,IAAS,IACT,qBAAqBD,CAAK;AAAA,EAC5B;AACF;;;;;;;;;;;;;;;AC5EA,UAAMgB,IAAQC,GAYRC,IAAOC,GAMPC,IAAYC,EAA8B,IAAI;AACpD,QAAIC,IAA8B,MAC9BC,IAAa;AAEjB,aAASC,IAAc;AACrB,MAAKJ,EAAU,UACfE,KAAA,QAAAA,KACAA,IAAShC,EAAgB;AAAA,QACvB,QAAQ8B,EAAU;AAAA,QAClB,QAAQJ,EAAM;AAAA,QACd,eAAeA,EAAM;AAAA,QACrB,OAAOA,EAAM;AAAA,QACb,WAAWA,EAAM;AAAA,QACjB,QAAQ,MAAME,EAAK,QAAQ,EAAEK,CAAU;AAAA,MAAA,CACxC,GACDL,EAAK,OAAO;AAAA,IACd;AAEA,aAASO,IAAa;AACpB,MAAAH,KAAA,QAAAA,KACAA,IAAS;AAAA,IACX;AAEA,WAAAI,EAAU,MAAM;AAAE,MAAIV,EAAM,YAAUQ,EAAA;AAAA,IAAQ,CAAC,GAC/CG,EAAY,MAAMF,GAAM,GAGxBG;AAAA,MACE,MAAM,CAACZ,EAAM,eAAeA,EAAM,OAAOA,EAAM,WAAWA,EAAM,MAAM;AAAA,MACtE,MAAM;AAAE,QAAIM,KAAQE,EAAA;AAAA,MAAQ;AAAA,MAC5B,EAAE,MAAM,GAAA;AAAA,IAAK,GAIfK,EAAgC,EAAE,OAAAL,GAAO,MAAAC,GAAM,mBAtF7CK,EAME,UAAA;AAAA,eALI;AAAA,MAAJ,KAAIV;AAAA,MACH,OAAOH,EAAA;AAAA,MACP,QAAQA,EAAA;AAAA,MACR,yCAAuCA,EAAA,YAAU;AAAA,MAClD,OAAM;AAAA,IAAA;;;;;;;iECMJc,IAAe;AAAA,EACnB,QAAQC,GAAgB;AACtB,IAAAA,EAAI,UAAU,aAAaC,CAAS;AAAA,EACtC;AACF;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(c,a){typeof exports=="object"&&typeof module<"u"?a(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],a):(c=typeof globalThis<"u"?globalThis:c||self,a(c.PixelFlowVue={},c.Vue))})(this,function(c,a){"use strict";function p(i){const{canvas:f,colors:u=["#00f5ff","#7b2fff","#ff2fa0","#ffdd00"],particleCount:o=120,speed:d=1,pixelSize:h=4,onTick:l}=i,y=f.getContext("2d");if(!y)throw new Error("[pixel-flow-vue] Cannot get 2D context");const t=y;let x=0,m=!0;function g(){return{x:Math.random()*f.width,y:Math.random()*f.height,vx:(Math.random()-.5)*d*2,vy:(Math.random()-.5)*d*2,color:u[Math.floor(Math.random()*u.length)],size:h*(.4+Math.random()*.8),alpha:Math.random(),alphaDir:Math.random()>.5?1:-1}}const n=Array.from({length:o},g);function S(e){e.x+=e.vx*d,e.y+=e.vy*d,(e.x<0||e.x>f.width)&&(e.vx*=-1),(e.y<0||e.y>f.height)&&(e.vy*=-1),e.alpha+=.012*e.alphaDir,e.alpha>=1&&(e.alpha=1,e.alphaDir=-1),e.alpha<=.1&&(e.alpha=.1,e.alphaDir=1)}function A(e){t.globalAlpha=e.alpha,t.fillStyle=e.color,t.fillRect(Math.round(e.x),Math.round(e.y),Math.round(e.size),Math.round(e.size))}function C(){for(let r=0;r<n.length;r++)for(let s=r+1;s<n.length;s++){const b=n[r].x-n[s].x,v=n[r].y-n[s].y,_=Math.sqrt(b*b+v*v);_<80&&(t.globalAlpha=(1-_/80)*.22,t.strokeStyle=n[r].color,t.lineWidth=.7,t.beginPath(),t.moveTo(n[r].x,n[r].y),t.lineTo(n[s].x,n[s].y),t.stroke())}}function M(){if(!m)return;const{width:e,height:r}=f;t.globalAlpha=.15,t.fillStyle="#000",t.fillRect(0,0,e,r),t.globalAlpha=1;for(const s of n)S(s),A(s);C(),l==null||l(),x=requestAnimationFrame(M)}return M(),function(){m=!1,cancelAnimationFrame(x)}}const k=["width","height"],w=((i,f)=>{const u=i.__vccOpts||i;for(const[o,d]of f)u[o]=d;return u})(a.defineComponent({__name:"PixelFlow",props:{width:{default:600},height:{default:400},colors:{default:()=>["#00f5ff","#7b2fff","#ff2fa0","#ffdd00"]},particleCount:{default:120},speed:{default:1},pixelSize:{default:4},background:{default:"#0d0d0d"},autoPlay:{type:Boolean,default:!0}},emits:["ready","tick"],setup(i,{expose:f,emit:u}){const o=i,d=u,h=a.ref(null);let l=null,y=0;function t(){h.value&&(l==null||l(),l=p({canvas:h.value,colors:o.colors,particleCount:o.particleCount,speed:o.speed,pixelSize:o.pixelSize,onTick:()=>d("tick",++y)}),d("ready"))}function x(){l==null||l(),l=null}return a.onMounted(()=>{o.autoPlay&&t()}),a.onUnmounted(()=>x()),a.watch(()=>[o.particleCount,o.speed,o.pixelSize,o.colors],()=>{l&&t()},{deep:!0}),f({start:t,stop:x}),(m,g)=>(a.openBlock(),a.createElementBlock("canvas",{ref_key:"canvasRef",ref:h,width:i.width,height:i.height,style:a.normalizeStyle({display:"block",background:i.background}),class:"pixel-flow"},null,12,k))}}),[["__scopeId","data-v-02bb9f54"]]),P={install(i){i.component("PixelFlow",w)}};c.PixelFlow=w,c.createPixelFlow=p,c.default=P,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
2
2
|
//# sourceMappingURL=pixel-flow-vue.umd.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pixel-flow-vue.umd.cjs","sources":["../src/core/pixelFlow.ts","../src/components/PixelFlow.vue","../src/index.ts"],"sourcesContent":["import type { PixelFlowOptions } from '../types'\n\n// -------------------------------------------------------\n// 粒子结构\n// -------------------------------------------------------\ninterface Particle {\n x: number\n y: number\n vx: number\n vy: number\n color: string\n size: number\n alpha: number\n alphaDir: number\n}\n\n// -------------------------------------------------------\n// 工厂函数:createPixelFlow\n// 返回一个 stop 函数,调用后停止动画循环\n// -------------------------------------------------------\nexport function createPixelFlow(options: PixelFlowOptions): () => void {\n const {\n canvas,\n colors = ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount = 120,\n speed = 1,\n pixelSize = 4,\n onTick,\n } = options\n\n const rawCtx = canvas.getContext('2d')\n if (!rawCtx) throw new Error('[pixel-flow-vue] Failed to get 2D context')\n // After the null-check, rebind as non-nullable so TypeScript is satisfied\n // inside every nested closure (TS cannot narrow across function boundaries).\n const ctx: CanvasRenderingContext2D = rawCtx\n\n let rafId = 0\n let running = true\n\n // ---- 初始化粒子 ----\n function makeParticle(): Particle {\n const w = canvas.width\n const h = canvas.height\n return {\n x: Math.random() * w,\n y: Math.random() * h,\n vx: (Math.random() - 0.5) * speed * 1.5,\n vy: (Math.random() - 0.5) * speed * 1.5,\n color: colors[Math.floor(Math.random() * colors.length)],\n size: pixelSize * (0.5 + Math.random() * 0.8),\n alpha: Math.random(),\n alphaDir: Math.random() > 0.5 ? 1 : -1,\n }\n }\n\n const particles: Particle[] = Array.from({ length: particleCount }, makeParticle)\n\n // ---- 更新单个粒子 ----\n function updateParticle(p: Particle): void {\n const w = canvas.width\n const h = canvas.height\n\n p.x += p.vx * speed\n p.y += p.vy * speed\n\n // 边界回弹\n if (p.x < 0 || p.x > w) p.vx *= -1\n if (p.y < 0 || p.y > h) p.vy *= -1\n\n // 呼吸透明度\n p.alpha += 0.012 * p.alphaDir\n if (p.alpha >= 1) { p.alpha = 1; p.alphaDir = -1 }\n if (p.alpha <= 0.1) { p.alpha = 0.1; p.alphaDir = 1 }\n }\n\n // ---- 绘制单个像素块 ----\n function drawParticle(p: Particle): void {\n ctx.globalAlpha = p.alpha\n ctx.fillStyle = p.color\n ctx.fillRect(\n Math.round(p.x),\n Math.round(p.y),\n Math.round(p.size),\n Math.round(p.size),\n )\n }\n\n // ---- 连线:距离近的粒子之间画线 ----\n function drawConnections(): void {\n const maxDist = 80\n for (let i = 0; i < particles.length; i++) {\n for (let j = i + 1; j < particles.length; j++) {\n const dx = particles[i].x - particles[j].x\n const dy = particles[i].y - particles[j].y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < maxDist) {\n ctx.globalAlpha = (1 - dist / maxDist) * 0.25\n ctx.strokeStyle = particles[i].color\n ctx.lineWidth = 0.8\n ctx.beginPath()\n ctx.moveTo(particles[i].x, particles[i].y)\n ctx.lineTo(particles[j].x, particles[j].y)\n ctx.stroke()\n }\n }\n }\n }\n\n // ---- 动画主循环 ----\n function loop(): void {\n if (!running) return\n\n const w = canvas.width\n const h = canvas.height\n\n // 拖尾效果:半透明清屏\n ctx.globalAlpha = 0.18\n ctx.fillStyle = '#000'\n ctx.fillRect(0, 0, w, h)\n\n ctx.globalAlpha = 1\n\n // 更新 & 绘制\n for (const p of particles) {\n updateParticle(p)\n drawParticle(p)\n }\n\n drawConnections()\n\n onTick?.()\n rafId = requestAnimationFrame(loop)\n }\n\n loop()\n\n // ---- 返回 stop 函数 ----\n return function stop() {\n running = false\n cancelAnimationFrame(rafId)\n }\n}\n","<template>\n <canvas\n ref=\"canvasRef\"\n :width=\"width\"\n :height=\"height\"\n :style=\"canvasStyle\"\n class=\"pixel-flow-canvas\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, computed, watch } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport { createPixelFlow } from '../core/pixelFlow'\nimport type { PixelFlowOptions } from '../types'\n\n// ----------------------------------------------------------------\n// Props\n// ----------------------------------------------------------------\ninterface Props {\n /** 画布宽度,默认 600 */\n width?: number\n /** 画布高度,默认 400 */\n height?: number\n /** 像素粒子颜色列表 */\n colors?: string[]\n /** 粒子数量,默认 120 */\n particleCount?: number\n /** 粒子速度倍率 (0.1 ~ 5),默认 1 */\n speed?: number\n /** 像素大小,默认 4 */\n pixelSize?: number\n /** 背景色,默认 '#0d0d0d' */\n background?: string\n /** 是否自动播放,默认 true */\n autoPlay?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n width: 600,\n height: 400,\n colors: () => ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount: 120,\n speed: 1,\n pixelSize: 4,\n background: '#0d0d0d',\n autoPlay: true,\n})\n\n// ----------------------------------------------------------------\n// Emits\n// ----------------------------------------------------------------\nconst emit = defineEmits<{\n (e: 'ready'): void\n (e: 'tick', frame: number): void\n}>()\n\n// ----------------------------------------------------------------\n// Refs & state\n// ----------------------------------------------------------------\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\nlet stopFn: (() => void) | null = null\nlet frame = 0\n\nconst canvasStyle = computed<CSSProperties>(() => ({\n display: 'block',\n background: props.background,\n}))\n\n// ----------------------------------------------------------------\n// Start / Stop helpers\n// ----------------------------------------------------------------\nfunction start() {\n if (!canvasRef.value) return\n stopFn?.()\n\n const options: PixelFlowOptions = {\n canvas: canvasRef.value,\n colors: props.colors,\n particleCount: props.particleCount,\n speed: props.speed,\n pixelSize: props.pixelSize,\n onTick: () => emit('tick', ++frame),\n }\n\n stopFn = createPixelFlow(options)\n emit('ready')\n}\n\nfunction stop() {\n stopFn?.()\n stopFn = null\n}\n\n// ----------------------------------------------------------------\n// Lifecycle\n// ----------------------------------------------------------------\nonMounted(() => {\n if (props.autoPlay) start()\n})\n\nonUnmounted(() => {\n stop()\n})\n\nwatch(\n () => [props.particleCount, props.speed, props.pixelSize, props.colors],\n () => {\n if (stopFn) start() // 重启以应用新配置\n },\n { deep: true }\n)\n\n// ----------------------------------------------------------------\n// Expose public API\n// ----------------------------------------------------------------\ndefineExpose({ start, stop })\n</script>\n\n<style scoped>\n.pixel-flow-canvas {\n border-radius: 4px;\n}\n</style>\n","import type { App } from 'vue'\nimport PixelFlow from './components/PixelFlow.vue'\nexport type { PixelFlowOptions, PixelFlowInstance } from './types'\nexport { createPixelFlow } from './core/pixelFlow'\n\n// ----------------------------------------------------------------\n// Vue 插件安装函数\n// ----------------------------------------------------------------\nconst PixelFlowVue = {\n install(app: App) {\n app.component('PixelFlow', PixelFlow)\n },\n}\n\n// ----------------------------------------------------------------\n// 导出\n// ----------------------------------------------------------------\nexport { PixelFlow }\nexport default PixelFlowVue\n"],"names":["createPixelFlow","options","canvas","colors","particleCount","speed","pixelSize","onTick","rawCtx","ctx","rafId","running","makeParticle","w","h","particles","updateParticle","p","drawParticle","drawConnections","i","j","dx","dy","dist","loop","props","__props","emit","__emit","canvasRef","ref","stopFn","frame","canvasStyle","computed","start","stop","onMounted","onUnmounted","watch","__expose","_createElementBlock","PixelFlowVue","app","PixelFlow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pixel-flow-vue.umd.cjs","sources":["../src/core/pixelFlow.ts","../src/components/PixelFlow.vue","../src/index.ts"],"sourcesContent":["import type { PixelFlowOptions } from '../types'\n\ninterface Particle {\n x: number; y: number\n vx: number; vy: number\n color: string\n size: number\n alpha: number\n alphaDir: 1 | -1\n}\n\n/**\n * 创建像素粒子流动画。\n * @returns 停止函数,调用后取消动画循环。\n */\nexport function createPixelFlow(options: PixelFlowOptions): () => void {\n const {\n canvas,\n colors = ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount = 120,\n speed = 1,\n pixelSize = 4,\n onTick,\n } = options\n\n // 在 null 检查之后重新赋值为非空类型,避免 TS18047 在嵌套函数中误报\n const maybeCtx = canvas.getContext('2d')\n if (!maybeCtx) throw new Error('[pixel-flow-vue] Cannot get 2D context')\n const ctx: CanvasRenderingContext2D = maybeCtx\n\n let rafId = 0\n let active = true\n\n /* ---- 粒子工厂 ---- */\n function spawn(): Particle {\n return {\n x: Math.random() * canvas.width,\n y: Math.random() * canvas.height,\n vx: (Math.random() - 0.5) * speed * 2,\n vy: (Math.random() - 0.5) * speed * 2,\n color: colors[Math.floor(Math.random() * colors.length)],\n size: pixelSize * (0.4 + Math.random() * 0.8),\n alpha: Math.random(),\n alphaDir: Math.random() > 0.5 ? 1 : -1,\n }\n }\n\n const particles: Particle[] = Array.from({ length: particleCount }, spawn)\n\n /* ---- 更新 ---- */\n function update(p: Particle): void {\n p.x += p.vx * speed\n p.y += p.vy * speed\n if (p.x < 0 || p.x > canvas.width) p.vx *= -1\n if (p.y < 0 || p.y > canvas.height) p.vy *= -1\n p.alpha += 0.012 * p.alphaDir\n if (p.alpha >= 1) { p.alpha = 1; p.alphaDir = -1 }\n if (p.alpha <= 0.1) { p.alpha = 0.1; p.alphaDir = 1 }\n }\n\n /* ---- 绘制像素块 ---- */\n function drawPixel(p: Particle): void {\n ctx.globalAlpha = p.alpha\n ctx.fillStyle = p.color\n ctx.fillRect(Math.round(p.x), Math.round(p.y), Math.round(p.size), Math.round(p.size))\n }\n\n /* ---- 连线 ---- */\n function drawLinks(): void {\n const MAX = 80\n for (let i = 0; i < particles.length; i++) {\n for (let j = i + 1; j < particles.length; j++) {\n const dx = particles[i].x - particles[j].x\n const dy = particles[i].y - particles[j].y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < MAX) {\n ctx.globalAlpha = (1 - dist / MAX) * 0.22\n ctx.strokeStyle = particles[i].color\n ctx.lineWidth = 0.7\n ctx.beginPath()\n ctx.moveTo(particles[i].x, particles[i].y)\n ctx.lineTo(particles[j].x, particles[j].y)\n ctx.stroke()\n }\n }\n }\n }\n\n /* ---- 主循环 ---- */\n function loop(): void {\n if (!active) return\n const { width: w, height: h } = canvas\n // 拖尾:半透明黑色蒙层\n ctx.globalAlpha = 0.15\n ctx.fillStyle = '#000'\n ctx.fillRect(0, 0, w, h)\n ctx.globalAlpha = 1\n\n for (const p of particles) { update(p); drawPixel(p) }\n drawLinks()\n\n onTick?.()\n rafId = requestAnimationFrame(loop)\n }\n\n loop()\n\n return function stop(): void {\n active = false\n cancelAnimationFrame(rafId)\n }\n}\n","<template>\n <canvas\n ref=\"canvasRef\"\n :width=\"width\"\n :height=\"height\"\n :style=\"{ display: 'block', background: background }\"\n class=\"pixel-flow\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\nimport { createPixelFlow } from '../core/pixelFlow'\nimport type { PixelFlowInstance } from '../types'\n\n// ---------- props ----------\ninterface Props {\n /** 画布宽度,默认 600 */\n width?: number\n /** 画布高度,默认 400 */\n height?: number\n /** 粒子颜色数组 */\n colors?: string[]\n /** 粒子数量,默认 120 */\n particleCount?: number\n /** 速度倍率,默认 1 */\n speed?: number\n /** 像素块大小,默认 4 */\n pixelSize?: number\n /** 背景色,默认 #0d0d0d */\n background?: string\n /** 挂载后自动开始,默认 true */\n autoPlay?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n width: 600,\n height: 400,\n colors: () => ['#00f5ff', '#7b2fff', '#ff2fa0', '#ffdd00'],\n particleCount: 120,\n speed: 1,\n pixelSize: 4,\n background: '#0d0d0d',\n autoPlay: true,\n})\n\n// ---------- emits ----------\nconst emit = defineEmits<{\n (e: 'ready'): void\n (e: 'tick', frame: number): void\n}>()\n\n// ---------- internal ----------\nconst canvasRef = ref<HTMLCanvasElement | null>(null)\nlet stopFn: (() => void) | null = null\nlet frameCount = 0\n\nfunction start(): void {\n if (!canvasRef.value) return\n stopFn?.()\n stopFn = createPixelFlow({\n canvas: canvasRef.value,\n colors: props.colors,\n particleCount: props.particleCount,\n speed: props.speed,\n pixelSize: props.pixelSize,\n onTick: () => emit('tick', ++frameCount),\n })\n emit('ready')\n}\n\nfunction stop(): void {\n stopFn?.()\n stopFn = null\n}\n\nonMounted(() => { if (props.autoPlay) start() })\nonUnmounted(() => stop())\n\n// 配置变化时热重启\nwatch(\n () => [props.particleCount, props.speed, props.pixelSize, props.colors] as const,\n () => { if (stopFn) start() },\n { deep: true },\n)\n\n// ---------- expose ----------\ndefineExpose<PixelFlowInstance>({ start, stop })\n</script>\n\n<style scoped>\n.pixel-flow { border-radius: 4px; }\n</style>\n","/**\n * pixel-flow-vue\n * Vue 3 + TypeScript canvas pixel-flow animation plugin\n */\nimport type { App } from 'vue'\nimport PixelFlow from './components/PixelFlow.vue'\nimport { createPixelFlow } from './core/pixelFlow'\n\nexport type { PixelFlowOptions, PixelFlowInstance } from './types'\nexport { PixelFlow, createPixelFlow }\n\n// ---------- Vue plugin ----------\nconst PixelFlowVue = {\n install(app: App): void {\n app.component('PixelFlow', PixelFlow)\n },\n}\n\nexport default PixelFlowVue\n"],"names":["createPixelFlow","options","canvas","colors","particleCount","speed","pixelSize","onTick","maybeCtx","ctx","rafId","active","spawn","particles","update","p","drawPixel","drawLinks","i","j","dx","dy","dist","loop","w","h","props","__props","emit","__emit","canvasRef","ref","stopFn","frameCount","start","stop","onMounted","onUnmounted","watch","__expose","_createElementBlock","PixelFlowVue","app","PixelFlow"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.pixel-flow
|
|
1
|
+
.pixel-flow[data-v-02bb9f54]{border-radius:4px}
|
package/package.json
CHANGED
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixel-flow-vue",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A lightweight Vue 3 pixel-flow animation plugin with TypeScript support",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"description": "A lightweight Vue 3 pixel-flow canvas animation plugin with TypeScript support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/pixel-flow-vue.umd.cjs",
|
|
7
7
|
"module": "./dist/pixel-flow-vue.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import":
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/pixel-flow-vue.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/pixel-flow-vue.umd.cjs"
|
|
18
|
+
}
|
|
14
19
|
},
|
|
15
20
|
"./style.css": "./dist/style.css"
|
|
16
21
|
},
|
|
17
|
-
"files": [
|
|
18
|
-
|
|
19
|
-
"README.md",
|
|
20
|
-
"LICENSE"
|
|
21
|
-
],
|
|
22
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
23
|
+
"sideEffects": ["**/*.css"],
|
|
22
24
|
"scripts": {
|
|
23
|
-
"dev": "vite",
|
|
25
|
+
"dev": "vite --config vite.dev.config.ts",
|
|
24
26
|
"build": "vue-tsc --noEmit && vite build",
|
|
25
|
-
"
|
|
26
|
-
"preview": "vite preview",
|
|
27
|
-
"lint": "eslint src --ext .ts,.vue --fix"
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
|
-
"vue",
|
|
31
|
-
"
|
|
32
|
-
"plugin",
|
|
33
|
-
"pixel",
|
|
34
|
-
"flow",
|
|
35
|
-
"animation",
|
|
36
|
-
"canvas",
|
|
37
|
-
"typescript",
|
|
38
|
-
"component"
|
|
30
|
+
"vue", "vue3", "plugin", "pixel", "flow",
|
|
31
|
+
"animation", "canvas", "typescript", "component"
|
|
39
32
|
],
|
|
40
33
|
"author": "",
|
|
41
34
|
"license": "MIT",
|
|
@@ -51,10 +44,10 @@
|
|
|
51
44
|
"vue": "^3.3.0"
|
|
52
45
|
},
|
|
53
46
|
"devDependencies": {
|
|
54
|
-
"@types/node": "^20.
|
|
47
|
+
"@types/node": "^20.0.0",
|
|
55
48
|
"@vitejs/plugin-vue": "^5.0.0",
|
|
56
49
|
"typescript": "^5.4.0",
|
|
57
|
-
"vite": "^5.
|
|
50
|
+
"vite": "^5.0.0",
|
|
58
51
|
"vite-plugin-dts": "^3.9.0",
|
|
59
52
|
"vue": "^3.4.0",
|
|
60
53
|
"vue-tsc": "^2.0.0"
|