Easy to understand anti-shake and throttling animation (and learn a little canvas)
A set of Canvas animations to describe what debounce and throttle do;
Online experience: online-demo
Inspiration comes from: a graph second understand function tremble and function throttling
Image preview:
Figure: A vertical line represents a function call, a function shake is executed after a certain interval, and a function throttling is executed only once in a certain period of time.
The opening nonsense
When I just started working, I still didn’t know exactly what kind of situation anti-shake and throttling were. Every time I meet this kind of requirement, I find the code on Baidu and then copy and paste it. Until the nuggets in the community to see an article a figure second understand function tremble and function throttling after suddenly understood, easy to understand, decisive point like, collection; Until today, when I went to the interview, I made handwriting anti-shaking and throttling, haha… Wrote a simpler version of the method;
Today is a summary for myself; Use canvas to realize and move pictures in other people’s articles;
Canvas part
Write canvas as a prototype
const Canvas = function(canvas) {
const { round } = Math
this.canvas = canvas || document.createElement('canvas') / / canvas element
this.ctx = this.canvas.getContext('2d') // Create the context object
this.font_content_width = 0 // The size of the left text area
this.row_height = round(this.canvas.height / 3) // The height of each area
// Render page data
this.data = {
option: {
width: 2.// The width of each square
height: 0.8.// The height of each square as a percentage of the entire line
interval: 3 // The space between two squares
},
// Function data
lists: {
common_array_data: {
desc: 'the ordinary (common)'.list: / * * / [] [...Array(1000).keys()].map(v= > v % Number.MAX_SAFE_INTEGER) // Initialize the data
},
debounce_array_data: {
desc: 'image stabilization (debounce)'.list: / * * / [] [...Array(1000).keys()].map(v= > v % 2) // Initialize the data
},
throttle_array_data: {
desc: 'the throttle (throttle)'.list: / * * / [] [...Array(1000).keys()].map(v= > v % 4) // Initialize the data}}}}Copy the code
Draw the left part of the text
Canvas.prototype.draw_text = function() {
const ctx = this.ctx
const { width, height } = this.canvas // Get the canvas width and height
// Find the width of the left text area by calculating the width of the text
const _set_text_content_width = (text, x = 10) = > {
const { round } = Math
// Add X space to both sides of the text
const font_width = round(ctx.measureText(text).width + x * 2)
if (!this.font_content_width) {
this.font_content_width = font_width
return
}
if (this.font_content_width < font_width) {
this.font_content_width = font_width
}
}
// Set the font
ctx.font = '16px Arial'
// Draw the left caption text
Object.keys(this.data.lists).forEach((key, index) = > {
// Get the text
const text = this.data.lists[key].desc
// Count the width
_set_text_content_width(text, 10)
// Compute the top of the text
const top = this.row_height * (index + 0.5)
// Draw text
ctx.fillText(text, 10, top)
})
}
Copy the code
Achieve drawing small square method
Canvas.prototype.fillRect = function() {
const ctx = this.ctx
const { min } = Math
ctx.fillStyle = '# 999' // Fill the color
let line_length_arr = [] // Stores three drawn lengths
// Iterate over the data
Object.keys(this.data.lists).forEach((key, index) = > {
// Get method data
const { desc, list } = this.data.lists[key]
// The data stored by each method
list.forEach((v, i) = > {
// Get the configuration properties for each square
const { width = 2, height = 0.8, interval = 2 } = this.data.option
// Calculate the X coordinates of each square X = left text header area + (square width + gap) * index (several)
const x = this.font_content_width + i * (width + interval)
// Calculate the Y coordinate of each square Y = height of each row * (remaining 100% in half + index (outer loop))
const y = this.row_height * ((1 - height) / 2 + index)
// Draw a square if the array value is not 0
if (v) {
ctx.fillRect(x, y, width, this.row_height * height)
}
// Collect the data for the last square
if (i === list.length - 1) {
line_length_arr.push(x + width + interval)
}
})
})
// Default to empty array if there is no data;
line_length_arr = line_length_arr.length ? line_length_arr : [0]
// Fetch the shortest value
constmin_line_length = min(... line_length_arr)// Determine if the shortest is beyond the right render area
if (min_line_length > this.canvas.width) {
// Erase the right area
ctx.clearRect(
this.font_content_width,
0.Number.MAX_SAFE_INTEGER,
Number.MAX_SAFE_INTEGER
)
const lists = this.data.lists
Object.keys(lists).forEach(key= > (lists[key].list = []))
}
}
Copy the code
Implement Canvas animation init
Canvas.prototype.init = function() {
this.draw_text()
const _start = (a)= > {
this.fillRect()
// console.log(' Running... ')
window.requestAnimationFrame(_start)
}
window.requestAnimationFrame(_start)
}
Copy the code
Anti-shake and throttling parts
Function debounce
When an event is continuously emitted, the event handler is executed only once if no event is emitted within a certain period of time. If the event is triggered again before the set time arrives, the delay starts again;
const debounce = (fn, t) = > {
let time
return function(. arg) {
clearTimeout(time)
let that = this
time = setTimeout(function(. arg) {
fn.apply(that, arg)
}, t)
}
}
Copy the code
Function throttle
Ensure that the event handler function is called only once in a certain period of time when the event is continuously triggered.
const throttle = (fn, t) = > {
let now = Date.now()
return function(. arg) {
if (Date.now() - now > t) {
fn.apply(this, arg)
now = Date.now()
}
}
}
Copy the code
Implement it in Demo
Create a example_fn method and add data to the instance object
const example_fn = (time = 300, living, log = false) = > {
const debounce_fn = debounce((a)= > {
log && console.error('if you')
living.data.lists.debounce_array_data.list.push(1)
}, time)
const throttle_fu = throttle((a)= > {
log && console.warn('the throttling')
living.data.lists.throttle_array_data.list.push(1)
}, time)
return function() {
log && console.log('ordinary')
living.data.lists.common_array_data.list.push(1)
throttle_fu()
living.data.lists.throttle_array_data.list.push(0)
debounce_fn()
living.data.lists.debounce_array_data.list.push(0)}}Copy the code
Create the instance and initialize it
let C = new Canvas(document.querySelector('canvas'))
C.init()
Copy the code
Create a method for the use instance
const fn = example_fn(300, C, false)
Copy the code
Example
- Bind input box input events
document.querySelector('input').addEventListener('input', fn)
Copy the code
- Bind the Canvas mouse movement event
document.querySelector('canvas').addEventListener('mousemove', fn)
Copy the code
- Binding browser resize window event
window.addEventListener('resize', fn)
Copy the code
conclusion
Function stabilization: Combine several operations into one operation. The idea is to maintain a timer that fires after the delay, but if it fires again within the delay, the timer will be cancelled and reset. In this way, only the last operation can be triggered.
Function throttling: causes functions to fire only once in a given period of time. The principle is to trigger the function by judging whether a certain time has been reached.
Thank you for reading
9102 years, I am still discussing this (manual face covering), my ability to write is not good, I hope you can correct more
The Internet is not easy to survive, do not snipe