国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用Javascript編寫一個(gè)鼠標(biāo)交互式跟隨特效和光標(biāo)交互效果

編寫一個(gè)互動(dòng)(并且超級(jí)令人滿意)的光標(biāo):7個(gè)簡單的步驟 + 2KB的代碼

近期我制作了這個(gè)光標(biāo)動(dòng)畫,人們似乎很喜歡它 :)

這是一個(gè)很好看的作品,但同時(shí)也非常簡單,只需2KB的JS代碼。

而且,這種方法非常通用,可以作為其他美麗作品的模板使用。因此,它值得有一個(gè)逐步指南!

鼠標(biāo)光標(biāo)特效結(jié)果

步驟#1:設(shè)置

我們正在<canvas>元素上繪圖,并且需要<canvas>全屏顯示。

canvas {
    position: fixed;
    top: 0;
    left: 0;
}
<canvas></canvas>
setupCanvas();
window.addEventListener("resize", setupCanvas);

function setupCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}

當(dāng)然,我們需要跟蹤光標(biāo)位置。

const pointer = {
    x: .5 * window.innerWidth,
    y: .5 * window.innerHeight,
}

window.addEventListener("click", e => {
    updateMousePosition(e.clientX, e.clientY);
});
window.addEventListener("mousemove", e => {
    updateMousePosition(e.clientX, e.clientY);
});
window.addEventListener("touchmove", e => {
    updateMousePosition(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
});

function updateMousePosition(eX, eY) {
    pointer.x = eX;
    pointer.y = eY;
}

步驟#2:動(dòng)畫循環(huán)

要看到最簡單的鼠標(biāo)跟隨動(dòng)畫,我們只需要使用該方法循環(huán)重畫畫布window.requestAnimationFrame(),并在每一步繪制以指針坐標(biāo)為中心的圓。

const p = {x: 0, y: 0}; // coordinate to draw

update(0);

function update(t) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // copy cursor position
    p.x = poiner.x;
    p.y = poiner.y;
    // draw a dot
    ctx.beginPath();
    ctx.arc(p.x, p.y, 5, 0, 2 * Math.PI);
    ctx.fill();

    window.requestAnimationFrame(update);
}

通過上面的代碼,我們有一個(gè)跟隨鼠標(biāo)的黑色圓圈。

鼠標(biāo)跟隨

步驟#3:添加延遲

現(xiàn)在,圓圈會(huì)盡可能快地跟隨光標(biāo)。讓我們添加一個(gè)延遲,以便點(diǎn)以某種彈性方式趕上目標(biāo)位置。

const params = {
    // ...
    spring: .4
};
// p.x = poiner.x;
// p.y = poiner.y;
p.x += (pointer.x - p.x) * params.spring;
p.y += (pointer.y - p.y) * params.spring;

ctx.beginPath();
ctx.arc(p.x, p.y, 5, 0, 2 * Math.PI);
ctx.fill();

spring 參數(shù)用于確定點(diǎn)追上光標(biāo)位置的速度。 像 0.1 這樣的小值會(huì)使其跟隨非常慢,而 spring = 1 意味著沒有延遲。

鼠標(biāo)延遲跟隨

步驟#3:創(chuàng)建鼠標(biāo)軌跡

讓我們創(chuàng)建一個(gè)點(diǎn)數(shù)據(jù)的軌跡數(shù)組,每個(gè)點(diǎn)都保存我們用來計(jì)算延遲的x/y坐標(biāo)和dx/增量。dy

const params = {
    // ...
    pointsNumber: 30
};

// const p = {x: 0, y: 0};

const trail = new Array(params.pointsNumber);
for (let i = 0; i < params.pointsNumber; i++) {
    trail[i] = {
        x: poiner.x,
        y: poiner.y,
        dx: 0,
        dy: 0,
    }
}

我們現(xiàn)在繪制整個(gè)軌跡,而不是單個(gè)點(diǎn),其中每個(gè)點(diǎn)都試圖趕上前一個(gè)點(diǎn)。第一個(gè)點(diǎn)追上了光標(biāo)坐標(biāo) ( pointer),并且第一個(gè)點(diǎn)的延遲更長 - 只是因?yàn)樗鼘ξ襾碚f看起來更好:)

function update(t) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    trail.forEach((p, pIdx) => {
        const prev = pIdx === 0 ? pointer : trail[pIdx - 1];
        const spring = pIdx === 0 ? .4 * params.spring : params.spring;

        p.dx = (prev.x - p.x) * spring;
        p.dy = (prev.y - p.y) * spring;

        p.x += p.dx;
        p.y += p.dy;

        ctx.beginPath();
        ctx.arc(p.x, p.y, 5, 0, 2 * Math.PI);
        ctx.fill();
    });

    window.requestAnimationFrame(update);
}

鼠標(biāo)蹤跡效果

