zoukankan      html  css  js  c++  java
  • 适配移动端的在图片上生成水波纹demo

     
    <!DOCTYPE html>
    <html lang="zh">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML5 canvas水波纹动画特效</title>
     
    <style type="text/css">
    body{
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-size: 100%;
    vertical-align: baseline; /*background: transparent;*/
    box-sizing: border-box;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0); //为了防止ios系统出现点击闪烁现象
    }
    body {
    overflow: hidden;
    }
     
    #holder{
    width: 100%;
    height: 6.3rem;
    position: absolute;
    /* cursor: pointer; */
    text-align: center;
    }
    </style>
    </head>
    <body id="body">
    <div id="holder"></div>
     
    <script>
    window.onload = ()=>{
    let outer = document.getElementById('holder').getBoundingClientRect();
    //获取canvas,外部容器的宽高,来进行设置canvas的宽高
    console.log(outer)
    function WaterRipple(element, settings) {
    // 默认设置
    var defaults = {
    image: "",
    dropRadius: 3, // 波源半径大小
     '',
    height: '',
    delay: 1,
    attenuation: 3,
    maxAmplitude: 1024,
    // sourceAmplitude: 512, // 震源振幅
    sourceAmplitude: 256, // 震源振幅
    auto: false
    };
    // 合并设置
    for (var item in defaults) {
    if (!settings.hasOwnProperty(item)) {
    settings[item] = defaults[item]
    }
    }
     
    // 检测背景图
    if (!settings.image.length) {
    return false;
    }
     
    var width = settings.width,
    height = settings.height,
    dropRadius = settings.dropRadius,
    delay = settings.delay * 1000,
    attenuation = settings.attenuation, // 衰减级别
    maxAmplitude = settings.maxAmplitude, // 最大振幅
    sourceAmplitude = settings.sourceAmplitude,
    half_width = width >> 1,
    half_height = height >> 1,
    amplitude_size = width * (height + 2) * 2,
    old_index = width,
    new_index = width * (height + 3),
    map_index, // 振幅数组索引
    texture, // 原始图像像素信息
    ripple, // 参数波纹的图像像素信息
    image, // Image对象
    autoRepeat, // 自动产生波源的重复事件
    ripple_map = [],
    last_map = [];
     
    var canvas = document.createElement('canvas');
    canvas.style.width = outer.width+'px';
    canvas.style.height = outer.height+'px';
    canvas.width = width;
    canvas.height = height;
    element.appendChild(canvas);
     
    var ctx = canvas.getContext('2d');
    ctx.fillStyle = settings.bgColor;
    ctx.fillRect(0, 0, width, height);
     
    window.requestAnimationFrame = (function(){
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function (callback) {
    window.setTimeout(callback, 1000 / 60);
    };
    })();
     
    // 加载图片,注意图片不要跨域
    function loadImage() {
    image = new Image();
    // image.src = settings.image;
    // image.src = './wallet_top.png';
    image.src = './long.jpg';
    // image.src = './top@3x.png';
    // image.src = './girl.png';
    image.crossOrigin = 'anonymous';
    image.onload = function() {
    console.log(image.style)
    init();
    }
    }
     
    // 保存图像的所有像素信息
    //将图片绘制在图片尺寸的宽高上
    function saveImageData() {
    // 在canvas中绘制图形
    console.log('width',width)
    ctx.drawImage(image, 0, 0,width,height);
    // ctx.drawImage(image, 0, 0,375,315);
    // 图像的ImageData对象
    texture = ctx.getImageData(0, 0, width, height);
    ripple = ctx.getImageData(0, 0, width, height);
    }
     
    function init() {
    saveImageData();
    // 波幅数组初始化为0
    for (var i = 0; i < amplitude_size; i++) {
    ripple_map[i] = last_map[i] = 0;
    }
     
    animate();
    // 如果设置了自动产生波源,则随机参数波源
    console.log('width',width)
    if (settings.auto) {
    autoRepeat = setInterval(function() {
    disturb(Math.random() * width, Math.random() * height);
    }, delay);
    disturb(Math.random() * width, Math.random() * height);
    }
     
    }
     
    // 动画主循环
    function animate() {
    requestAnimationFrame(animate);
    renderRipple();
    }
     
    // 在指定地点产生波源
    function disturb(circleX, circleY) {
    // 将值向下取整
    circleX <<= 0;
    circleY <<= 0;
    var maxDistanceX = circleX + dropRadius,
    maxDistanceY = circleY + dropRadius;
    for (var y = circleY - dropRadius; y < maxDistanceY; y++) {
    for (var x = circleX - dropRadius; x < maxDistanceX; x++) {
    ripple_map[old_index + y * width + x] += sourceAmplitude;
    }
    }
    // console.log('ripple_map',ripple_map)
    }
     
    // 渲染下一帧
    function renderRipple() {
    var i = old_index,
    deviation_x, // x水平方向偏移
    deviation_y, // y竖直方向偏移
    pixel_deviation, // 偏移后的ImageData对象像素索引
    pixel_source; // 原始ImageData对象像素索引
     
    // 交互索引 old_index, new_index
    old_index = new_index;
    new_index = i;
     
    // 设置像素索引和振幅索引
    i = 0;
    map_index = old_index;
    // 使用局部变量优化全局作用域查询
    var _map_index = map_index,
    _width = width,
    _height = height,
    _half_width = half_width,
    _half_height = half_height,
    _ripple_map = ripple_map,
    _last_map = last_map,
    _ripple_data = ripple.data, // 引用修改
    _texture_data = texture.data, // 引用修改
    _new_index = new_index,
    _attenuation = attenuation,
    _maxAmplitude = maxAmplitude;
     
     
    // 渲染所有像素点
    for (var y = 0; y < _height; y++) {
    for (var x = 0; x < _width; x++) {
    var x_boundary = 0, judge = _map_index % _width;
    if (judge == 0) {
    x_boundary = 1; // 左边边界
    }else if (judge == _width - 1) {
    x_boundary = 2; // 右边边界
    }
    var top = _ripple_map[_map_index - _width],// 上边的相邻点
    bottom = _ripple_map[_map_index + _width],// 下边的相邻点
    left = x_boundary != 1 ? _ripple_map[_map_index - 1] : 0,// 左边的相邻点
    right = x_boundary != 2 ? _ripple_map[_map_index + 1] : 0;// 右边的相邻点
    // 计算当前像素点下一时刻的振幅
    var amplitude = (top + bottom + left + right) >> 1;
    amplitude -= _ripple_map[_new_index + i];
    amplitude -= amplitude >> _attenuation; // 计算衰减
     
    // 更新振幅数组
    _ripple_map[_new_index + i] = amplitude;
     
    amplitude = _maxAmplitude - amplitude;
    var old_amplitude = _last_map[i];
    _last_map[i] = amplitude;
     
    if (old_amplitude != amplitude) {
    deviation_x = (((x - _half_width) * amplitude / _maxAmplitude) << 0) + _half_width;
    deviation_y = (((y - _half_height) * amplitude / _maxAmplitude) << 0) + _half_height;
     
    // 检查边界
    if (deviation_x > _width) {
    deviation_x = _width - 1;
    }
    if (deviation_x < 0) {
    deviation_x = 0;
    }
    if (deviation_y > _height) {
    deviation_y = _height - 1;
    }
    if (deviation_y < 0) {
    deviation_y = 0;
    }
     
    pixel_source = i * 4;
    // console.error(width)
    pixel_deviation = (deviation_x + (deviation_y * width)) * 4;
     
    // 移动像素的RGBA信息
    _ripple_data[pixel_source] = _texture_data[pixel_deviation];
    _ripple_data[pixel_source + 1] = _texture_data[pixel_deviation + 1];
    _ripple_data[pixel_source + 2] = _texture_data[pixel_deviation + 2];
    // ripple.data[pixel_source + 3] = texture.data[pixel_deviation + 3];
    }
    ++i;
    ++_map_index;
    }
    }
     
    map_index = _map_index;
    ctx.putImageData(ripple, 0, 0);
    }
     
    function calculAmplitude(index, old_amplitude) {
    var x_boundary = 0, judge = map_index % width;
    if (judge == 0) {
    x_boundary = 1; // 左边边界
    }else if (judge == width - 1) {
    x_boundary = 2; // 右边边界
    }
    var top = ripple_map[index - width],// 上边的相邻点
    bottom = ripple_map[index + width],// 下边的相邻点
    left = x_boundary != 1 ? ripple_map[index - 1] : 0,// 左边的相邻点
    right = x_boundary != 2 ? ripple_map[index + 1] : 0;// 右边的相邻点
    // 计算当前像素点下一时刻的振幅
    var amplitude = top + bottom + left + right;
    amplitude >>= 1;
    amplitude -= old_amplitude;
    amplitude -= amplitude >> attenuation; // 计算衰减
    return amplitude;
    }
    this.disturb = function(a, b) {
    console.log('ab',a)
    console.log('ab',b)
    disturb(a, b);
    // disturb(573, 759);
    };
    loadImage();
    return this;
    }
     
    function init() {
     
     
    //Settings - params for WaterRippleEffect
    var settings = {
    //注意图片不要跨域
    image: './girl.png',//image path
    // image: './wallettop.png',//image path
    dropRadius: 3,//radius of the ripple
    //这里设置canvas画布的宽高,可以使用图片的宽高来设置,这样会保证图片清晰程度。
     750,//width
    height: 630,//height
    //  outer.width,//width
    // height: outer.height,//height
    delay: 1,//if auto param === true. 1 === 1 second delay for animation
    auto: true,//if auto param === true, animation starts on it´s own
    attenuation:5,
    };
     
    //init
    var waterRippleEffect = new WaterRipple( document.getElementById( 'holder' ), settings );
    // document.getElementById( 'holder' ).style.cursor = 'pointer';
     
    //on click
    document.getElementById( 'holder' ).addEventListener( 'click', function( e ) {
    var mouseX = e.layerX;
    var mouseY = e.layerY;
     
    console.log('e',e)
    let canvas_x = (mouseX/outer.width)*settings.width;
    let canvas_y = (mouseY/outer.height)*settings.height;
    // waterRippleEffect.disturb( mouseX, mouseY );
    waterRippleEffect.disturb( canvas_x, canvas_y );
     
    } );
     
     
    //on mousemove
    // document.getElementById( 'holder' ).addEventListener( 'mousemove', function( e ) {
    // var mouseX = e.layerX;
    // var mouseY = e.layerY;
    // // waterRippleEffect.disturb( mouseX, mouseY );
     
    // } );
     
    document.onkeydown = function(e) {
    var event = e || window.event || arguments.callee.caller.arguments[0];
    if(event && event.keyCode==13){ // enter 键
    waterRippleEffect.disturb( 200, 200);
     
    }
    }
    }
    init();
     
    }
     
    </script>
    </body>
     
    主要做了以下几个部分:
    1、动态设置canvas的宽高,使其自适应移动端的尺寸
     
    2、动态设置波纹出现的位置,
    document.getElementById( 'holder' ).addEventListener( 'click', function( e ) {
    var mouseX = e.layerX;
    var mouseY = e.layerY;
     
    console.log('e',e)
    //鼠标或者手指在画布css尺寸上的位置来乘以canvas画布的位置来精确生成波纹。
    let canvas_x = (mouseX/outer.width)*settings.width;
    let canvas_y = (mouseY/outer.height)*settings.height;
    // waterRippleEffect.disturb( mouseX, mouseY );
    waterRippleEffect.disturb( canvas_x, canvas_y );
     
    } );

  • 相关阅读:
    在IIS中设置默认网页
    vim 查找匹配字符串次数
    resource about NLP
    Mongodb基本知识和常用语法
    fudanNLP keyword Extraction
    nltk support chinese by sinica
    Gmail小技巧:只显示未读邮件
    java get line number and file name
    java classpath import package 机制
    linux 调用 fudanNLP
  • 原文地址:https://www.cnblogs.com/qdcnbj/p/10418665.html
Copyright © 2011-2022 走看看