Front end “componentized series” catalogue
- Build components using JSX Parser
- “Two” uses JSX to establish a Markup component style
- “Three” use JSX to realize Carousel multicast module
- “Four” with JavaScript timeline and animation
- “Five” with JavaScript to achieve three times bezier animation library – front-end componentization
- “Six” use JavaScript to achieve gesture library – to achieve listening logic
- “Seven” use JavaScript to achieve gesture library – gesture logic
- “Eight” implements the gesture library in JavaScript – supports multi-key triggering
- “9” Using JavaScript to Implement Gesture Libraries — Event distribution and Flick Events
- . To be continued…
We implemented all of gesture in the last installment, so the next thing we need to implement is the event distribution function.
Provided by the event
In the DOM, the Event is dispatched by using a new Event, adding some attributes to it, and finally dispatching the Event.
Therefore, we are doing the same here, establishing a dSIpatch function and adding parameters such as Type and property. The property has the context object and the point coordinate properties.
In our Dispatch function, the first thing we need to do is create an Event object. In the new browser API, we can create it directly using new Event. Of course, we can also create a new CustomEvent using a CustomEvent. So in this case, we’ll just use a normal New Event.
function dispatch(type, properties) {
let event = new Event(type);
}
Copy the code
Then we loop through the properties object, copying out all the properties inside. Our new Event needs to be attached to an element, just attach it to the element we defined earlier.
function dispatch(type, properties) {
let event = new Event(type);
for (let name in properties) {
event[name] = properties[name];
}
element.dispatchEvent(event);
}
Copy the code
The problem with this is that the listeners we wrote were all mounted on element. And then finally we’re going to change all of this to mount on document.
element.addEventListener('mousedown'.event= > {
let context = Object.create(null);
contexts.set(`mouseThe ${1 << event.button}`, context);
start(event, context);
let mousemove = event= > {
let button = 1;
while (button <= event.buttons) {
if (button & event.buttons) {
let key;
// Order of buttons & button is not the same
if (button === 2) {
key = 4;
} else if (button === 4) {
key = 2;
} else {
key = button;
}
let context = contexts.get('mouse' + key);
move(event, context);
}
button = button << 1; }};let mouseup = event= > {
let context = contexts.get(`mouseThe ${1 << event.button}`);
end(event, context);
contexts.delete(`mouseThe ${1 << event.button}`);
if (event.buttons === 0) {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
isListeningMouse = false; }};if(! isListeningMouse) {document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
isListeningMouse = true; }});Copy the code
Dipatch = dipatch = dipatch = dipatch = dipatch
let end = (point, context) = > {
if (context.isTap) {
//console.log('tap');
// Replace the old console.log with the dispatch call
// This event does not require any special attributes, just pass 'empty object'
dispatch('tap', {})
clearTimeout(context.handler);
}
if (context.isPan) {
console.log('pan-end');
}
if (context.isPress) {
console.log('press-end'); }};Copy the code
So finally, we can try adding a script to the HTML that listens for our newly created TAP event.
<script src="gesture.js"></script>
<body oncontextmenu="event.preventDefault()"></body>
<script>
document.documentElement.addEventListener('tap'.() = > {
console.log('Tapped! ');
});
</script>
Copy the code
At that point, if we go to the browser and tap, we trigger a tap event and output the message “Tapped”!
And that would be the end of our distribution.
Implement a flick event
Here we finish up one last and most special flick event. The Flick event is unique in our system of events because it is a sudoku event.
As we mentioned earlier, after Pan Start, if we perform a quick finger swipe before the finger leaves the screen, reaching a certain speed will trigger our flick event instead of the original Pan End event.
So how do we figure out the velocity? We can actually get the speed of the current move in our move function. But this doesn’t help us, because if you just go by the speed at which you move between the two points, it will have a big error depending on the browser implementation.
So a more accurate way to do this is to take a number of points, and use the average of them as your value. So to do this, we need to store these points over a period of time, and then use those points to calculate the average speed.
Now that we have an idea, let’s sort out how to write this piece of logic in code.
First we need to add the first record point to our global context when start is triggered. Here we need to record several values:
t
: represents the time when the current point triggers/joins, which we use hereDate.now()
x
: represents the X-axis coordinates of the current pointy
: represents the Y-axis of the current point
These values are then used to calculate the speed of movement.
let start = (point, context) = > {
(context.startX = point.clientX), (context.startY = point.clientY);
context.points = [
{
t: Date.now(),
x: point.clientX,
y: point.clientY,
},
];
context.isPan = false;
context.isTap = true;
context.isPress = false;
context.handler = setTimeout(() = > {
context.isPan = false;
context.isTap = false;
context.isPress = true;
console.log('press-start');
context.handler = null;
}, 500);
};
Copy the code
Then each time a move is triggered, a new dot is added to the current content. But before adding new points, you need to filter the points already stored. We only need the points within the last 500 milliseconds to calculate the speed, and the rest can be filtered out.
When performing the flick, we don’t swipe for long distances and time, plus we need to capture a quick swipe, which must be within 500 milliseconds or not “fast” at all. So you only need points in 500 milliseconds.
let move = (point, context) = > {
let dx = point.clientX - context.startX,
dy = point.clientY - context.startY;
if(! context.isPan && dx **2 + dy ** 2 > 100) {
context.isPan = true;
context.isTap = false;
context.isPress = false;
console.log('pan-start');
clearTimeout(context.handler);
}
if (context.isPan) {
console.log(dx, dy);
console.log('pan');
}
context.points = context.points.filter(point= > Date.now() - point.t < 500);
context.points.push({
t: Date.now(),
x: point.clientX,
y: point.clientY,
});
};
Copy the code
When the end event is triggered, you can calculate the speed of the slide. Because this is how fast the user swipes, if the user is doing other gestures, you don’t need to calculate the speed. So this calculation logic can be written in the judgment that isPan is valid.
First give this gesture a state variable, isFlick, and give it a default value of false.
Again, before we calculate the speed, we need to filter all the points that are stored in our context, and filter out the points that are 500 milliseconds away.
In mathematics or physics, there is a formula for calculating speed: speed = distance/time. So if you want to calculate velocity here, the first thing you need to calculate is distance. And this is the diameter distance, so you add the x and y distances to the second power, and then you take the square root and you get the diameter distance that you want.
So the x-distance, for example, is the x-coordinate of the current point, minus the left of the X-axis of the first point in the record. You can do the same thing with the Y-axis. So with distance, we can get the time directly from the difference between the current point and the first point. And then we can figure out the velocity.
let end = (point, context) = > {
context.isFlick = false;
if (context.isTap) {
//console.log('tap');
// Replace the old console.log with the dispatch call
// This event does not require any special attributes, just pass 'empty object'
dispatch('tap'{});clearTimeout(context.handler);
}
if (context.isPan) {
context.points = context.points.filter(point= > Date.now() - point.t < 500);
let d = Math.sqrt((point.x - context.points[0].x) ** 2 + (point.y - context.points[0].y) ** 2);
let v = d / (Date.now() - context.points[0].t);
}
if (context.isPress) {
console.log('press-end'); }};Copy the code
Good. So we have v velocity between the two points. Now, how fast do we need to know to consider it a flick? It is best to use god’s perspective to directly calculate the speed of 1.5 pixels per millisecond. In fact, we can console. Log (v) and print out the speed, and then manually test it and find that v = 1.5 is about right).
So we can say that if v > 1.5, we consider the user’s gesture to be a flick, otherwise it’s a generic pan-end.
let end = (point, context) = > {
context.isFlick = false;
if (context.isTap) {
//console.log('tap');
// Replace the old console.log with the dispatch call
// This event does not require any special attributes, just pass 'empty object'
dispatch('tap'{});clearTimeout(context.handler);
}
if (context.isPan) {
context.points = context.points.filter(point= > Date.now() - point.t < 500);
let d = Math.sqrt((point.x - context.points[0].x) ** 2 + (point.y - context.points[0].y) ** 2);
let v = d / (Date.now() - context.points[0].t);
if (v > 1.5) {
context.isFlick = true;
dispatch('flick'{}); }else {
context.isFlick = false;
dispatch('panend'{}); }}if (context.isPress) {
console.log('press-end'); }};Copy the code
Now that the flick event is handled, there are some console.log() in this code that are not dispatched instead. But the next step is to see how to repackage the gesture library, so we won’t change it all here.
If you want to complete this code, you can correct all console.log(event name)
Finally, attach this complete code.
let element = document.documentElement;
let contexts = new Map(a);let isListeningMouse = false;
element.addEventListener('mousedown'.event= > {
let context = Object.create(null);
contexts.set(`mouseThe ${1 << event.button}`, context);
start(event, context);
let mousemove = event= > {
let button = 1;
while (button <= event.buttons) {
if (button & event.buttons) {
let key;
// Order of buttons & button is not the same
if (button === 2) {
key = 4;
} else if (button === 4) {
key = 2;
} else {
key = button;
}
let context = contexts.get('mouse' + key);
move(event, context);
}
button = button << 1; }};let mouseup = event= > {
let context = contexts.get(`mouseThe ${1 << event.button}`);
end(event, context);
contexts.delete(`mouseThe ${1 << event.button}`);
if (event.buttons === 0) {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
isListeningMouse = false; }};if(! isListeningMouse) {document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
isListeningMouse = true; }}); element.addEventListener('touchstart'.event= > {
for (let touch of event.changedTouches) {
let context = Object.create(null); contexts.set(event.identifier, context); start(touch, context); }}); element.addEventListener('touchmove'.event= > {
for (let touch of event.changedTouches) {
letcontext = contexts.get(touch.identifier); move(touch, context); }}); element.addEventListener('touchend'.event= > {
for (let touch of event.changedTouches) {
letcontext = contexts.get(touch.identifier); end(touch, context); contexts.delete(touch.identifier); }}); element.addEventListener('cancel'.event= > {
for (let touch of event.changedTouches) {
letcontext = contexts.get(touch.identifier); cancel(touch, context); contexts.delete(touch.identifier); }});let start = (point, context) = > {
(context.startX = point.clientX), (context.startY = point.clientY);
context.points = [
{
t: Date.now(),
x: point.clientX,
y: point.clientY,
},
];
context.isPan = false;
context.isTap = true;
context.isPress = false;
context.handler = setTimeout(() = > {
context.isPan = false;
context.isTap = false;
context.isPress = true;
console.log('press-start');
context.handler = null;
}, 500);
};
let move = (point, context) = > {
let dx = point.clientX - context.startX,
dy = point.clientY - context.startY;
if(! context.isPan && dx **2 + dy ** 2 > 100) {
context.isPan = true;
context.isTap = false;
context.isPress = false;
console.log('pan-start');
clearTimeout(context.handler);
}
if (context.isPan) {
console.log(dx, dy);
console.log('pan');
}
context.points = context.points.filter(point= > Date.now() - point.t < 500);
context.points.push({
t: Date.now(),
x: point.clientX,
y: point.clientY,
});
};
let end = (point, context) = > {
context.isFlick = false;
if (context.isTap) {
//console.log('tap');
// Replace the old console.log with the dispatch call
// This event does not require any special attributes, just pass 'empty object'
dispatch('tap'{});clearTimeout(context.handler);
}
if (context.isPan) {
context.points = context.points.filter(point= > Date.now() - point.t < 500);
let d, v;
if(! context.points.length) { v =0;
} else {
d = Math.sqrt(
(point.clientX - context.points[0].x) ** 2 + (point.clientY - context.points[0].y) ** 2
);
v = d / (Date.now() - context.points[0].t);
}
if (v > 1.5) {
context.isFlick = true;
dispatch('flick'{}); }else {
context.isFlick = false;
dispatch('panend'{}); }}if (context.isPress) {
console.log('press-end'); }};let cancel = (point, context) = > {
clearTimeout(context.handler);
console.log('cancel');
};
function dispatch(type, properties) {
let event = new Event(type);
for (let name in properties) {
event[name] = properties[name];
}
element.dispatchEvent(event);
}
Copy the code
Next time, we’ll look at the final step of the gesture library: encapsulation! ~
I’m Three Diamonds from Tech Galaxy, a tech guy who is reinventing knowledge. See you next time.
⭐️ three elder brother recommended
Open Source Project Recommendation
Hexo Theme Aurora
The following features were recently updated in version 1.5.0:
“Preview”
: sparkles: new
- Adaptive “Recommended Articles” layout (added a new”
Top article layout
“!!- The ability to toggle between Recommended articles and Top articles modes
- If the total number of articles is less than 3, it will automatically switch to “Top articles” mode
- Add “top” and “Recommended” tags to the article card
- Book: document
- Added custom containers like VuePress# 77
Info
The containerWarning
The containerDanger
The containerDetail
The container- preview
- Support for more SEO meta data# 76
- added
description
- added
keywords
- added
author
- Book: document
- added
Recently, bloggers have been fully engaged in the development of a “futuristic” Hexo theme, a blog theme based on the aurora.
If you’re a developer, creating a personal blog can be another bright spot on your resume. And if you have a really cool blog, it’s even brighter. It’s just sparkling.
If you like this theme, please click 🌟 on Github and let each other shine
Github address: github.com/auroral-ui/… Topics using document: aurora. Tridiamond. Tech/useful /
VSCode Aurora Future
Yeah, the blogger also did a VSCode theme for Aurora. The Hexo Theme Aurora color scheme was used. The key feature of this theme is to use only 3 colors, which reduces the distraction of multi-color coding and allows you to focus on writing code.
Like you can support oh! Just type “Aurora Future” into VSCode’s plugin search to find this theme. ~
Github address: github.com/auroral-ui/… Theme plugin address: marketplace.visualstudio.com/items?itemN…
Firefox Aurora Future
I don’t know about you, but I’ve been using Firefox for development lately. I think Firefox is really good. I recommend you try it.
And of course what I want to show you here is that I did an Aurora theme for Firefox as well. Right! They use the same color system. Like small partners can try oh!
Subject address: addons.mozilla.org/en-US/firef…
Bloggers are learning live at station B. Welcome to live Studio.
We are here to supervise each other, encourage each other, and strive to embark on the road of learning in life, so that learning changes our life!
It is boring and lonely on the way to study, but I hope it can bring us more company and more encouragement. Let’s refuel together! (๑ • ̀ ㅂ ́) organisation