头图

在现代应用程序中,无论是网页还是移动端应用,进度条都是一种常见的用户界面元素。它不仅能够向用户直观地展示任务或操作的完成进度,还能提高用户体验感。进度条的动画效果尤其重要,因为它能使进度条的变化更加生动,为用户提供视觉上的反馈,从而使等待过程不那么枯燥乏味,通过图扑软件自研的产品 HT for Web 可以绘制出千变万化的进度条效果控制动画。

这篇文章就将浅析进度条控制动画是如何实现的?

系统分析

进度条动画的核心在于记录和管理每一帧的动作,每一帧代表着在特定时间点上,进度条应展现的具体状态。当时间推进到指定的帧时,场景中的元素根据预设的动画效果发生变动。这些变化通常通过平滑的过渡动画来实现,以提供一个视觉上连续且流畅的体验。为了实现这种平滑效果,动画设计需要精心调整关键帧之间的插值,确保各个过渡阶段无缝衔接。

此外,进度条动画还可以与用户交互反馈相结合,例如在用户点击或拖动时,实时更新进度条的状态和动画效果。这种交互式的设计不仅提高了用户体验,还增加了应用程序的响应性和互动性。

动画实现步骤

1、根据之前的分析,我们需要记录动画帧。动画效果要求平滑过渡,因此需要记录的信息包括参与动画的节点、动画类型以及动画的时间周期数据。例如,以下记录了船只和飞机在不同时间点的路径动画数据。

var animConfig = {
     ship: [{
        startTime: 15,
        endTime: 47,
        path: 'shipPath'
    }],
    plane: [{
        startTime: 0,
        endTime: 30,
        path: 'path'
    },
    {
        startTime: 35,
        endTime: 70,
        path: 'path2'
    }]
}

2、要封装设置每帧动画的方法。由于上述数据只涉及路径动画,因此在这个案例中只需封装路径动画的设置方法。每种动画类型都可以各自封装对应的方法,以便于使用。

function pathAnim(node, path, v, currtAnim, prevAnim) {
  // 获取管道百分比点信息,设置到运动节点上
  if (v >= 0 && v <= 1) {
    var lineLength = g3d.getLineLength(path);
    var offset = g3d.getLineOffset(path, lineLength * v), 
      point = offset.point, 
      px = point.x, py = point.y, 
      pz = point.z, 
      tangent = offset.tangent, 
      tx = tangent.x, 
      ty = tangent.y, 
      tz = tangent.z;
    node.p3(px, py, pz);
    node.lookAt([px + tx, py + ty, pz + tz], 'front');
  }
  
  if (v > 0 && v < 1) {
    path.s({
      '3d.clip.percentage': v,
      'transparent.mask': false
    })
  }
  else {
    path.s('transparent.mask', true)
  }
  
  if (currtAnim !== prevAnim && prevAnim >= 0) {
    g3d.dm().getDataByTag(animConfig[node.getTag()][prevAnim].path).s('transparent.mask', true)
  }
}

3、使用记录的动画数据,计算当前时间所对应的动画帧。即使节点当前不在动画时间周期内,也需要设置相应的动画帧。

