资讯专栏INFORMATION COLUMN

SVG 立方体内嵌路径拼接

姘存按 / 2090人阅读

摘要:第一部分是正方体部分,第二部分是中的路径动画了,第三部分则是交互旋转。然后在立方体元素上添加鼠标点击事件事件,在回调函数中做处理内容。回调函数中先记录下来鼠标点击的位置。

1.前言

我使用了jquery编写交互的旋转,因为初学所以不太承受,还请见谅。样式我是写stylus编码,自动生成css。

2.正文

先放上一张效果图

我将其分成三部分。第一部分是正方体部分(SVG),第二部分是svg中的路径动画了(animateMotion + jQuery),第三部分则是交互旋转(jQuery)。

1.正方体

做一个正方体

我的思路是用六块svg正方形画板通过css属性旋转和平移来构成正方体。

html代码:

stylus代码

html
    margin 0
    padding 0
    height 100%
    width 100%
    body
        height 100%
        width 100%
        .page
            .state
                height 300px
                width 300px
                position absolute
                top 50%
                left 50%
                transform translate(-50%,-50%)//修正位置
                .container
                    transform-style preserve-3d
                    position relative
                    height 300px
                    width 300px
                    transform rotateX(0deg) rotateY(0deg)
                    svg
                        position absolute
                        height 300px
                        width 300px
                        stroke-width 5px
                        stroke brown
                        fill transparent //填充用透明
                        .rect
                            height 300px
                            width 300px
                    .top
                        transform rotateX(90deg) translateZ(150px)
                    .bottom 
                        transform rotateX(-90deg) translateZ(150px)
                    .left
                        transform rotateY(-90deg) translateZ(150px)
                    .right
                        transform rotateY(90deg) translateZ(150px)
                    .front
                        transform rotateY(0deg) translateZ(150px)
                    .behind
                        transform rotateY(180deg) translateZ(150px)

通常有两种方式来构建一个立方体
第一种:先平移再旋转。优点是不许太强的空间构造能力,写起来比较简单。缺点就是:代码数会多一些,需要在平移后设置旋转基点。替换一下样式就行。

.top 
    fill blue 
    transform-origin: bottom 
    transform translateY(-200px) rotateX(90deg)
.bottom 
    fill red 
    transform-origin:top 
    transform translateY(200px) rotateX(-90deg)
.left 
    fill green 
    transform-origin: right 
    transform translateX(-200px) rotateY(-90deg)
.right 
    fill black 
    transform-origin: left 
    transform translateX(200px) rotateY(90deg)
.front 
    fill grey
    transform translateZ()
.behind 
    fill pink 
    transform translateZ(-200px)

第二种:先旋转再平移。这个的特点就是与上面的相反了。(我使用的是这种)
两种生成立方体的原理看下图
第一种

第二种

以上就是两种构建立方体的方法大致原理了

2.路径动画

路径动画我是通过在相邻两个面上一个动画结束的位置和下一个动画起始位置重合,
下一个动画起始的延时设置为之前所有动画的动画时间,做到视觉认为路线是连接起来的。
先上代码:

路径动画是有animateMotion元素做的所以可以不是直线,只是为了方便设计,我吧path路径设计成了直线
有兴趣的可以自己设计一下。
路径是我用 Method Draw 画的 editor.method.ac/

接下来就是重点的路径控制了

$(document).ready(function () {
    const animate = document.getElementsByTagName("animateMotion");
    // 0 frontY 1 frontX 2 behindY 3 behindX 4 leftX 5 rightX 6 topY 7 bottomY
    var frontY = animate[0], frontX = animate[1],
        behindY = animate[2], behindX = animate[3],
        leftX = animate[4], rightX = animate[5],
        topY = animate[6], bottomY = animate[7];
    // Y面球体运动
    (() => {
        //先执行一次
        frontY.beginElement();
        setTimeout(() => {
            bottomY.beginElement();
        }, 3000);
        setTimeout(() => {
            behindY.beginElement();
        }, 6000);
        setTimeout(() => {
            topY.beginElement();
        }, 9000);
        // 循环执行动画
        var time = setInterval(() => {
            frontY.beginElement();
            setTimeout(() => {
                bottomY.beginElement();
            }, 3000);
            setTimeout(() => {
                behindY.beginElement();
            }, 6000);
            setTimeout(() => {
                topY.beginElement();
            }, 9000);
        }, 12000);
    })();
    // X面球体运动
    (() => {
        //先执行一次
        frontX.beginElement();
        setTimeout(() => {
            leftX.beginElement();
        }, 3000);
        setTimeout(() => {
            behindX.beginElement();
        }, 6000);
        setTimeout(() => {
            rightX.beginElement();
        }, 9000);
        // 循环执行动画
        var time = setInterval(() => {
            frontX.beginElement();
            setTimeout(() => {
                leftX.beginElement();
            }, 3000);
            setTimeout(() => {
                behindX.beginElement();
            }, 6000);
            setTimeout(() => {
                rightX.beginElement();
            }, 9000);
        }, 12000);
    })();
})

我设置的是让animateMotion元素的起始值begininfinite,在页面加载完毕后动画不会自动执行。
我用jQuery来控制动画的执行顺序。

首先获取每个动画元素const animate = document.getElementsByTagName("animateMotion");,之后将每个动画元素都标记好。
接着使用计时器setIntervalsetTimeout计时器来控制动画。首先使用setInterval来控制动画循环执行。接着在setInterval中用setTimeout设置动画执行的顺序,每个setTimeout计时器的延迟都为之前所有动画时间之和。模块化的最好先设置一个动画对象数组,然后将动画顺序加入数组。

