zoukankan      html  css  js  c++  java
  • 使用canvas实现画中画效果的H5

    最近看到一个挺有趣的H5,主要效果就是通过不断的放缩来展示画中画,网上找了一下并没有这方面的实现代码,故决定原创一下,并分享出来

    主要的思路就是通过canvas不断的写入图片,考虑到每一层的图片的位置和大小不一样,于是通过最外层的图片来尺寸和位置来控制里面的图片,然后通过循环写入canvas的方式实现最终的效果。

    需要注意的是使用canvas写入图片需要预加载图片,通过回调函数来写入,同时,由于图片加载需要一定的时候,所以一般的H5会有一个加载的过程,我也加上了一个回调函数来处理加载图片以后其他的操作,比如隐藏加载页面等操作。

    此项目已经放到码云上了,传送门,第一次分享项目,共勉之。

    主要代码如下:
    let $ = require('jquery');
    let tools = require('./utils.js');
    $.fn.longPress = function() {
        let timeout = undefined;
        let start;
        let beginHandel, endHandel;
        let length = arguments.length;
        beginHandel = arguments[0];
        if (length = 2) {
            endHandel = arguments[1];
        }
        $(this).on('touchstart', function(e) {
            e.preventDefault();
            timeout = setTimeout(beginHandel, 500);
        });
        $(this).on('touchend', function(e) {
            e.preventDefault();
            tools.execCB(endHandel);
            clearTimeout(timeout);
        });
    };
    let TWEEN = require('@tweenjs/tween.js');
    (function(global, factory) {
        if (typeof define === 'function' && define.amd) {
            define(function() {
                return factory(global, global.document);
            })
        } else if (typeof module !== 'undefined' && module.exports) {
            module.exports = factory(global, global.document);
        } else {
            global.Pip = factory(global, global.document);
        }
    }(typeof window !== 'undefined' ? window : this, function(window, document) {
    
        'use strict'
        //常量
        const CW = $(window).width();
        const CH = $(window).height();
        let container = $('#pip');
    
    
        let Pip = function(options) {
            let _this = this;
            this.defaultOps = {
                model: 'bts',
                duration: 1000,
            }
            if (typeof options == 'object') {
                Object.keys(options).map(function(key) {
                    _this.defaultOps[key] = options[key];
                })
            }
            //创建canvas
            let canvas = document.createElement('canvas');
            let length = _this.defaultOps.content.length;
            canvas.width = CW;
            canvas.height = CH;
            _this.defaultOps.context = canvas.getContext('2d');
            container.append(canvas);
    
        };
        Pip.prototype.start = function(cb) {
            let opts = this.defaultOps;
            let ctx = opts.context;
            let content = opts.content;
            let length = content.length;
            let model = opts.model;
            let beginStatus = {};
            let endStatus = {};
            let i = 0;
    
            if (ctx) {
                // 加载所有的图片
                loadimages(content, function(images) {
                    //去掉加载提示页面
                    tools.execCB(cb)
    
                    // 总时间
                    let duration = opts.duration;
                    let timestamp1 = 0
                    let timestamp2 = 0
    
                    // 补间动画
                    let tween = null
                    // 初始化状态
                    if (model == 'stb') {
                        i = length - 2;
                        let width = CW;
                        let height = CH;
                        let left = 0;
                        let top = 0;
    
                        for (let k = i + 1; k >= 0; k--) {
                            if (k !== i + 1) {
                                left = left + width * content[length - 1 - k].left;
                                top = top + height * content[length - 1 - k].top;
                                width = width * content[length - 1 - k].width;
                                height = height * content[length - 1 - k].height;
                            }
                            let image = images[length - 1 - k];
                            ctx.drawImage(image, left, top, width, height);
                        }
                        //定义开始和结束状态
                        endStatus = {
                             CW / content[length - 1 - i].width,
                            height: CH / content[length - 1 - i].height,
                            left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                            top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                        }
                        beginStatus = {
                             CW,
                            height: CH,
                            left: 0,
                            top: 0
                        }
                    } else {
                        ctx.drawImage(images[length - 1 - i], 0, 0, container.width(), container.height());
                        //定义开始和结束状态
                        beginStatus = {
                             CW / content[length - 1 - i].width,
                            height: CH / content[length - 1 - i].height,
                            left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                            top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                        }
                        endStatus = {
                             CW,
                            height: CH,
                            left: 0,
                            top: 0
                        }
    
                    }
    
    
    
    
    
    
                    function go() {
                        tween = new TWEEN.Tween(beginStatus)
                            .to(endStatus, duration)
                            .onUpdate(function() {
                                let _this = this;
                                ctx.clearRect(0, 0, container.width(), container.height());
                                let width = _this.width;
                                let height = _this.height;
                                let left = _this.left;
                                let top = _this.top;
    
                                for (let k = i + 1; k >= 0; k--) {
                                    if (k !== i + 1) {
                                        left = left + width * content[length - 1 - k].left;
                                        top = top + height * content[length - 1 - k].top;
                                        width = width * content[length - 1 - k].width;
                                        height = height * content[length - 1 - k].height;
                                    }
                                    let image = images[length - 1 - k];
                                    ctx.drawImage(image, left, top, width, height)
                                }
                            })
                            .onComplete(function() {
                                if (model == 'bts') {
                                    i++;
                                } else {
                                    i--;
                                }
                                if (i > length - 2 || i < 0) {
                                    if (model == 'bts') {
                                        i--;
                                        model = 'stb';
                                        endStatus = {
                                             CW / content[length - 1 - i].width,
                                            height: CH / content[length - 1 - i].height,
                                            left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                                            top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                                        };
                                        beginStatus = {
                                             CW,
                                            height: CH,
                                            left: 0,
                                            top: 0
                                        };
                                    } else {
                                        i++;
                                        model = 'bts';
                                        beginStatus = {
                                             CW / content[length - 1 - i].width,
                                            height: CH / content[length - 1 - i].height,
                                            left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                                            top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                                        };
                                        endStatus = {
                                             CW,
                                            height: CH,
                                            left: 0,
                                            top: 0
                                        };
                                    }
                                    return;
                                }
                                //定义开始和结束状态
                                if (model == 'bts') {
                                    beginStatus = {
                                         CW / content[length - 1 - i].width,
                                        height: CH / content[length - 1 - i].height,
                                        left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                                        top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                                    };
                                    endStatus = {
                                         CW,
                                        height: CH,
                                        left: 0,
                                        top: 0
                                    };
                                } else {
                                    endStatus = {
                                         CW / content[length - 1 - i].width,
                                        height: CH / content[length - 1 - i].height,
                                        left: -CW / content[length - 1 - i].width * content[length - 1 - i].left,
                                        top: -CH / content[length - 1 - i].height * content[length - 1 - i].top
                                    };
                                    beginStatus = {
                                         CW,
                                        height: CH,
                                        left: 0,
                                        top: 0
                                    };
    
                                }
    
                                duration = opts.duration;
                                go();
                            })
                            .onStop(function() {
                                timestamp2 = new Date().getTime()
                                duration = duration - (timestamp2 - timestamp1)
                                if (duration < 0) {
                                    duration = 0
                                }
                            })
                            .onStart(function() {
                                timestamp1 = new Date().getTime()
                            })
                            .start()
    
                        requestAnimationFrame(animate)
    
                        function animate() {
                            TWEEN.update()
                            requestAnimationFrame(animate)
                        }
                    }
    
                    container.longPress(function() {
                        go()
                    }, function() {
                        if (tween) {
                            tween.stop()
                        }
                    })
                })
            } else {
                console.log("context is not defined")
                return
            }
    
            function loadimages(content, cb) {
                let images = [];
                let num = 0;
                let length = content.length;
                for (let c in content) {
                    images[c] = new Image();
                    images[c].onload = function() {
                        if (num === length) {
                            num = 0;
                            tools.execCB(cb, images)
                        }
                    }
                    images[c].src = content[length - 1 - num].src;
                    num++;
                }
            }
        };
        return Pip
    }));
    
    用法如下:
    var pip = new Pip({
        content: [{
            src: require('../src/images/2.jpg'),
            top: 0,
            left: 0,
             1,
            height: 1
        }, {
            src: require('../src/images/3.png'),
            top: .1,
            left: .05,
             .08,
            height: .08
        }, {
            src: require('../src/images/4.jpg'),
            top: .4,
            left: .6,
             .08,
            height: .08
        }, {
            src: require('../src/images/5.jpg'),
            top: .4,
            left: .6,
             .08,
            height: .08
        }, {
            src: require('../src/images/6.jpg'),
            top: .9,
            left: .4,
             .08,
            height: .08
        }, {
            src: require('../src/images/7.jpg'),
            top: .1,
            left: .05,
             .08,
            height: .08
        }, {
            src: require('../src/images/8.jpg'),
            top: .4,
            left: .6,
             .08,
            height: .08
        }, {
            src: require('../src/images/9.jpg'),
            top: .1,
            left: .05,
             .08,
            height: .08
        }, {
            src: require('../src/images/4.jpg'),
            top: .4,
            left: .6,
             .08,
            height: .08
        }, {
            src: require('../src/images/5.jpg'),
            top: .4,
            left: .6,
             .08,
            height: .08
        }, {
            src: require('../src/images/6.jpg'),
            top: .9,
            left: .4,
             .08,
            height: .08
        }],
        model: 'stb',
    });
    pip.start(function() {
        //此处加载完图片以后隐藏遮罩
        $('.mask').hide();
    });
    
    ------学习贵在分享,贵在记录,贵在总结。
  • 相关阅读:
    jsp eclipse 创建jsp项目
    SQL Server 身份验证 登陆
    HUD 5086 Revenge of Segment Tree(递推)
    HDU 1700 Points on Cycle (几何 向量旋转)
    RocketMQ broker jvm 监控
    RocketMQ runbroker.sh 分析JVM启动参数
    问题:虚拟机老生代垃圾回收频繁出现
    空白行 ,空白
    eclipse find 两位数
    生成字母+数字6位字符串
  • 原文地址:https://www.cnblogs.com/kevin1220/p/7410961.html
Copyright © 2011-2022 走看看