canvas使用滑杆交互

介绍 (Introduction)

How nice or fun can we make the interactions on a website or web application? The truth is that most could be better than we do today. For example, who would not want to use an application like this:

我们可以在网站或Web应用程序上进行互动有多有趣? 事实是,大多数情况可能会比今天更好。 例如,谁不想使用这样的应用程序:

Credit: Jakub Antalik on dribble

图片来源: Jakub Antalik运球

In this tutorial we will see how to implement a creative component to upload files, using as inspiration the previous animation by Jakub Antalík. The idea is to bring better visual feedback around what happens with the file after is dropped.

在本教程中,我们将利用JakubAntalík的先前动画作为灵感,了解如何实现一个创意组件来上传文件。 这个想法是关于删除文件后发生的情况带来更好的视觉反馈。

We will be focusing only on implementing the drag and drop interactions and some animations, without actually implementing all the necessary logic to actually upload the files to the server and use the component in production.

我们将只注重实现dragdrop的相互作用和一些动画,而无需实际执行所有必要的逻辑实际的文件上传到服务器,并在生产中使用的组件。

This is what our component will look like:

这是我们的组件的外观:

You can see the live demo or play with the code in Codepen. But if you also want to know how it works, just keep reading.

您可以观看现场演示或在Codepen中玩代码 。 但是,如果您还想知道其工作原理,请继续阅读。

During the tutorial we will be seeing two main aspects:

在本教程中,我们将看到两个主要方面:

  • We will learn how to implement a simple particle system using Javascript and Canvas.我们将学习如何使用Javascript和Canvas实现简单的粒子系统。
  • We will implement everything necessary to handle drag and drop events.

    我们将实施一切必要措施来处理dragdrop的事件。

In addition to the usual technologies (HTML, CSS, Javascript), to code our component we will use the lightweight animation library anime.js.

除了常用的技术(HTML,CSS,Javascript)之外,我们还将使用轻量级动画库anime.js来编码我们的组件。

第1步-创建HTML结构 (Step 1 — Creating the HTML Structure)

In this case our HTML structure will be quite basic:

在这种情况下,我们HTML结构将是非常基本的:

<!-- Form to upload the files -->
<form class="upload" method="post" action="" enctype="multipart/form-data" novalidate=""><!-- The `input` of type `file` --><input class="upload__input" name="files[]" type="file" multiple=""/><!-- The `canvas` element to draw the particles --><canvas class="upload__canvas"></canvas><!-- The upload icon --><div class="upload__icon"><svg viewBox="0 0 470 470"><path d="m158.7 177.15 62.8-62.8v273.9c0 7.5 6 13.5 13.5 13.5s13.5-6 13.5-13.5v-273.9l62.8 62.8c2.6 2.6 6.1 4 9.5 4 3.5 0 6.9-1.3 9.5-4 5.3-5.3 5.3-13.8 0-19.1l-85.8-85.8c-2.5-2.5-6-4-9.5-4-3.6 0-7 1.4-9.5 4l-85.8 85.8c-5.3 5.3-5.3 13.8 0 19.1 5.2 5.2 13.8 5.2 19 0z"></path></svg></div>
</form>

As you can see, we only need a form element and a file type input to allow the upload of files to the server. In our component we also need a canvas element to draw the particles and an SVG icon.

如您所见,我们只需要一个form元素和一个file类型input就可以将文件上传到服务器。 在我们的组件中,我们还需要一个canvas元素来绘制粒子和一个SVG图标。

Keep in mind that to use a component like this in production, you must fill in the action attribute in the form, and perhaps add a label element for the input, etc.

请记住,要在生产环境中使用此类组件,必须在表单中填写action属性,并可能为输入添加label元素,等等。

第2步-添加CSS样式 (Step 2 — Adding CSS Styles)

We will be using SCSS as the CSS preprocessor, but the styles we are using are very close to being plain CSS and they are quite simple.

我们将使用SCSS作为CSS预处理程序,但是我们使用的样式非常接近纯CSS,而且非常简单。

Let’s start by positioning the form and canvas elements, among other basic styles:

让我们从canvas formcanvas元素以及其他基本样式开始:

// Position `form` and `canvas` full width and height
.upload, .upload__canvas {position: absolute;left: 0;top: 0;width: 100%;height: 100%;
}// Position the `canvas` behind all other elements
.upload__canvas {z-index: -1;
}// Hide the file `input`
.upload__input {display: none;
}

Now let’s see the styles needed for our form, both for the initial state (hidden) and for when it is active (the user is dragging files to upload). The code has been commented exhaustively for a better understanding:

现在,让我们看一下form所需的样式,包括初始状态(隐藏)和活动状态(用户拖动文件进行上传)所需的样式。 该代码已被详尽注释以更好地理解:

// Styles for the upload `form`
.upload {z-index: 1; // should be the higher `z-index`// Styles for the `background`background-color: rgba(4, 72, 59, 0.8);background-image: radial-gradient(ellipse at 50% 120%, rgba(4, 72, 59, 1) 10%, rgba(4, 72, 59, 0) 40%);background-position: 0 300px;background-repeat: no-repeat;// Hide it by defaultopacity: 0;visibility: hidden;// Transitiontransition: 0.5s;// Upload overlay, that prevent the event `drag-leave` to be triggered while dragging over inner elements&:after {position: absolute;content: '';left: 0;top: 0;width: 100%;height: 100%;}
}// Styles applied while files are being dragging over the screen
.upload--active {// Translate the `radial-gradient`background-position: 0 0;// Show the upload componentopacity: 1;visibility: visible;// Only transition `opacity`, preventing issues with `visibility`transition-property: opacity;
}

Finally, let’s look at the simple styles that we have applied to the upload icon:

最后,让我们看一下已应用于上传图标的简单样式:

// Styles for the icon
.upload__icon {position: relative;left: calc(50% - 40px);top: calc(50% - 40px);width: 80px;height: 80px;padding: 15px;border-radius: 100%;background-color: #EBF2EA;path {fill: rgba(4, 72, 59, 0.8);}
}

Now our component looks like we want, so we’re ready to add interactivity with Javascript.

现在我们的组件看起来像我们想要的,因此我们准备添加与Javascript的交互性。

第3步-开发粒子系统 (Step 3 — Developing a Particle System)

Before implementing the drag and drop functionality, let’s see how we can implement a particle system.

实施之前dragdrop功能,让我们看看如何可以实现粒子系统。

In our particle system, each particle will be a simple Javascript Object with basic parameters to define how the particle should behave. And all the particles will be stored in an Array, which in our code is called particles.

在我们的粒子系统中,每个粒子将是一个具有基本参数的简单Javascript Object ,以定义粒子的行为方式。 并且所有粒子都将存储在一个Array ,在我们的代码中称为particles

Then, adding a new particle to our system is a matter of creating a new Javascrit Object and adding it to the particles array. Check the comments so you understand the purpose of each property:

然后,向我们的系统中添加新粒子就是创建一个新的Javascrit Object并将其添加到particles数组的问题。 检查注释,以便您了解每个属性的用途:

// Create a new particle
function createParticle(options) {var o = options || {};particles.push({'x': o.x, // particle position in the `x` axis'y': o.y, // particle position in the `y` axis'vx': o.vx, // in every update (animation frame) the particle will be translated this amount of pixels in `x` axis'vy': o.vy, // in every update (animation frame) the particle will be translated this amount of pixels in `y` axis'life': 0, // in every update (animation frame) the life will increase'death': o.death || Math.random() * 200, // consider the particle dead when the `life` reach this value'size': o.size || Math.floor((Math.random() * 2) + 1) // size of the particle});
}

Now that we have defined the basic structure of our particle system, we need a loop function, which allows us to add new particles, update them and draw them on the canvas in each animation frame. Something like this:

现在我们已经定义了粒子系统的基本结构,我们需要一个循环函数,该函数允许我们添加新的粒子,更新它们并将其绘制在每个动画帧中的canvas上。 像这样:

// Loop to redraw the particles on every frame
function loop() {addIconParticles(); // add new particles for the upload iconupdateParticles(); // update all particlesrenderParticles(); // clear `canvas` and draw all particlesiconAnimationFrame = requestAnimationFrame(loop); // loop
}

Now let’s see how we have defined all the functions that we call inside the loop. As always, pay attention to the comments:

现在,让我们看看如何定义在循环中调用的所有函数。 与往常一样,请注意以下注释:

// Add new particles for the upload icon
function addIconParticles() {iconRect = uploadIcon.getBoundingClientRect(); // get icon dimensionsvar i = iconParticlesCount; // how many particles we should add?while (i--) {// Add a new particlecreateParticle({x: iconRect.left + iconRect.width / 2 + rand(iconRect.width - 10), // position the particle along the icon width in the `x` axisy: iconRect.top + iconRect.height / 2, // position the particle centered in the `y` axisvx: 0, // the particle will not be moved in the `x` axisvy: Math.random() * 2 * iconParticlesCount // value to move the particle in the `y` axis, greater is faster});}
}// Update the particles, removing the dead ones
function updateParticles() {for (var i = 0; i < particles.length; i++) {if (particles[i].life > particles[i].death) {particles.splice(i, 1);} else {particles[i].x += particles[i].vx;particles[i].y += particles[i].vy;particles[i].life++;}}
}// Clear the `canvas` and redraw every particle (rect)
function renderParticles() {ctx.clearRect(0, 0, canvasWidth, canvasHeight);for (var i = 0; i < particles.length; i++) {ctx.fillStyle = 'rgba(255, 255, 255, ' + (1 - particles[i].life / particles[i].death) + ')';ctx.fillRect(particles[i].x, particles[i].y, particles[i].size, particles[i].size);}
}

And we have our particle system ready, where we can add new particles defining the options we want, and the loop will be responsible for performing the animation.

我们已经准备好粒子系统,可以在其中添加新的粒子来定义所需的选项,然后循环将负责执行动画。

为上传图标添加动画 (Adding animations for the upload icon)

Now let’s see how we prepare the upload icon to be animated:

现在,让我们看看我们如何准备要上载动画的上载图标:

// Add 100 particles for the icon (without render), so the animation will not look empty at first
function initIconParticles() {var iconParticlesInitialLoop = 100;while (iconParticlesInitialLoop--) {addIconParticles();updateParticles();}
}
initIconParticles();// Alternating animation for the icon to translate in the `y` axis
function initIconAnimation() {iconAnimation = anime({targets: uploadIcon,translateY: -10,duration: 800,easing: 'easeInOutQuad',direction: 'alternate',loop: true,autoplay: false // don't execute the animation yet, only on `drag` events (see later)});
}
initIconAnimation();

With the previous code, we only need a couple of other functions to pause or resume the animation of the upload icon, as appropriate:

使用前面的代码,我们仅需要几个其他函数即可根据需要暂停或恢复上传图标的动画:

// Play the icon animation (`translateY` and particles)
function playIconAnimation() {if (!playingIconAnimation) {playingIconAnimation = true;iconAnimation.play();iconAnimationFrame = requestAnimationFrame(loop);}
}// Pause the icon animation (`translateY` and particles)
function pauseIconAnimation() {if (playingIconAnimation) {playingIconAnimation = false;iconAnimation.pause();cancelAnimationFrame(iconAnimationFrame);}
}

步骤4 —添加拖放功能 (Step 4 — Adding the Drag and Drop Functionality)

Then we can start adding the drag and drop functionality to upload the files. Let’s start by preventing unwanted behaviors for each related event:

然后我们就可以开始添加dragdrop功能,上传的文件。 让我们从防止每个相关事件的不良行为开始:

// Preventing the unwanted behaviours
['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function (event) {document.addEventListener(event, function (e) {e.preventDefault();e.stopPropagation();});
});

Now we will handle the events of type drag, where we will activate the form so that it is shown, and we will play the animations for the upload icon:

现在,我们将处理类型为drag的事件,在该事件中我们将激活form以使其显示,然后将播放上载图标的动画:

// Show the upload component on `dragover` and `dragenter` events
['dragover', 'dragenter'].forEach(function (event) {document.addEventListener(event, function () {if (!animatingUpload) {uploadForm.classList.add('upload--active');playIconAnimation();}});
});

In case the user leaves the drop zone, we simply hide the form again and pause the animations for the upload icon:

如果用户离开drop区,我们只需再次隐藏form并暂停上载图标的动画即可:

// Hide the upload component on `dragleave` and `dragend` events
['dragleave', 'dragend'].forEach(function (event) {document.addEventListener(event, function () {if (!animatingUpload) {uploadForm.classList.remove('upload--active');pauseIconAnimation();}});
});

And finally the most important event that we must handle is the drop event, because it will be where we will obtain the files that the user has dropped, we will execute the corresponding animations, and if this were a fully functional component we would upload the files to the server through AJAX.

最后,我们必须处理的最重要的事件是drop事件,因为它将是获取用户放置的文件的位置,我们将执行相应的动画,如果这是功能齐全的组件,我们将上载文件通过AJAX发送到服务器。

// Handle the `drop` event
document.addEventListener('drop', function (e) {if (!animatingUpload) { // If no animation in progressdroppedFiles = e.dataTransfer.files; // the files that were droppedfilesCount = droppedFiles.length > 3 ? 3 : droppedFiles.length; // the number of files (1-3) to perform the animationsif (filesCount) {animatingUpload = true;// Add particles for every file loaded (max 3), also staggered (increasing delay)var i = filesCount;while (i--) {addParticlesOnDrop(e.pageX + (i ? rand(100) : 0), e.pageY + (i ? rand(100) : 0), 200 * i);}// Hide the upload component after the animationsetTimeout(function () {uploadForm.classList.remove('upload--active');}, 1500 + filesCount * 150);// Here is the right place to call something like:// triggerFormSubmit();// A function to actually upload the files to the server} else { // If no files where dropped, just hide the upload componentuploadForm.classList.remove('upload--active');pauseIconAnimation();}}
});

In the previous code snippet we saw that the function addParticlesOnDrop is called, which is in charge of executing the particle animation from where the files were dropped. Let’s see how we can implement this function:

在前面的代码片段中,我们看到调用了addParticlesOnDrop函数,该函数负责执行放置文件的粒子动画。 让我们看看如何实现此功能:

// Create a new particles on `drop` event
function addParticlesOnDrop(x, y, delay) {// Add a few particles when the `drop` event is triggeredvar i = delay ? 0 : 20; // Only add extra particles for the first item dropped (no `delay`)while (i--) {createParticle({x: x + rand(30),y: y + rand(30),vx: rand(2),vy: rand(2),death: 60});}// Now add particles along the way where the user `drop` the files to the icon position// Learn more about this kind of animation in the `anime.js` documentationanime({targets: {x: x, y: y},x: iconRect.left + iconRect.width / 2,y: iconRect.top + iconRect.height / 2,duration: 500,delay: delay || 0,easing: 'easeInQuad',run: function (anim) {var target = anim.animatables[0].target;var i = 10;while (i--) {createParticle({x: target.x + rand(30),y: target.y + rand(30),vx: rand(2),vy: rand(2),death: 60});}},complete: uploadIconAnimation // call the second part of the animation});
}

Finally, when the particles reach the position of the icon, we must move the icon upwards, giving the impression that the files are being uploaded:

最后,当粒子到达图标的位置时,我们必须向上移动图标,给人的印象是正在上传文件:

// Translate and scale the upload icon
function uploadIconAnimation() {iconParticlesCount += 2; // add more particles per frame, to get a speed up feelinganime.remove(uploadIcon); // stop current animations// Animate the icon using `translateY` and `scale`iconAnimation = anime({targets: uploadIcon,translateY: {value: -canvasHeight / 2 - iconRect.height,duration: 1000,easing: 'easeInBack'},scale: {value: '+=0.1',duration: 2000,elasticity: 800},complete: function () {// reset the icon and all animation variables to its initial statesetTimeout(resetAll, 0);}});
}

To finish, we must implement the resetAll function, which resets the icon and all the variables to its initial state. We must also update the canvas size and reset the component on resize event. But in order not to make this tutorial any longer, we have not included these and other minor details, although you can check the complete code in the Github repository.

最后,我们必须实现resetAll函数,该函数将图标和所有变量重置为其初始状态。 我们还必须更新canvas大小,并在发生resize事件时重置组件。 但是为了不使本教程不再做,尽管您可以在Github存储库中检查完整的代码,但我们没有包括这些和其他次要细节。

结论 (Conclusion)

And finally our component is complete! Let’s take a look:

最后,我们的组件完成了! 让我们来看看:

You can check the live demo, play with the code on Codepen, or get the full code on Github.

您可以查看现场演示 , 在Codepen上使用代码 ,或在Github上获取完整代码 。

Throughout the tutorial we saw how to create a simple particle system, as well as handle drag and drop events to implement an eye-catching file upload component.

在本教程中,我们看到了如何创建一个简单的粒子系统,以及手柄dragdrop事件来实现一个醒目的文件上传组件。

Remember that this component is not ready to be used in production. In case you want to complete the implementation to make it fully functional, I recommend checking this excellent tutorial in CSS Tricks.

请记住,该组件尚未准备好在生产中使用。 如果您想完成实现以使其完全发挥作用,我建议您在CSS Tricks中检查该出色的教程 。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-develope-a-creative-upload-interaction-with-javascript-and-canvas

canvas使用滑杆交互

canvas使用滑杆交互_如何使用JavaScript和Canvas开发交互式文件上传器相关推荐

  1. 如何使用HTML5,JavaScript和Bootstrap构建自定义文件上传器

    by Prashant Yadav 通过Prashant Yadav 如何使用HTML5,JavaScript和Bootstrap构建自定义文件上传器 (How to build a custom f ...

  2. [JavaScript]多个表单中文件上传网址的获得的代码示例

    假设一个网页里有多个表单,其中一个表单里有文件上传, <form action='http://xxx.com/data' method='post'><input type=&qu ...

  3. 用JavaScript和HTML5创建文件上传器

    说明: 本文阐述了如何用HTML5和JavaScript上传文件.HTML5提供输入类型"文件"允许我们与本地文件互动,文件输入类型对于从用户那提走一些示例并进行一些操作来说可能非 ...

  4. Hadoop入门(10)_通过java代码实现从本地的文件上传到Hadoop的文件系统

    2019独角兽企业重金招聘Python工程师标准>>> 第一步:首先搭建java的编译环境.创建一个Java Project工程,名为upload. 第二步:选中所需的Jar包.   ...

  5. asp 检查黑名单_十九、绕过黑名单检查实现文件上传2

    1.   文件上传漏洞简介 通常web站点会有用户注册功能,而当用户登录之后大多数情况下会存在类似头像上传.附件上传之类的功能,这些功能点往往存在上传验证方式不严格的安全缺陷,导致攻击者通过各种手段绕 ...

  6. nfine框架 上传文件_网站服务器Nginx运行环境,后台文件上传超出Nginx的最大值...

    解决方法: 1.修改Nginx的配置文件(一般是:nginx/nginx.conf),在 http{} 段中增大nginx上传文件大小限制 #设置允许发布内容为8M client_max_body_s ...

  7. vc++ 6.0 创建程序快捷方式的一个例子源码_漏洞复现:phpcms v9.6.0任意文件上传漏洞(CVE201814399)...

    文章说明 漏洞复现是为了学习漏洞利用所写,漏洞都是互联网上以流传已久的各种漏洞的利用及原理,用来增强自己见识,培养自己动手能力,有兴趣的朋友可自行搭建环境练习.源码下载连接在文章最后. 漏洞说明 PH ...

  8. html 上传文件_【实战篇】记一次文件上传漏洞绕过

    点击上方"公众号" 可以订阅哦! Hello,各位小伙伴大家好~ 最近有点高产似母猪~ 那今天就少写点,简单记录一个文件上传漏洞的绕过吧~(机智如我..) 之前也介绍过一期文件上传 ...

  9. layui实现文件压缩上传_基于SSM框架、Layui的多文件上传、包括图片,压缩包,音频等文件(与数据库挂钩) - 爱秧博客...

    写在前面:当初为了实现一个多文件上传可是费了一番功夫,经过我日日夜夜的百度咨询,写了好几种方法,最终还是没能解决问题.我可以很负责任的告诉你,你去百度上不管你形容有多好,只要是涉及多文件,就会查到Mu ...

最新文章

  1. numpy 数组 独热编码 one hot
  2. VDI序曲十七 RDVH虚拟主机中开启RemoteFX的硬件配置要求
  3. 关注点分离之RestTemplate的错误处理
  4. 【luogu P3378 堆】 模板
  5. Android宫格自动换行,九宫格视图的布局及展示(相册选择)
  6. ps -ef和ps aux
  7. php文件锁 阻塞区别,php文件锁阻塞模式和非阻塞模式
  8. 企业以太坊联盟发布了愿景文件
  9. Leetcode: Excel Sheet Column Title
  10. 程序员的求生欲有所强?用Python花式哄女友
  11. 怎么提高Mysql执行sql导入的速度
  12. linux跟踪线程,linux跟踪线程的方法:LWP和strace命令
  13. vue el-date-picker 直接赋值不生效、数据绑定无效
  14. 计算机应用基础 教学工作总结,四年级下期计算机教学工作总结(共3篇)
  15. SCAR:Scalable Consensus Algorithm一种可伸缩共识算法
  16. java8 Stream分组求和reducing分组求最大值
  17. python表示差值_Python-dataframe的对应列求差值
  18. [面试题]1000瓶水中有1瓶是有毒的,问需要多少只老鼠才能试出那瓶有毒?
  19. The Sandbox沙盒遊戲設計大賽將於12月24日開始
  20. (转)如何获得两个日期相减的天数?

热门文章

  1. 【PCIe】PCIe Scaled Flow Control 简介
  2. 群号:但也听说seo外链专员绝不会容忍这
  3. 洛谷 P2615 [NOIP2015 D1T1] 神奇的幻方
  4. Maven上传jar包到本地仓库
  5. Hadoop学习笔记1,如何搭建可以正常使用的CentOS7系统虚拟机节点
  6. 【极客时间】《Java并发编程实战》学习笔记
  7. Android实现方程编辑器
  8. 【调剂】南京邮电大学2022年硕士研究生招生拟接收调剂专业预告
  9. 养肥了再宰,Nginx之父被警方抓走!
  10. 树莓派通过物联网照顾宠物龟