步驟#4:將點(diǎn)轉(zhuǎn)向線

繪制折線而不是點(diǎn)很容易。

trail.forEach((p, pIdx) => {
    const prev = pIdx === 0 ? pointer : trail[pIdx - 1];

    p.dx = (prev.x - p.x) * params.spring;
    p.dy = (prev.y - p.y) * params.spring;

    p.x += p.dx;
    p.y += p.dy;

    // ctx.beginPath();
    // ctx.arc(p.x, p.y, 5, 0, 2 * Math.PI);
    // ctx.fill();

    if (pIdx === 0) {
        // start the line on the first point
        ctx.beginPath();
        ctx.moveTo(p.x, p.y);
    } else {
        // continue with new line segment to the following one
        ctx.lineTo(p.x, p.y);
    }
});

// draw the thing
ctx.stroke();

鼠標(biāo)折線

步驟#5:累積速度

使光標(biāo)動(dòng)畫看起來非常漂亮的是累積增量。讓我們不僅使用dx/dy來表示到鄰居位置的距離,而且還累加這個(gè)距離。

為了防止增量值變得超級(jí)大超級(jí)快,我們還在每個(gè)步驟上將dx/dy與新參數(shù)相乘。friction

const params = {
    // ...
    friction: .5
};

...

// ...

// p.dx = (prev.x - p.x) * spring;
// p.dy = (prev.y - p.y) * spring;
p.dx += (prev.x - p.x) * spring;
p.dy += (prev.y - p.y) * spring;
p.dx *= params.friction;
p.dy *= params.friction;

// as before
p.x += p.dx;
p.y += p.dy;

// ...

鼠標(biāo)積累效果

步驟#6:平滑線條

動(dòng)議完成!讓我們讓筆畫看起來更好,并將每條線段替換為貝塞爾曲線。

trail.forEach((p, pIdx) => {
    // calc p.x and p.y

    if (pIdx === 0) {
        ctx.beginPath();
        ctx.moveTo(p.x, p.y);
    // } else {
    //     ctx.lineTo(p.x, p.y);
    }
});

for (let i = 1; i < trail.length - 1; i++) {
    const xc = .5 * (trail[i].x + trail[i + 1].x);
    const yc = .5 * (trail[i].y + trail[i + 1].y);
    ctx.quadraticCurveTo(trail[i].x, trail[i].y, xc, yc);
}

ctx.stroke();

光滑的!

線條流暢效果

步驟#7:調(diào)整線寬

對于此演示,最后一步是將默認(rèn)值lineWidth1px 替換為每個(gè)段變得更小的動(dòng)態(tài)值。

const params = {
    baseWidth: .9,
};
...

for (let i = 1; i < trail.length - 1; i++) {
    // ...
    ctx.quadraticCurveTo(trail[i].x, trail[i].y, xc, yc);
    ctx.lineWidth = params.baseWidth * (params.pointsNumber - i);
}

最終曲線效果

全源碼示例

HTML

<canvas></canvas>


<div class="links">
    <a href="http://www.zghlxwxcb.cn" target="_blank">tutorial<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" ><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>    </a>
</div>

CSS

body, html {
    padding: 0;
    margin: 0;
     overscroll-behavior: none;
}

/* for tutorial link only */
.links {
    position: fixed;
    bottom: 10px;
    right: 10px;
    font-size: 18px;
    font-family: sans-serif;
     background-color: white;
     padding: 10px;
}
a {
    text-decoration: none;
    color: black;
    margin-left: 1em;
}
a:hover {
    text-decoration: underline;
}
a img.icon {
    display: inline-block;
    height: 1em;
    margin: 0 0 -0.1em 0.3em;
}

JS

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext('2d');

// for intro motion
let mouseMoved = false;

const pointer = {
    x: .5 * window.innerWidth,
    y: .5 * window.innerHeight,
}
const params = {
    pointsNumber: 40,
    widthFactor: .3,
    mouseThreshold: .6,
    spring: .4,
    friction: .5
};

const trail = new Array(params.pointsNumber);
for (let i = 0; i < params.pointsNumber; i++) {
    trail[i] = {
        x: pointer.x,
        y: pointer.y,
        dx: 0,
        dy: 0,
    }
}

window.addEventListener("click", e => {
    updateMousePosition(e.pageX, e.pageY);
});
window.addEventListener("mousemove", e => {
    mouseMoved = true;
    updateMousePosition(e.pageX, e.pageY);
});
window.addEventListener("touchmove", e => {
    mouseMoved = true;
    updateMousePosition(e.targetTouches[0].pageX, e.targetTouches[0].pageY);
});

function updateMousePosition(eX, eY) {
    pointer.x = eX;
    pointer.y = eY;
}

setupCanvas();
update(0);
window.addEventListener("resize", setupCanvas);


