締めきっていたのですね
js
1<!DOCTYPE html>
2<meta charset="UTF-8">
3<title>Mouse Stalker</title>
4
5<body>
6
7<script>
8
9class P2{
10 constructor(x=0,y=0){this.x=x;this.y=y}
11 get clone(){return new P2(this.x,this.y)}//複写
12 add({x=0,y=0},{x:X,y:Y}=this){this.x=X+x;this.y=Y+y;return this}//加算
13 sub({x=0,y=0},{x:X,y:Y}=this){this.x=X-x;this.y=Y-y;return this}//減算
14 mul({x=0,y=0},{x:X,y:Y}=this){this.x=X*x;this.y=Y*y;return this}//乗算
15 div({x=0,y=0},{x:X,y:Y}=this){this.x=X/x;this.y=Y/y;return this}//除算
16 sMul(n=0,{x:X,y:Y}=this){this.x=X*n;this.y=Y*n;return this}//スカラー倍
17}
18//__
19
20//追いかける素となるもの(マウスの座標)
21class MousePointer extends P2 {
22 constructor (x, y) {
23 super (x, y);
24 }
25
26 handleEvent (event) {
27 this.x = event.clientX + window.pageXOffset;
28 this.y = event.clientY + window.pageYOffset;
29 }
30
31 static create (view = document) {
32 let obj = new this ();
33 view.addEventListener ('mousemove', obj, false);
34 return obj;
35 }
36}
37
38//__
39//追いかけるもの
40class Stalker extends P2 {
41 constructor (target, images, pointer, option = {}) {
42 super (pointer.x, pointer.y);
43 this.target = target;
44 this.images = images;
45 this.pointer = pointer;
46 this.option = Object.assign ({}, this.constructor.getDefaultOption (), option);
47 this.disabled = false;
48
49 this.chase ();
50 }
51
52
53 chase () {
54 const { PI, floor:int } = Math;
55 if (this.disabled) return;
56 let
57 dp = this.pointer.clone.sub (this),
58 n = 360 / this.images.length,
59 ang = Math.atan2 (dp.x, -dp.y) * 180 / PI;
60
61 this.add (dp.sMul (this.option.accelerator));
62 this.locate ();
63 this.target.src = this.images[int ((360 + ang) % 360 / n)].src;
64 requestAnimationFrame (this.chase.bind (this));
65 }
66
67
68 locate () {
69 const int = Math.floor;
70 let p = this.option.offset.clone.add (this);
71 Object.assign (this.target.style, { left: int (p.x) + 'px', top: int (p.y) + 'px'});
72 return this;
73 }
74
75
76 static getDefaultOption () {
77 return {
78 offset: new P2 (0, 0),
79 accelerator: .9
80 };
81 }
82
83
84 static create (imageList, pointer, option = { }) {
85 let
86 div = document.createElement ('div'),
87 target = new Image,
88 style = {position: 'absolute', left: '0px', top: '0px'},
89 images = imageList.map (src=> Object.assign (new Image, {src}));
90
91 target.src = images[0].src;
92 Object.assign (div.style, style);
93 Object.assign (target.style, style);
94 document.body.appendChild (div).appendChild (target);
95
96 return new Stalker (target, images, pointer, option);
97 }
98}
99
100//__
101
102const src = [
103 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJklI+py33gYgsAymsCrVjqzXXMB4YiQpbmmaor1rpvFMvzWFf6bjm1xgv6frYdjhhMKoifpJKWerKiwpOgJRVhq1NStrPlWa9UsTVsPJfT3SZXu9aN0XK19w2O3zz6HvxuNiZYAAA7',
104 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJklI+py+0Po5xUhIuzziDuz3UeuAHmRIYnmppuRbovBcqzVNvrWOr7k/OJgB/hrRE0EnvGnyLZRBabMgbUJsA+p8JDdauJIo6IsFLhLF/Ei+EiwK4YzvKxrt7+4tHpvdcPGChRAAA7',
105 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJXlI+py+0Po2Rh2lBtxFk73nkLGIoIWZoCmh7sC1PwTI70jSn4nuy868MdAMSi8YhMEg3KpnPJfEqNiKk1YZUqss4FV6kaIsNiKjlaPJcB6nJb/B7G56oCADs=',
106 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJjlI+py+0Po5zUhFDhvbnt3SnfFx4AMILheaacx7Csiy1vIsu0eJu57kKQFD9gyjIkFlu0UWPJbPaUS+mUWrRCoKhmhOv9QncS8HFiTpbH6i23e32+o+s5U2yfufOykv8P6FAAADs=',
107 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJnlI+pywkPQZi02QhptQw/PXGdBwbi4kngqaQl65ArfLgzLdgabugb7gvxgqahbGfEvJKRJfD4a6SIpSJiqqwiW9iPVjjCfq1SsZZldp6mVWbm9mxueTk5mN57k/F5FR8l8dchSChQAAA7',
108 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJmlI+py+0PE4j0gFvj3dnt3y3fGCLjGHjN+QXuOins5tYMZ85AzYu4oNvxbDJQcEgsBmnI1G15aTqfS+kDar0emxpdFuLlUmbfLkpcOUmn49aaDWa+4Z7oPKm9DzV6ZOkPGCg4yFAAADs=',
109 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJXlI+py+0PAZwJSErtxU9vzngfWInkIlpnmbbuaLxyqsy2xt4zoutH7xMAg4KA8YhMKpcBBPMJbTqj1KOiWl1go4zts7FcXZPisbWcQKLN63H7+o7L54cCADs=',
110 'data:image/gif;base64,R0lGODlhIAAgAJEAAPwAAYcAAf///wAAACH5BAEAAAIALAAAAAAgACAAAAJflI+py+0PYwO02nthwDzr3XFSQIZeRJYmIBmp2rXuC8YtDYsjXusfb0LxcpjfMOgYvpAM5TLUcD5tCtoMx0S8tEBoIlXtFsNNcaWZNMu+3XUY517A43IwvXzP6/d8fQEAOw=='
111];
112
113let
114 pointer0 = MousePointer.create (),
115 pointer1 = Stalker.create (src, pointer0, {offset: new P2(20,20), accelerator: .1}),
116 pointer2 = Stalker.create (src, pointer1, {offset: new P2(40,40), accelerator: .09}),
117 pointer3 = Stalker.create (src, pointer2, {offset: new P2(60,60), accelerator: .08});
118 pointer4 = Stalker.create (src, pointer3, {offset: new P2(80,80), accelerator: .07});
119 pointer5 = Stalker.create (src, pointer4, {offset: new P2(100,100), accelerator: .06});
120 pointer6 = Stalker.create (src, pointer5, {offset: new P2(120,120), accelerator: .05});
121 pointer7 = Stalker.create (src, pointer6, {offset: new P2(140,140), accelerator: .04});
122
123</script>