valaxy-theme-hairy 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -21
- package/client/index.ts +1 -1
- package/components/HairyBody.vue +49 -49
- package/components/HairyCodepen.vue +40 -40
- package/components/HairyComment.vue +33 -33
- package/components/HairyContainer.vue +17 -17
- package/components/HairyDrawer.vue +44 -44
- package/components/HairyFooter.vue +62 -62
- package/components/HairyHeader.vue +32 -32
- package/components/HairyImage.vue +15 -15
- package/components/HairyImageGroup.vue +65 -65
- package/components/HairyNavbar.vue +56 -56
- package/components/HairyPageArchives.vue +59 -59
- package/components/HairyPageTags.vue +48 -48
- package/components/HairyPosts.vue +54 -54
- package/components/HairySearch.vue +201 -201
- package/components/HairySidebar.vue +30 -30
- package/components/HairyTabbar.vue +56 -56
- package/components/PageTags.vue +48 -48
- package/components/ValaxyMain.vue +45 -45
- package/components/navbar/HairyNav.vue +16 -16
- package/components/navbar/HairyNavExpand.vue +12 -12
- package/components/navbar/HairyNavItem.vue +35 -35
- package/components/navbar/HairyNavbarBackground.vue +7 -7
- package/components/navbar/HairyNavbarSearch.vue +8 -8
- package/components/navbar/HairyNavbarTitle.vue +15 -15
- package/components/navbar/HairyNavbarToggleDark.vue +22 -22
- package/components/parts/HairyBreadcrumb.vue +51 -51
- package/components/parts/HairyBreadcrumbItem.vue +11 -11
- package/components/parts/HairyFootFish.js +352 -352
- package/components/parts/HairyFootFish.vue +38 -38
- package/components/parts/HairyHeadHero.vue +34 -34
- package/components/parts/HairyHeadWaves.vue +67 -67
- package/components/parts/HairyImageGlobal.vue +51 -51
- package/components/parts/HairyImageViewer.vue +23 -23
- package/components/parts/HairyLink.vue +21 -21
- package/components/parts/HairyMenu.vue +16 -16
- package/components/parts/HairyMenuItem.vue +47 -47
- package/components/parts/HairyOutline.vue +99 -99
- package/components/parts/HairyOutlineItem.vue +48 -48
- package/components/parts/HairySocialLinks.vue +27 -27
- package/components/parts/HairyTimelineContent.vue +39 -39
- package/components/parts/HairyUserNav.vue +95 -95
- package/components/parts/HairyUserStats.vue +18 -18
- package/components/posts/HairyArticleImage.vue +126 -126
- package/components/posts/HairyArticleSeries.vue +89 -89
- package/components/posts/HairyArticleText.vue +43 -43
- package/components/posts/HairyPostFooter.vue +15 -15
- package/components/posts/HairyPostImageList.vue +27 -27
- package/components/posts/HairyPostTextsList.vue +22 -22
- package/components/posts/HairyPostToggleLayout.vue +36 -36
- package/components/third/HairyAlgoliaSearch.vue +17 -17
- package/components/third/HairyFuseSearch.vue +10 -10
- package/components/third/HairyFuseSearchDialog.vue +32 -32
- package/components/third/HairyFuseSearchDropdown.vue +77 -77
- package/components/third/HairyFuseSearchFooter.vue +28 -28
- package/components/third/HairyFuseSearchHeader.vue +30 -30
- package/components/third/HairyFuseSearchHit.vue +52 -52
- package/components/third/HairySearchBtnDisplay.vue +29 -29
- package/components/third/HairySearchBtnInput.vue +20 -20
- package/components/third/HairySearchBtnKeys.vue +19 -19
- package/components/third/HairySwiperCarousel.vue +45 -45
- package/composables/archives.ts +48 -48
- package/composables/category.ts +43 -43
- package/composables/config.ts +11 -11
- package/composables/dark.ts +13 -13
- package/composables/fuse.ts +60 -60
- package/composables/index.ts +7 -7
- package/composables/layout.ts +16 -16
- package/composables/outline.ts +49 -49
- package/composables/tags.ts +36 -36
- package/layouts/archive-month.vue +13 -13
- package/layouts/archive-year.vue +13 -13
- package/layouts/archives.vue +11 -11
- package/layouts/categories.vue +13 -13
- package/layouts/default.vue +13 -15
- package/layouts/home.vue +33 -33
- package/layouts/post.vue +54 -54
- package/layouts/tag.vue +10 -10
- package/layouts/tags.vue +10 -14
- package/library/loading.scss +535 -535
- package/library/loading.ts +60 -60
- package/library/scroll.ts +22 -22
- package/locales/en.yml +1 -1
- package/locales/zh-CN.yml +1 -1
- package/node/images/default.json +139 -139
- package/node/images/index.ts +46 -46
- package/node/images/shims.d.ts +8 -8
- package/node/index.ts +2 -2
- package/node/theme/index.ts +78 -78
- package/package.json +1 -1
- package/pages/archives/[year]/[month]/index.vue +48 -48
- package/pages/archives/[year]/index.vue +73 -73
- package/pages/archives/index.md +6 -0
- package/pages/categories/[...its].vue +108 -108
- package/pages/index.vue +8 -8
- package/pages/page/[page].vue +12 -12
- package/pages/tags/[tag]/index.vue +38 -38
- package/pages/tags/index.md +7 -0
- package/setup/main.ts +9 -9
- package/store/index.ts +1 -1
- package/store/modules/global.ts +12 -12
- package/styles/components/aplayer.scss +75 -75
- package/styles/components/index.scss +3 -3
- package/styles/components/markdown.scss +89 -89
- package/styles/components/nprogress.scss +15 -15
- package/styles/components/scrollbar.scss +25 -25
- package/styles/css-vars.scss +171 -171
- package/styles/element-plus/index.scss +1 -1
- package/styles/element-plus/tabs.scss +25 -25
- package/styles/element-plus/timeline.scss +18 -18
- package/styles/font-face.scss +19 -19
- package/styles/global.scss +38 -38
- package/styles/index.scss +3 -3
- package/tsconfig.json +27 -27
- package/types/index.d.ts +163 -163
- package/unocss.config.ts +43 -43
- package/utils/index.ts +37 -37
- package/valaxy.config.ts +26 -26
- package/pages/archives/index.vue +0 -6
- package/pages/tags/index.vue +0 -6
@@ -1,352 +1,352 @@
|
|
1
|
-
/* eslint-disable ts/no-use-before-define */
|
2
|
-
/* eslint-disable eqeqeq */
|
3
|
-
|
4
|
-
class RENDERER {
|
5
|
-
ENABLE = false
|
6
|
-
POINT_INTERVAL = 5
|
7
|
-
FISH_COUNT = 3
|
8
|
-
MAX_INTERVAL_COUNT = 50
|
9
|
-
INIT_HEIGHT_RATE = 0.5
|
10
|
-
THRESHOLD = 50
|
11
|
-
|
12
|
-
COLOR = 'hsl(0, 0%, 95%)'
|
13
|
-
|
14
|
-
constructor(color) {
|
15
|
-
if (this.ENABLE)
|
16
|
-
return
|
17
|
-
|
18
|
-
this.setColor(color)
|
19
|
-
this.removeCanvas()
|
20
|
-
this.setParameters()
|
21
|
-
this.reconstructMethods()
|
22
|
-
this.setup()
|
23
|
-
this.bindEvent()
|
24
|
-
this.render()
|
25
|
-
this.ENABLE = true
|
26
|
-
}
|
27
|
-
|
28
|
-
removeCanvas() {
|
29
|
-
const container = document.querySelector('#jsi-flying-fish-container')
|
30
|
-
const canvas = container.querySelector('canvas')
|
31
|
-
if (canvas)
|
32
|
-
canvas.remove()
|
33
|
-
}
|
34
|
-
|
35
|
-
setColor(color) {
|
36
|
-
if (color)
|
37
|
-
this.COLOR = color
|
38
|
-
}
|
39
|
-
|
40
|
-
setParameters() {
|
41
|
-
this.$window = $(window)
|
42
|
-
this.$container = $('#jsi-flying-fish-container')
|
43
|
-
this.$canvas = $('<canvas />')
|
44
|
-
this.context = this.$canvas.appendTo(this.$container).get(0).getContext('2d')
|
45
|
-
this.points = []
|
46
|
-
this.fishes = []
|
47
|
-
this.watchIds = []
|
48
|
-
}
|
49
|
-
|
50
|
-
createSurfacePoints() {
|
51
|
-
const count = Math.round(this.width / this.POINT_INTERVAL)
|
52
|
-
this.pointInterval = this.width / (count - 1)
|
53
|
-
this.points.push(new SURFACE_POINT(this, 0))
|
54
|
-
for (let i = 1; i < count; i++) {
|
55
|
-
const point = new SURFACE_POINT(this, i * this.pointInterval)
|
56
|
-
const previous = this.points[i - 1]
|
57
|
-
point.setPreviousPoint(previous)
|
58
|
-
previous.setNextPoint(point)
|
59
|
-
this.points.push(point)
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
reconstructMethods() {
|
64
|
-
this.watchWindowSize = this.watchWindowSize.bind(this)
|
65
|
-
this.jdugeToStopResize = this.jdugeToStopResize.bind(this)
|
66
|
-
this.startEpicenter = this.startEpicenter.bind(this)
|
67
|
-
this.moveEpicenter = this.moveEpicenter.bind(this)
|
68
|
-
this.reverseVertical = this.reverseVertical.bind(this)
|
69
|
-
this.render = this.render.bind(this)
|
70
|
-
}
|
71
|
-
|
72
|
-
setup() {
|
73
|
-
this.points.length = 0
|
74
|
-
this.fishes.length = 0
|
75
|
-
this.watchIds.length = 0
|
76
|
-
this.intervalCount = this.MAX_INTERVAL_COUNT
|
77
|
-
this.width = this.$container.width()
|
78
|
-
this.height = this.$container.height()
|
79
|
-
this.fishCount = (((this.FISH_COUNT * this.width) / 500) * this.height) / 500
|
80
|
-
this.$canvas.attr({ width: this.width, height: this.height })
|
81
|
-
this.reverse = false
|
82
|
-
this.fishes.push(new FISH(this))
|
83
|
-
this.createSurfacePoints()
|
84
|
-
}
|
85
|
-
|
86
|
-
watchWindowSize() {
|
87
|
-
this.clearTimer()
|
88
|
-
this.tmpWidth = this.$window.width()
|
89
|
-
this.tmpHeight = this.$window.height()
|
90
|
-
this.watchIds.push(setTimeout(this.jdugeToStopResize, this.WATCH_INTERVAL))
|
91
|
-
}
|
92
|
-
|
93
|
-
clearTimer() {
|
94
|
-
while (this.watchIds.length > 0)
|
95
|
-
clearTimeout(this.watchIds.pop())
|
96
|
-
}
|
97
|
-
|
98
|
-
jdugeToStopResize() {
|
99
|
-
const width = this.$window.width()
|
100
|
-
const height = this.$window.height()
|
101
|
-
const stopped = width == this.tmpWidth && height == this.tmpHeight
|
102
|
-
this.tmpWidth = width
|
103
|
-
this.tmpHeight = height
|
104
|
-
if (stopped)
|
105
|
-
this.setup()
|
106
|
-
}
|
107
|
-
|
108
|
-
bindEvent() {
|
109
|
-
this.$window.on('resize', this.watchWindowSize)
|
110
|
-
this.$container.on('mouseenter', this.startEpicenter)
|
111
|
-
this.$container.on('mousemove', this.moveEpicenter)
|
112
|
-
}
|
113
|
-
|
114
|
-
getAxis(event) {
|
115
|
-
const offset = this.$container.offset()
|
116
|
-
return { x: event.clientX - offset.left + this.$window.scrollLeft(), y: event.clientY - offset.top + this.$window.scrollTop() }
|
117
|
-
}
|
118
|
-
|
119
|
-
startEpicenter(event) {
|
120
|
-
this.axis = this.getAxis(event)
|
121
|
-
}
|
122
|
-
|
123
|
-
moveEpicenter(event) {
|
124
|
-
const axis = this.getAxis(event)
|
125
|
-
if (!this.axis)
|
126
|
-
this.axis = axis
|
127
|
-
|
128
|
-
this.generateEpicenter(axis.x, axis.y, axis.y - this.axis.y)
|
129
|
-
this.axis = axis
|
130
|
-
}
|
131
|
-
|
132
|
-
generateEpicenter(x, y, velocity) {
|
133
|
-
if (y < this.height / 2 - this.THRESHOLD || y > this.height / 2 + this.THRESHOLD)
|
134
|
-
return
|
135
|
-
|
136
|
-
const index = Math.round(x / this.pointInterval)
|
137
|
-
if (index < 0 || index >= this.points.length)
|
138
|
-
return
|
139
|
-
|
140
|
-
if (this.points[index])
|
141
|
-
this.points[index].interfere(y, velocity)
|
142
|
-
}
|
143
|
-
|
144
|
-
reverseVertical() {
|
145
|
-
this.reverse = !this.reverse
|
146
|
-
for (let i = 0, count = this.fishes.length; i < count; i++)
|
147
|
-
this.fishes[i].reverseVertical()
|
148
|
-
}
|
149
|
-
|
150
|
-
controlStatus() {
|
151
|
-
for (let i = 0, count = this.points.length; i < count; i++)
|
152
|
-
this.points[i].updateSelf()
|
153
|
-
|
154
|
-
for (let i = 0, count = this.points.length; i < count; i++)
|
155
|
-
this.points[i].updateNeighbors()
|
156
|
-
|
157
|
-
if (this.fishes.length < this.fishCount && --this.intervalCount == 0) {
|
158
|
-
this.intervalCount = this.MAX_INTERVAL_COUNT
|
159
|
-
this.fishes.push(new FISH(this))
|
160
|
-
}
|
161
|
-
}
|
162
|
-
|
163
|
-
render() {
|
164
|
-
requestAnimationFrame(this.render)
|
165
|
-
this.controlStatus()
|
166
|
-
this.context.clearRect(0, 0, this.width, this.height)
|
167
|
-
this.context.fillStyle = this.COLOR
|
168
|
-
for (let i = 0, count = this.fishes.length; i < count; i++)
|
169
|
-
this.fishes[i].render(this.context)
|
170
|
-
|
171
|
-
this.context.save()
|
172
|
-
this.context.globalCompositeOperation = 'xor'
|
173
|
-
this.context.beginPath()
|
174
|
-
this.context.moveTo(0, this.reverse ? 0 : this.height)
|
175
|
-
for (let i = 0, count = this.points.length; i < count; i++)
|
176
|
-
this.points[i].render(this.context)
|
177
|
-
|
178
|
-
this.context.lineTo(this.width, this.reverse ? 0 : this.height)
|
179
|
-
this.context.closePath()
|
180
|
-
this.context.fill()
|
181
|
-
this.context.restore()
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
const SURFACE_POINT = function (renderer, x) {
|
186
|
-
this.renderer = renderer
|
187
|
-
this.x = x
|
188
|
-
this.init()
|
189
|
-
}
|
190
|
-
|
191
|
-
SURFACE_POINT.prototype = {
|
192
|
-
SPRING_CONSTANT: 0.03,
|
193
|
-
SPRING_FRICTION: 0.9,
|
194
|
-
WAVE_SPREAD: 0.3,
|
195
|
-
ACCELARATION_RATE: 0.01,
|
196
|
-
init() {
|
197
|
-
this.initHeight = this.renderer.height * this.renderer.INIT_HEIGHT_RATE
|
198
|
-
this.height = this.initHeight
|
199
|
-
this.fy = 0
|
200
|
-
this.force = { previous: 0, next: 0 }
|
201
|
-
},
|
202
|
-
setPreviousPoint(previous) {
|
203
|
-
this.previous = previous
|
204
|
-
},
|
205
|
-
setNextPoint(next) {
|
206
|
-
this.next = next
|
207
|
-
},
|
208
|
-
interfere(y, velocity) {
|
209
|
-
this.fy = this.renderer.height * this.ACCELARATION_RATE * (this.renderer.height - this.height - y >= 0 ? -1 : 1) * Math.abs(velocity)
|
210
|
-
},
|
211
|
-
updateSelf() {
|
212
|
-
this.fy += this.SPRING_CONSTANT * (this.initHeight - this.height)
|
213
|
-
this.fy *= this.SPRING_FRICTION
|
214
|
-
this.height += this.fy
|
215
|
-
},
|
216
|
-
updateNeighbors() {
|
217
|
-
if (this.previous)
|
218
|
-
this.force.previous = this.WAVE_SPREAD * (this.height - this.previous.height)
|
219
|
-
|
220
|
-
if (this.next)
|
221
|
-
this.force.next = this.WAVE_SPREAD * (this.height - this.next.height)
|
222
|
-
},
|
223
|
-
render(context) {
|
224
|
-
if (this.previous) {
|
225
|
-
this.previous.height += this.force.previous
|
226
|
-
this.previous.fy += this.force.previous
|
227
|
-
}
|
228
|
-
if (this.next) {
|
229
|
-
this.next.height += this.force.next
|
230
|
-
this.next.fy += this.force.next
|
231
|
-
}
|
232
|
-
context.lineTo(this.x, this.renderer.height - this.height)
|
233
|
-
},
|
234
|
-
}
|
235
|
-
|
236
|
-
const FISH = function (renderer) {
|
237
|
-
this.renderer = renderer
|
238
|
-
this.init()
|
239
|
-
}
|
240
|
-
|
241
|
-
FISH.prototype = {
|
242
|
-
GRAVITY: 0.4,
|
243
|
-
init() {
|
244
|
-
this.direction = Math.random() < 0.5
|
245
|
-
this.x = this.direction ? this.renderer.width + this.renderer.THRESHOLD : -this.renderer.THRESHOLD
|
246
|
-
this.previousY = this.y
|
247
|
-
this.vx = this.getRandomValue(4, 7) * (this.direction ? -1 : 1)
|
248
|
-
|
249
|
-
if (this.renderer.reverse) {
|
250
|
-
this.y = this.getRandomValue((this.renderer.height * 1) / 10, (this.renderer.height * 4) / 10)
|
251
|
-
this.vy = this.getRandomValue(2, 5)
|
252
|
-
this.ay = this.getRandomValue(0.05, 0.2)
|
253
|
-
}
|
254
|
-
else {
|
255
|
-
this.y = this.getRandomValue((this.renderer.height * 6) / 10, (this.renderer.height * 9) / 10)
|
256
|
-
this.vy = this.getRandomValue(-5, -2)
|
257
|
-
this.ay = this.getRandomValue(-0.2, -0.05)
|
258
|
-
}
|
259
|
-
this.isOut = false
|
260
|
-
this.theta = 0
|
261
|
-
this.phi = 0
|
262
|
-
},
|
263
|
-
getRandomValue(min, max) {
|
264
|
-
return min + (max - min) * Math.random()
|
265
|
-
},
|
266
|
-
reverseVertical() {
|
267
|
-
this.isOut = !this.isOut
|
268
|
-
this.ay *= -1
|
269
|
-
},
|
270
|
-
controlStatus() {
|
271
|
-
this.previousY = this.y
|
272
|
-
this.x += this.vx
|
273
|
-
this.y += this.vy
|
274
|
-
this.vy += this.ay
|
275
|
-
if (this.renderer.reverse) {
|
276
|
-
if (this.y > this.renderer.height * this.renderer.INIT_HEIGHT_RATE) {
|
277
|
-
this.vy -= this.GRAVITY
|
278
|
-
this.isOut = true
|
279
|
-
}
|
280
|
-
else {
|
281
|
-
if (this.isOut)
|
282
|
-
this.ay = this.getRandomValue(0.05, 0.2)
|
283
|
-
|
284
|
-
this.isOut = false
|
285
|
-
}
|
286
|
-
}
|
287
|
-
else {
|
288
|
-
if (this.y < this.renderer.height * this.renderer.INIT_HEIGHT_RATE) {
|
289
|
-
this.vy += this.GRAVITY
|
290
|
-
this.isOut = true
|
291
|
-
}
|
292
|
-
else {
|
293
|
-
if (this.isOut)
|
294
|
-
this.ay = this.getRandomValue(-0.2, -0.05)
|
295
|
-
|
296
|
-
this.isOut = false
|
297
|
-
}
|
298
|
-
}
|
299
|
-
if (!this.isOut) {
|
300
|
-
this.theta += Math.PI / 20
|
301
|
-
this.theta %= Math.PI * 2
|
302
|
-
this.phi += Math.PI / 30
|
303
|
-
this.phi %= Math.PI * 2
|
304
|
-
}
|
305
|
-
this.renderer.generateEpicenter(this.x + (this.direction ? -1 : 1) * this.renderer.THRESHOLD, this.y, this.y - this.previousY)
|
306
|
-
if ((this.vx > 0 && this.x > this.renderer.width + this.renderer.THRESHOLD) || (this.vx < 0 && this.x < -this.renderer.THRESHOLD))
|
307
|
-
this.init()
|
308
|
-
},
|
309
|
-
render(context) {
|
310
|
-
context.save()
|
311
|
-
context.translate(this.x, this.y)
|
312
|
-
context.rotate(Math.PI + Math.atan2(this.vy, this.vx))
|
313
|
-
context.scale(1, this.direction ? 1 : -1)
|
314
|
-
context.beginPath()
|
315
|
-
context.moveTo(-30, 0)
|
316
|
-
context.bezierCurveTo(-20, 15, 15, 10, 40, 0)
|
317
|
-
context.bezierCurveTo(15, -10, -20, -15, -30, 0)
|
318
|
-
context.fill()
|
319
|
-
context.save()
|
320
|
-
context.translate(40, 0)
|
321
|
-
context.scale(0.9 + 0.2 * Math.sin(this.theta), 1)
|
322
|
-
context.beginPath()
|
323
|
-
context.moveTo(0, 0)
|
324
|
-
context.quadraticCurveTo(5, 10, 20, 8)
|
325
|
-
context.quadraticCurveTo(12, 5, 10, 0)
|
326
|
-
context.quadraticCurveTo(12, -5, 20, -8)
|
327
|
-
context.quadraticCurveTo(5, -10, 0, 0)
|
328
|
-
context.fill()
|
329
|
-
context.restore()
|
330
|
-
context.save()
|
331
|
-
context.translate(-3, 0)
|
332
|
-
context.rotate((Math.PI / 3 + (Math.PI / 10) * Math.sin(this.phi)) * (this.renderer.reverse ? -1 : 1))
|
333
|
-
context.beginPath()
|
334
|
-
if (this.renderer.reverse) {
|
335
|
-
context.moveTo(5, 0)
|
336
|
-
context.bezierCurveTo(10, 10, 10, 30, 0, 40)
|
337
|
-
context.bezierCurveTo(-12, 25, -8, 10, 0, 0)
|
338
|
-
}
|
339
|
-
else {
|
340
|
-
context.moveTo(-5, 0)
|
341
|
-
context.bezierCurveTo(-10, -10, -10, -30, 0, -40)
|
342
|
-
context.bezierCurveTo(12, -25, 8, -10, 0, 0)
|
343
|
-
}
|
344
|
-
context.closePath()
|
345
|
-
context.fill()
|
346
|
-
context.restore()
|
347
|
-
context.restore()
|
348
|
-
this.controlStatus(context)
|
349
|
-
},
|
350
|
-
}
|
351
|
-
|
352
|
-
export { RENDERER }
|
1
|
+
/* eslint-disable ts/no-use-before-define */
|
2
|
+
/* eslint-disable eqeqeq */
|
3
|
+
|
4
|
+
class RENDERER {
|
5
|
+
ENABLE = false
|
6
|
+
POINT_INTERVAL = 5
|
7
|
+
FISH_COUNT = 3
|
8
|
+
MAX_INTERVAL_COUNT = 50
|
9
|
+
INIT_HEIGHT_RATE = 0.5
|
10
|
+
THRESHOLD = 50
|
11
|
+
|
12
|
+
COLOR = 'hsl(0, 0%, 95%)'
|
13
|
+
|
14
|
+
constructor(color) {
|
15
|
+
if (this.ENABLE)
|
16
|
+
return
|
17
|
+
|
18
|
+
this.setColor(color)
|
19
|
+
this.removeCanvas()
|
20
|
+
this.setParameters()
|
21
|
+
this.reconstructMethods()
|
22
|
+
this.setup()
|
23
|
+
this.bindEvent()
|
24
|
+
this.render()
|
25
|
+
this.ENABLE = true
|
26
|
+
}
|
27
|
+
|
28
|
+
removeCanvas() {
|
29
|
+
const container = document.querySelector('#jsi-flying-fish-container')
|
30
|
+
const canvas = container.querySelector('canvas')
|
31
|
+
if (canvas)
|
32
|
+
canvas.remove()
|
33
|
+
}
|
34
|
+
|
35
|
+
setColor(color) {
|
36
|
+
if (color)
|
37
|
+
this.COLOR = color
|
38
|
+
}
|
39
|
+
|
40
|
+
setParameters() {
|
41
|
+
this.$window = $(window)
|
42
|
+
this.$container = $('#jsi-flying-fish-container')
|
43
|
+
this.$canvas = $('<canvas />')
|
44
|
+
this.context = this.$canvas.appendTo(this.$container).get(0).getContext('2d')
|
45
|
+
this.points = []
|
46
|
+
this.fishes = []
|
47
|
+
this.watchIds = []
|
48
|
+
}
|
49
|
+
|
50
|
+
createSurfacePoints() {
|
51
|
+
const count = Math.round(this.width / this.POINT_INTERVAL)
|
52
|
+
this.pointInterval = this.width / (count - 1)
|
53
|
+
this.points.push(new SURFACE_POINT(this, 0))
|
54
|
+
for (let i = 1; i < count; i++) {
|
55
|
+
const point = new SURFACE_POINT(this, i * this.pointInterval)
|
56
|
+
const previous = this.points[i - 1]
|
57
|
+
point.setPreviousPoint(previous)
|
58
|
+
previous.setNextPoint(point)
|
59
|
+
this.points.push(point)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
reconstructMethods() {
|
64
|
+
this.watchWindowSize = this.watchWindowSize.bind(this)
|
65
|
+
this.jdugeToStopResize = this.jdugeToStopResize.bind(this)
|
66
|
+
this.startEpicenter = this.startEpicenter.bind(this)
|
67
|
+
this.moveEpicenter = this.moveEpicenter.bind(this)
|
68
|
+
this.reverseVertical = this.reverseVertical.bind(this)
|
69
|
+
this.render = this.render.bind(this)
|
70
|
+
}
|
71
|
+
|
72
|
+
setup() {
|
73
|
+
this.points.length = 0
|
74
|
+
this.fishes.length = 0
|
75
|
+
this.watchIds.length = 0
|
76
|
+
this.intervalCount = this.MAX_INTERVAL_COUNT
|
77
|
+
this.width = this.$container.width()
|
78
|
+
this.height = this.$container.height()
|
79
|
+
this.fishCount = (((this.FISH_COUNT * this.width) / 500) * this.height) / 500
|
80
|
+
this.$canvas.attr({ width: this.width, height: this.height })
|
81
|
+
this.reverse = false
|
82
|
+
this.fishes.push(new FISH(this))
|
83
|
+
this.createSurfacePoints()
|
84
|
+
}
|
85
|
+
|
86
|
+
watchWindowSize() {
|
87
|
+
this.clearTimer()
|
88
|
+
this.tmpWidth = this.$window.width()
|
89
|
+
this.tmpHeight = this.$window.height()
|
90
|
+
this.watchIds.push(setTimeout(this.jdugeToStopResize, this.WATCH_INTERVAL))
|
91
|
+
}
|
92
|
+
|
93
|
+
clearTimer() {
|
94
|
+
while (this.watchIds.length > 0)
|
95
|
+
clearTimeout(this.watchIds.pop())
|
96
|
+
}
|
97
|
+
|
98
|
+
jdugeToStopResize() {
|
99
|
+
const width = this.$window.width()
|
100
|
+
const height = this.$window.height()
|
101
|
+
const stopped = width == this.tmpWidth && height == this.tmpHeight
|
102
|
+
this.tmpWidth = width
|
103
|
+
this.tmpHeight = height
|
104
|
+
if (stopped)
|
105
|
+
this.setup()
|
106
|
+
}
|
107
|
+
|
108
|
+
bindEvent() {
|
109
|
+
this.$window.on('resize', this.watchWindowSize)
|
110
|
+
this.$container.on('mouseenter', this.startEpicenter)
|
111
|
+
this.$container.on('mousemove', this.moveEpicenter)
|
112
|
+
}
|
113
|
+
|
114
|
+
getAxis(event) {
|
115
|
+
const offset = this.$container.offset()
|
116
|
+
return { x: event.clientX - offset.left + this.$window.scrollLeft(), y: event.clientY - offset.top + this.$window.scrollTop() }
|
117
|
+
}
|
118
|
+
|
119
|
+
startEpicenter(event) {
|
120
|
+
this.axis = this.getAxis(event)
|
121
|
+
}
|
122
|
+
|
123
|
+
moveEpicenter(event) {
|
124
|
+
const axis = this.getAxis(event)
|
125
|
+
if (!this.axis)
|
126
|
+
this.axis = axis
|
127
|
+
|
128
|
+
this.generateEpicenter(axis.x, axis.y, axis.y - this.axis.y)
|
129
|
+
this.axis = axis
|
130
|
+
}
|
131
|
+
|
132
|
+
generateEpicenter(x, y, velocity) {
|
133
|
+
if (y < this.height / 2 - this.THRESHOLD || y > this.height / 2 + this.THRESHOLD)
|
134
|
+
return
|
135
|
+
|
136
|
+
const index = Math.round(x / this.pointInterval)
|
137
|
+
if (index < 0 || index >= this.points.length)
|
138
|
+
return
|
139
|
+
|
140
|
+
if (this.points[index])
|
141
|
+
this.points[index].interfere(y, velocity)
|
142
|
+
}
|
143
|
+
|
144
|
+
reverseVertical() {
|
145
|
+
this.reverse = !this.reverse
|
146
|
+
for (let i = 0, count = this.fishes.length; i < count; i++)
|
147
|
+
this.fishes[i].reverseVertical()
|
148
|
+
}
|
149
|
+
|
150
|
+
controlStatus() {
|
151
|
+
for (let i = 0, count = this.points.length; i < count; i++)
|
152
|
+
this.points[i].updateSelf()
|
153
|
+
|
154
|
+
for (let i = 0, count = this.points.length; i < count; i++)
|
155
|
+
this.points[i].updateNeighbors()
|
156
|
+
|
157
|
+
if (this.fishes.length < this.fishCount && --this.intervalCount == 0) {
|
158
|
+
this.intervalCount = this.MAX_INTERVAL_COUNT
|
159
|
+
this.fishes.push(new FISH(this))
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
render() {
|
164
|
+
requestAnimationFrame(this.render)
|
165
|
+
this.controlStatus()
|
166
|
+
this.context.clearRect(0, 0, this.width, this.height)
|
167
|
+
this.context.fillStyle = this.COLOR
|
168
|
+
for (let i = 0, count = this.fishes.length; i < count; i++)
|
169
|
+
this.fishes[i].render(this.context)
|
170
|
+
|
171
|
+
this.context.save()
|
172
|
+
this.context.globalCompositeOperation = 'xor'
|
173
|
+
this.context.beginPath()
|
174
|
+
this.context.moveTo(0, this.reverse ? 0 : this.height)
|
175
|
+
for (let i = 0, count = this.points.length; i < count; i++)
|
176
|
+
this.points[i].render(this.context)
|
177
|
+
|
178
|
+
this.context.lineTo(this.width, this.reverse ? 0 : this.height)
|
179
|
+
this.context.closePath()
|
180
|
+
this.context.fill()
|
181
|
+
this.context.restore()
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
const SURFACE_POINT = function (renderer, x) {
|
186
|
+
this.renderer = renderer
|
187
|
+
this.x = x
|
188
|
+
this.init()
|
189
|
+
}
|
190
|
+
|
191
|
+
SURFACE_POINT.prototype = {
|
192
|
+
SPRING_CONSTANT: 0.03,
|
193
|
+
SPRING_FRICTION: 0.9,
|
194
|
+
WAVE_SPREAD: 0.3,
|
195
|
+
ACCELARATION_RATE: 0.01,
|
196
|
+
init() {
|
197
|
+
this.initHeight = this.renderer.height * this.renderer.INIT_HEIGHT_RATE
|
198
|
+
this.height = this.initHeight
|
199
|
+
this.fy = 0
|
200
|
+
this.force = { previous: 0, next: 0 }
|
201
|
+
},
|
202
|
+
setPreviousPoint(previous) {
|
203
|
+
this.previous = previous
|
204
|
+
},
|
205
|
+
setNextPoint(next) {
|
206
|
+
this.next = next
|
207
|
+
},
|
208
|
+
interfere(y, velocity) {
|
209
|
+
this.fy = this.renderer.height * this.ACCELARATION_RATE * (this.renderer.height - this.height - y >= 0 ? -1 : 1) * Math.abs(velocity)
|
210
|
+
},
|
211
|
+
updateSelf() {
|
212
|
+
this.fy += this.SPRING_CONSTANT * (this.initHeight - this.height)
|
213
|
+
this.fy *= this.SPRING_FRICTION
|
214
|
+
this.height += this.fy
|
215
|
+
},
|
216
|
+
updateNeighbors() {
|
217
|
+
if (this.previous)
|
218
|
+
this.force.previous = this.WAVE_SPREAD * (this.height - this.previous.height)
|
219
|
+
|
220
|
+
if (this.next)
|
221
|
+
this.force.next = this.WAVE_SPREAD * (this.height - this.next.height)
|
222
|
+
},
|
223
|
+
render(context) {
|
224
|
+
if (this.previous) {
|
225
|
+
this.previous.height += this.force.previous
|
226
|
+
this.previous.fy += this.force.previous
|
227
|
+
}
|
228
|
+
if (this.next) {
|
229
|
+
this.next.height += this.force.next
|
230
|
+
this.next.fy += this.force.next
|
231
|
+
}
|
232
|
+
context.lineTo(this.x, this.renderer.height - this.height)
|
233
|
+
},
|
234
|
+
}
|
235
|
+
|
236
|
+
const FISH = function (renderer) {
|
237
|
+
this.renderer = renderer
|
238
|
+
this.init()
|
239
|
+
}
|
240
|
+
|
241
|
+
FISH.prototype = {
|
242
|
+
GRAVITY: 0.4,
|
243
|
+
init() {
|
244
|
+
this.direction = Math.random() < 0.5
|
245
|
+
this.x = this.direction ? this.renderer.width + this.renderer.THRESHOLD : -this.renderer.THRESHOLD
|
246
|
+
this.previousY = this.y
|
247
|
+
this.vx = this.getRandomValue(4, 7) * (this.direction ? -1 : 1)
|
248
|
+
|
249
|
+
if (this.renderer.reverse) {
|
250
|
+
this.y = this.getRandomValue((this.renderer.height * 1) / 10, (this.renderer.height * 4) / 10)
|
251
|
+
this.vy = this.getRandomValue(2, 5)
|
252
|
+
this.ay = this.getRandomValue(0.05, 0.2)
|
253
|
+
}
|
254
|
+
else {
|
255
|
+
this.y = this.getRandomValue((this.renderer.height * 6) / 10, (this.renderer.height * 9) / 10)
|
256
|
+
this.vy = this.getRandomValue(-5, -2)
|
257
|
+
this.ay = this.getRandomValue(-0.2, -0.05)
|
258
|
+
}
|
259
|
+
this.isOut = false
|
260
|
+
this.theta = 0
|
261
|
+
this.phi = 0
|
262
|
+
},
|
263
|
+
getRandomValue(min, max) {
|
264
|
+
return min + (max - min) * Math.random()
|
265
|
+
},
|
266
|
+
reverseVertical() {
|
267
|
+
this.isOut = !this.isOut
|
268
|
+
this.ay *= -1
|
269
|
+
},
|
270
|
+
controlStatus() {
|
271
|
+
this.previousY = this.y
|
272
|
+
this.x += this.vx
|
273
|
+
this.y += this.vy
|
274
|
+
this.vy += this.ay
|
275
|
+
if (this.renderer.reverse) {
|
276
|
+
if (this.y > this.renderer.height * this.renderer.INIT_HEIGHT_RATE) {
|
277
|
+
this.vy -= this.GRAVITY
|
278
|
+
this.isOut = true
|
279
|
+
}
|
280
|
+
else {
|
281
|
+
if (this.isOut)
|
282
|
+
this.ay = this.getRandomValue(0.05, 0.2)
|
283
|
+
|
284
|
+
this.isOut = false
|
285
|
+
}
|
286
|
+
}
|
287
|
+
else {
|
288
|
+
if (this.y < this.renderer.height * this.renderer.INIT_HEIGHT_RATE) {
|
289
|
+
this.vy += this.GRAVITY
|
290
|
+
this.isOut = true
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
if (this.isOut)
|
294
|
+
this.ay = this.getRandomValue(-0.2, -0.05)
|
295
|
+
|
296
|
+
this.isOut = false
|
297
|
+
}
|
298
|
+
}
|
299
|
+
if (!this.isOut) {
|
300
|
+
this.theta += Math.PI / 20
|
301
|
+
this.theta %= Math.PI * 2
|
302
|
+
this.phi += Math.PI / 30
|
303
|
+
this.phi %= Math.PI * 2
|
304
|
+
}
|
305
|
+
this.renderer.generateEpicenter(this.x + (this.direction ? -1 : 1) * this.renderer.THRESHOLD, this.y, this.y - this.previousY)
|
306
|
+
if ((this.vx > 0 && this.x > this.renderer.width + this.renderer.THRESHOLD) || (this.vx < 0 && this.x < -this.renderer.THRESHOLD))
|
307
|
+
this.init()
|
308
|
+
},
|
309
|
+
render(context) {
|
310
|
+
context.save()
|
311
|
+
context.translate(this.x, this.y)
|
312
|
+
context.rotate(Math.PI + Math.atan2(this.vy, this.vx))
|
313
|
+
context.scale(1, this.direction ? 1 : -1)
|
314
|
+
context.beginPath()
|
315
|
+
context.moveTo(-30, 0)
|
316
|
+
context.bezierCurveTo(-20, 15, 15, 10, 40, 0)
|
317
|
+
context.bezierCurveTo(15, -10, -20, -15, -30, 0)
|
318
|
+
context.fill()
|
319
|
+
context.save()
|
320
|
+
context.translate(40, 0)
|
321
|
+
context.scale(0.9 + 0.2 * Math.sin(this.theta), 1)
|
322
|
+
context.beginPath()
|
323
|
+
context.moveTo(0, 0)
|
324
|
+
context.quadraticCurveTo(5, 10, 20, 8)
|
325
|
+
context.quadraticCurveTo(12, 5, 10, 0)
|
326
|
+
context.quadraticCurveTo(12, -5, 20, -8)
|
327
|
+
context.quadraticCurveTo(5, -10, 0, 0)
|
328
|
+
context.fill()
|
329
|
+
context.restore()
|
330
|
+
context.save()
|
331
|
+
context.translate(-3, 0)
|
332
|
+
context.rotate((Math.PI / 3 + (Math.PI / 10) * Math.sin(this.phi)) * (this.renderer.reverse ? -1 : 1))
|
333
|
+
context.beginPath()
|
334
|
+
if (this.renderer.reverse) {
|
335
|
+
context.moveTo(5, 0)
|
336
|
+
context.bezierCurveTo(10, 10, 10, 30, 0, 40)
|
337
|
+
context.bezierCurveTo(-12, 25, -8, 10, 0, 0)
|
338
|
+
}
|
339
|
+
else {
|
340
|
+
context.moveTo(-5, 0)
|
341
|
+
context.bezierCurveTo(-10, -10, -10, -30, 0, -40)
|
342
|
+
context.bezierCurveTo(12, -25, 8, -10, 0, 0)
|
343
|
+
}
|
344
|
+
context.closePath()
|
345
|
+
context.fill()
|
346
|
+
context.restore()
|
347
|
+
context.restore()
|
348
|
+
this.controlStatus(context)
|
349
|
+
},
|
350
|
+
}
|
351
|
+
|
352
|
+
export { RENDERER }
|