function update(t) {

    // for intro motion
    if (!mouseMoved) {
        pointer.x = (.5 + .3 * Math.cos(.002 * t) * (Math.sin(.005 * t))) * window.innerWidth;
        pointer.y = (.5 + .2 * (Math.cos(.005 * t)) + .1 * Math.cos(.01 * t)) * window.innerHeight;
    }

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    trail.forEach((p, pIdx) => {
        const prev = pIdx === 0 ? pointer : trail[pIdx - 1];
        const spring = pIdx === 0 ? .4 * params.spring : params.spring;
        p.dx += (prev.x - p.x) * spring;
        p.dy += (prev.y - p.y) * spring;
        p.dx *= params.friction;
        p.dy *= params.friction;
        p.x += p.dx;
        p.y += p.dy;
    });

    ctx.beginPath();
    ctx.moveTo(trail[0].x, trail[0].y);

    for (let i = 1; i < trail.length - 1; i++) {
        const xc = .5 * (trail[i].x + trail[i + 1].x);
        const yc = .5 * (trail[i].y + trail[i + 1].y);
        ctx.quadraticCurveTo(trail[i].x, trail[i].y, xc, yc);
        ctx.lineWidth = params.widthFactor * (params.pointsNumber - i);
        ctx.stroke();
    }
    ctx.lineTo(trail[trail.length - 1].x, trail[trail.length - 1].y);
    ctx.stroke();
   
    window.requestAnimationFrame(update);
}

function setupCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;


文章來源地址http://www.zghlxwxcb.cn/article/395.html

到此這篇關(guān)于使用Javascript編寫一個(gè)鼠標(biāo)交互式跟隨特效和光標(biāo)交互效果的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

原文地址:http://www.zghlxwxcb.cn/article/395.html