最后附加两个API

// svg指当前svg DOM元素
// 暂停
svg.pauseAnimations();
// 重启动
svg.unpauseAnimations()

两个API可已暂停当前动画,关于详情请看张鑫旭大佬的文章鑫空间

3.旋转控制

旋转控制是我还没完善的地方,用户体验不是十分好,还望大佬们帮我指出错误。另一个旋转方案过一两天再添加上来。
代码:

var X = 0;//记录X轴旋转过的角度
var Y = 0;//记录Y轴旋转过的角度
// 旋转控制
$(".container").mousedown(function (event) {
    var mousedownX = event.clientX;
    var mousedownY = event.clientY;
    $("body").mousemove(function (event) {
        var mousemoveX = event.clientX;
        var mousemoveY = event.clientY;
        var scaleY = ((mousemoveX - mousedownX) / 200);
        var scaleX = ((mousemoveY - mousedownY) / 200);
        Y = ((Y + scaleY) % 360);
        X = ((X + scaleX) % 360);
        $(".container").animate({}, function () {
            $(".container").css({ "transform": `rotateX(${X}deg) rotateY(${Y}deg)` });
        })
    })
})
$("body").mouseup(function () {
    $("body").unbind("mousemove");
    $("body").unbind("mousedown");
})

首先设置两个变量X,Y这是记录这个立方体真正旋转了多少角度。
然后在立方体.container元素上添加鼠标点击事件mousedown事件,在回调函数中做处理内容。回调函数中先记录下来鼠标点击的位置。
接着body上添加鼠标移动mousemove事件因为我们移动不能只在立方体上,移动的范围要扩大到页面上。接着在移动事件中的回调函数做旋转处理,首先记录下来移动后鼠标的位置,计算出鼠标移动的距离然后除以一个数var scaleY = ((mousemoveX - mousedownX) / 200);注意其中的200没有真正代表的意义,只是因为鼠标移动的距离数值相对于旋转的角度来说比较大,所以除以200减少它移动的角度,可以随意更改,其中鼠标在X轴上移动用户需要的是图形在以Y轴旋转。接着我么要计算立方体真正对于初始旋转了多少角度我们最好做一下范围限制(取模运算),Y = ((Y + scaleY) % 360);最后就是设置属性了,先用$(".container").animate()让旋转用动画的形式来做成,然后设置旋转角度$(".container").css({ "transform": rotateX(${X}deg) rotateY(${Y}deg) });css()方法来设置旋转角度。

3.总结

最后将github库放上来
github库

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103322.html

相关文章

  • SVG 方体内嵌路径拼接

    摘要:第一部分是正方体部分,第二部分是中的路径动画了,第三部分则是交互旋转。然后在立方体元素上添加鼠标点击事件事件,在回调函数中做处理内容。回调函数中先记录下来鼠标点击的位置。 1.前言 我使用了jquery编写交互的旋转,因为初学所以不太承受,还请见谅。样式我是写stylus编码,自动生成css。 2.正文 先放上一张效果图showImg(https://segmentfault.com...

    YPHP 评论0 收藏0
  • 2017-10-19 前端日报

    摘要:前端日报精选源码解析一组件的实现与挂载写在的前端数据层不完全指北非时圆角边框剪裁问题专题之解读排序源码中的闭包再也不用担心面试被问什么是闭包了中文路由路由基础入门实战操作详细指南前端学习教程用实现一门编程语言语言简介众成翻译第 2017-10-19 前端日报 精选 React源码解析(一):组件的实现与挂载写在2017的前端数据层不完全指北Chrome opacity非1时border...

    v1 评论0 收藏0
  • 翻译 | 编写SVG的口袋指南(上)

    摘要:元素元素归属于容器和结构元素,在文档内允许嵌套使用独立的片段。如果包含葡萄的组被移动到文档的末尾,它将出现在西瓜的前面。例如,将葡萄的茎的路径移动到组的末尾将导致茎在顶部。 作者:DDU(沪江前端开发工程师)本文是原文翻译,转载请注明作者及出处。 简介 Scalable Vector Graphics (SVG)是在XML中描述二维图形的语言。这些图形由路径,图片和(或)文本组成,并能...

    Brenner 评论0 收藏0
  • 翻译 | 编写SVG的口袋指南(上)

    摘要:元素元素归属于容器和结构元素,在文档内允许嵌套使用独立的片段。如果包含葡萄的组被移动到文档的末尾,它将出现在西瓜的前面。例如,将葡萄的茎的路径移动到组的末尾将导致茎在顶部。 作者:DDU(沪江前端开发工程师)本文是原文翻译,转载请注明作者及出处。 简介 Scalable Vector Graphics (SVG)是在XML中描述二维图形的语言。这些图形由路径,图片和(或)文本组成,并能...

    linkFly 评论0 收藏0
  • 打造最美HTML5 3D机房(第二季)

    摘要:写在前面的前面现在拍电影搞真人秀都流行拍续集,哥今天给大家带来的是打造最美机房的续集,哥的目标是成为机房界的网红。机柜标签机房中最重要的物理资源机柜是机房管理规划监控人员最关注的对象之一。 写在前面的前面 现在拍电影、搞真人秀都流行拍续集,哥今天给大家带来的是打造最美3D机房的续集,哥的目标是成为3D机房界的网红。 -------------------------------我是这个...

    BetaRabbit 评论0 收藏0

发表评论

0条评论

姘存按

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<