function playProggress(currtTime) {
  for (var key in animConfig) {
    var node = g3d.dm().getDataByTag(key)
    var anims = animConfig[key];
    var length = anims.length;
    var currtAnim = isCurrtTimeOutOfRanges(currtTime, anims);
    var prevAnim = node.a('prevAnim');


    // 计算每一段动画对应的百分比
    var currtItemPercentage;
    if (currtAnim > -1) {
      node.a({
        'prevAnim': currtAnim
      })
      var startTime = anims[currtAnim].startTime * 1000;
      var endTime = anims[currtAnim].endTime * 1000;
      currtItemPercentage = (currtTime - startTime) / (endTime - startTime);
    }
    else {
      var bTime = anims[0].startTime * 1000;
      var eTime = anims[length - 1].endTime * 1000;
      var currtAnim = prevAnim;
      if (currtTime < bTime) {
        currtAnim = 0;
      }
      else if (currtTime > eTime) {
          currtAnim = length - 1;
      }
      currtItemPercentage = currtTime < bTime ? 0 : 1;
    }
    var path = this.dm.getDataByTag(anims[currtAnim].path);
    pathAnim(node, path, currtItemPercentage, currtAnim, prevAnim);
}


// 判断是不是在动画周期内
function isCurrtTimeOutOfRanges(currtTime, ranges) {
  return ranges.findIndex((range) => {
    var startTime = range.startTime * 1000,
    endTime = range.endTime * 1000;
    return currtTime >= startTime && currtTime <= endTime;
  });
}

4、封装动画,使其能够自动播放整个动画,同时在动画中设置进度条百分比。这里的 duration 指的是整个动画的周期。

var _partAnim;
function partAnim(duration, percentage) {
   _partAnim && _partAnim.pause();
  var dm = g3d.dm();
  if (percentage === 1) {
    percentage = 0.99;
  }
  
  // 获取百分比控制节点
  var progress = g2d.dm().getDataByTag('progress');
  _partAnim = ht.Default.startAnim({
    duration: duration * (1 - percentage),
    easing: easingFunc(function (t) {
      return t;
    }, percentage),
    action: (v, t) => {
      // 不同的控制组件百分比属性可能不一样
      progress.a('value', v * 100);
      playProggress(duration * v)
    },
    finishFunc: () => {
      partAnim(duration, 0);
    }
  });
}


// 传入进度百分比,设置缓动函数,使用此方法自由控制动画起始帧
function easingFunc(easing, percentage) {
  if (!percentage) return easing;
    return function (t) {
      t = percentage + t * (1 - percentage);
      return easing(t);
    }
}

5、封装监听封装进度条控制方法,在鼠标拖动控制条时,切换对应的动画帧。

function progressChange(percentage){
  _partAnim.pause()
  partAnim(80e3, percentage)
}

进度条应用案例

进度条控制动画需要对每一帧进行精准控制,明确每个时间节点的属性状态。当时间到达指定节点时,相应地调整属性,从而实现进度条控制动画的流畅运行。

以下简单介绍几个进度条在图扑可视化案例中的应用:

农作物模拟生长

图扑的进度条控制功能为用户提供了一种直观方式,手动调节和观察农作物的生长模拟。通过拖动进度条,用户可以精确设定作物从播种到成熟的各个生长阶段变化。这种模拟不仅帮助理解生长周期,还可用于研究不同环境和管理措施对作物的影响,为农业生产提供参考和指导。

火情救灾模拟

用户可以通过进度条手动调节救援各阶段,实时监控和调整资源分配。借助这种交互操作,参与者能更直观地理解火情动态,提高应急决策能力,为实际救援提供宝贵经验。

防恐演练模拟

这一功能允许实时调整模拟情境,用户可以灵活切换应对策略。这种交互方式帮助指挥人员优化决策和资源配置,提高实际事件中的应变效率。模拟提供了一个安全环境来测试和完善防恐策略,为应对现实威胁做好准备。

工厂流水线操作

HT 进度条控制功能允许用户手动调整工厂车间流水线的模拟过程。用户可以启动、暂停、加速生产模拟,通过拖动进度条来精确控制生产速度,实时分析各环节的效率和瓶颈。这种交互模拟为优化资源配置和改进工艺流程提供了有效支持,有助于提升整体生产效率和响应能力。

船舶时间进度

图扑港口船舶可视化案例中,进度条显示船只的航行日期,通过调节时间日期可查看事件的历史作业情况,在发生意外时可追溯问题原因,以及对后续港口事件处理的预防以及港口运维人员更好地设置应急处理预案。

智慧施工实况

通过图扑进度条的控制实现智慧工地对场地平整、做地基、回填等各阶段工况的实时管理回放,从一线操作与远程监管的数据链条,实现劳务、安全、环境、材料各业务环节的智能化、互联网化管理,提升建筑工地的精益生产管理水平。

进度条控制动画进度条在图扑的很多其他案例中也有被用到,尤其是在流程动画较长时,用户可以在任意时间节点开始演示流程动画效果,这极大地方便了用户使用。

总结

进度条控制动画播放是一个较为高级的功能,需要开发者对 HT 有一定的基础,才能较为轻松地实现。对于有兴趣深入学习这一功能的开发者,欢迎随时与我们沟通交流,我们将提供专业的指导和资源,帮助大家更好地掌握和应用这一技术。通过我们的支持,您能够在项目中实现更加流畅和互动的动画效果。


hightopo
5.5k 声望3k 粉丝

Everything you need to create cutting-edge 2D and 3D visualization