如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請聯(lián)系站長進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Python+turtle交互式繪圖:可以用鼠標(biāo)拖動(dòng)的小海龜

    Python+turtle交互式繪圖:可以用鼠標(biāo)拖動(dòng)的小海龜

    功能描述:代碼運(yùn)行后,在窗口上顯示3個(gè)小海龜,使用鼠標(biāo)拖動(dòng)小海龜時(shí)可以動(dòng)態(tài)改變窗口顏色,如下圖所示。 說明:本例代碼主體部分來自turtle Demo,我稍微修改了一下,重點(diǎn)增加了注釋,方便閱讀和理解。 參考代碼: ----------相關(guān)閱讀---------- 教學(xué)課件 1900頁P(yáng)ython系列P

    2023年04月08日
    瀏覽(25)
  • 創(chuàng)建交互式用戶體驗(yàn):探索JavaScript中的Prompt功能

    在前端開發(fā)中,JavaScript的 prompt() 函數(shù)是一個(gè)強(qiáng)大而有用的工具,它可以創(chuàng)建交互式的用戶體驗(yàn)。無論是接收用戶輸入、進(jìn)行簡單的驗(yàn)證還是實(shí)現(xiàn)高級(jí)的交互功能, prompt() 函數(shù)都能勝任。本篇博客將深入探討 prompt() 函數(shù)的用法、最佳實(shí)踐和一些示例代碼,為您展示如何利用它

    2024年02月15日
    瀏覽(20)
  • 19個(gè)Web前端交互式3D JavaScript框架和庫

    19個(gè)Web前端交互式3D JavaScript框架和庫

    JavaScript (JS) 是一種輕量級(jí)的解釋(或即時(shí)編譯)編程語言,是世界上最流行的編程語言。JavaScript 是一種基于原型的多范式、單線程的動(dòng)態(tài)語言,支持面向?qū)ο?、命令式和聲明式(例如函?shù)式編程)風(fēng)格。JavaScript 幾乎可以做任何事情,更可以在包括物聯(lián)網(wǎng)在內(nèi)的多個(gè)平臺(tái)

    2024年02月22日
    瀏覽(20)
  • 構(gòu)建一個(gè)動(dòng)態(tài)交互式圖表

    在Web開發(fā)中,JavaScript不僅是實(shí)現(xiàn)交互效果的關(guān)鍵,還可以用于構(gòu)建復(fù)雜的可視化組件,如動(dòng)態(tài)交互式圖表。在本篇博客中,我將演示如何使用JavaScript和HTML5的Canvas元素來創(chuàng)建一個(gè)簡單的動(dòng)態(tài)條形圖。 HTML結(jié)構(gòu) ?首先,我們需要一個(gè)HTML結(jié)構(gòu)來容納我們的圖表。 JavaScript實(shí)現(xiàn) 接下

    2024年02月20日
    瀏覽(30)
  • 用 ChatGPT 嘗試 JavaScript 交互式學(xué)習(xí)體驗(yàn),有用但不完美

    用 ChatGPT 嘗試 JavaScript 交互式學(xué)習(xí)體驗(yàn),有用但不完美

    很好,但還不能取代專家導(dǎo)師,有時(shí)還會(huì)犯錯(cuò)! ChatGPT 教小狗編程( Midjourney 創(chuàng)作) GPT-4剛剛發(fā)布,相較于GPT-3.5,它有顯著的增強(qiáng)功能。其中之一是它在更長時(shí)間的交互和更大的提示下,能夠更好地保持連貫性。 多年來,我一直致力于建立前端教學(xué)網(wǎng)站,為JavaScript開發(fā)人員

    2024年02月02日
    瀏覽(24)
  • Linux【腳本 05】交互式shell腳本編寫及問題處理([: ==: unary operator expected)[: ==: 期待一元表達(dá)式

    之前寫了Windows的cmd腳本用來保存報(bào)告文件: 但是有時(shí)候服務(wù)僅在Linux環(huán)境上進(jìn)行部署,所以要寫一個(gè)shell腳本進(jìn)行報(bào)告的保存。 2.1 初始版本 簡單的參數(shù)判斷,這里只給出一個(gè)分支,腳本save.sh內(nèi)容如下: 此時(shí)如果執(zhí)行腳本時(shí)沒有攜帶參數(shù),將會(huì)報(bào)錯(cuò): 這個(gè)腳本的問題很多

    2024年02月09日
    瀏覽(18)
  • Python【Matplotlib】交互式時(shí)間序列繪圖,將x軸設(shè)置為日期時(shí)間格式并和鼠標(biāo)拖動(dòng)縮放相結(jié)合

    Python【Matplotlib】交互式時(shí)間序列繪圖,將x軸設(shè)置為日期時(shí)間格式并和鼠標(biāo)拖動(dòng)縮放相結(jié)合

    上篇博客:python【matplotlib】鼠標(biāo)拖動(dòng)滾動(dòng)縮放坐標(biāo)范圍和拖動(dòng)圖例共存,得到啟發(fā),我們已經(jīng)可以通過鼠標(biāo)拖動(dòng)縮放坐標(biāo)范圍和移動(dòng)圖例,來實(shí)現(xiàn)動(dòng)態(tài)交互式繪圖了,對于x軸是時(shí)間序列的繪圖需求,能否也實(shí)現(xiàn)動(dòng)態(tài)交互式繪圖呢? 答案是肯定的,接下來我將詳細(xì)描述其實(shí)現(xiàn)

    2024年03月13日
    瀏覽(26)
  • 使用 htmx 構(gòu)建交互式 Web 應(yīng)用

    學(xué)習(xí)目標(biāo):了解htmx的基本概念、特點(diǎn)和用法,并能夠運(yùn)用htmx來創(chuàng)建交互式的Web應(yīng)用程序。 學(xué)習(xí)內(nèi)容: 1. 什么是htmx? ? ?- htmx是一種用于構(gòu)建交互式Web應(yīng)用程序的JavaScript庫。 ? ?- 它通過將HTML擴(kuò)展為一種聲明性的交互式語言,使得開發(fā)人員可以使用簡單的HTML標(biāo)記來實(shí)現(xiàn)動(dòng)態(tài)

    2024年02月10日
    瀏覽(17)
  • 使用Gradio庫創(chuàng)建交互式散點(diǎn)圖

    使用Gradio庫創(chuàng)建交互式散點(diǎn)圖

    ??覺得內(nèi)容不錯(cuò)的話,歡迎點(diǎn)贊收藏加關(guān)注??????,后續(xù)會(huì)繼續(xù)輸入更多優(yōu)質(zhì)內(nèi)容?? ??有問題歡迎大家加關(guān)注私戳或者評論(包括但不限于NLP算法相關(guān),linux學(xué)習(xí)相關(guān),讀研讀博相關(guān)......)?? 博主原文鏈接:https://www.yourmetaverse.cn/nlp/424/ (封面圖由文心一格生成)

    2024年02月16日
    瀏覽(14)
  • TransformControls 是 Three.js 中的一個(gè)類,用于在網(wǎng)頁中進(jìn)行 3D 場景中物體的交互式操作。

    TransformControls 是 Three.js 中的一個(gè)類,用于在網(wǎng)頁中進(jìn)行 3D 場景中物體的交互式操作。

    demo案例 TransformControls 是 Three.js 中的一個(gè)類,用于在網(wǎng)頁中進(jìn)行 3D 場景中物體的交互式操作。讓我們來詳細(xì)講解它的輸入?yún)?shù)、輸出、屬性和方法: 輸入?yún)?shù): TransformControls 構(gòu)造函數(shù)通常接受兩個(gè)參數(shù): camera (THREE.Camera):用于渲染場景的攝像機(jī)。這個(gè)參數(shù)是必需的。

    2024年04月15日
    瀏覽(92)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包