印第安纳 (琼斯) 的精神 - 使用 HTML5 视频与地图同步

我一直很喜欢印第安纳琼斯电影中的旅行/飞行场景,从 YouTube 上的复制尝试数量来看,我并不孤单。由于我没有使用任何视频编辑软件,我认为使用 Web 技术和 Google 地图可以实现相同的效果,并且果然可以。

查看在线演示

您可以下载动画演示并尝试本地运行 - 您只需要一个支持 HTML5 视频的浏览器。我知道 - 音乐与电影中的音乐不太一样,但至少这首音乐没有侵犯版权,它来自我的内心(在 Mozilla 办公室的会议室里待了 5 分钟)。

那么这是如何完成的,需要解决什么问题呢?以下是方法和问题。

步骤 1:查找电影并将其转换为正确的格式

这很简单。 Archive.org 拥有许多可供您使用的很棒的公共领域电影,它们已经是 HTML5 视频元素所需的格式。在这种情况下,我拍摄了查尔斯·林德伯格起飞的简短电影,他于 1927 年从纽约起飞前往巴黎进行破纪录的飞行

步骤 2:显示视频

使用视频非常简单

MP4 格式将被基于 Webkit 的浏览器使用,而 Ogg 版本将被 Firefox 和其他浏览器使用。由于我们要控制视频,因此我们在 video 元素上省略了 controls 属性 - 而是使用 JavaScript 创建一个按钮来播放视频。

window.addEventListener('load',
  function() {
    var stage = document.getElementById('stage');
    var v = document.getElementsByTagName('video')[0];
    but = document.createElement('button');
    but.innerHTML = 'Click to see Lindbergh's flight';
    stage.appendChild(but);
    but.addEventListener('click',function(e) {
      v.play();
      e.preventDefault();
    },false);
  },
false);

由于视频是标记,我们可以对其进行任何处理 - 开放技术的强大功能。例如,正如我们在这里所做的那样,我们可以在 CSS 中设置其不透明度,并将其放在地图的顶部。

步骤 3:创建地图路径动画

说到这里,让我们开始进行移动路径。Google Earth 有一个 API 可以做到这一点,但它需要一个特殊的插件。Google 地图允许您在地图上绘制路径(实际上是 SVG,另一种开放标准)。将其放入递归函数中,您会获得所需的效果

Animated Google Maps path synced with HTML5 video

本质上,我所做的是获取起点和终点的纬度和经度,并根据动画的持续时间计算出这两点之间的尽可能多的点。我将这些点存储在一个名为 pos 的数组中,然后从起点绘制一条到当前点的路径,并在每次迭代时将地图中心移动到该点。

spirit.draw = function(){
  var path = new google.maps.Polyline({
        path: [startpos,pos[now]],
        strokeColor: "#c00",
        strokeOpacity: .7,
        strokeWeight: 10
  });
  path.setMap(map);
  map.panTo(pos[now])
  now = now + 1;
  if(now < animationend-1){
    setTimeout(spirit.draw,200);
  }
}

查看地图示例的高度注释的源代码以获取详细信息。现在,我们可以使用这种动画并播放视频,但问题是它们可能会不同步。当电影停顿(就像在这种酒店无线连接上经常发生的那样)时,我们不希望动画继续移动,对吧?

步骤 4:同步视频和地图移动

我们必须将自己限制在一个真实的来源,而不是拥有两个计时信息来源。这是当前正在播放的电影的时间戳。

顺便说一句 - 您可能已经注意到我将地图代码包装在一个 tilesloaded 事件处理程序中。这是保持事物同步的另一种保障措施。我发现,在连接速度慢的情况下,瓦片加载可能会极大地延迟整个界面(由于所有子域查找),因此我让整个界面依赖于地图的加载,并且只有在瓦片加载完成后才继续。由于 tilesloaded 事件也会在地图平移时触发,因此我们需要使用一个布尔值来阻止它多次启动效果。

google.maps.event.addListener(map,'tilesloaded',function(){
  if(played === false){
    // [...other code...]
    played = true;
  }
});

您可以使用 video.currentTime 读取视频的当前时间戳,并且当电影播放时,它会不断触发一个名为 timeupdate 的事件。由于该事件触发了很多次,因此我们需要对其进行节流。这里的诀窍是只取完整的秒数,并在达到新秒数时增加计数器。您可以在视频同步演示中看到时间戳和秒间隔触发。

HTML5 video with timestamp

var now = 0;
v.addEventListener('timeupdate',function(o){
  log.innerHTML = v.currentTime; /* logging the real timestamp */
  var full = parseInt(v.currentTime);
  if(full >= now) {
    seqlog.innerHTML = now;  /* logging the seconds firing */
    now = now + 1;
  }
},false);

这样,电影可以在中间滞后,而序列仍然保持同步。查看Github 上此演示的源代码

将它们全部组合在一起

就这样 - 我所要做的就是在某个时间戳设置电影的不透明度,在另一个时间戳开始声音,并在另一个时间戳显示和隐藏版权声明。由于我们依赖于时间戳来实现其他效果,因此我们需要一个布尔开关来避免重复触发。

v.addEventListener('timeupdate',function(o){
  full = parseInt(v.currentTime);
  if(full === now-1){
    mapelm.style.opacity = .8;
    v.style.opacity = .4;
  }
  if(full === animationstart+1 && audioplay === false){
    a.play();
    audioplay = true;
  }
  if(full === animationstart+2 && hidden === true){
    drmbedamned.style.display = 'block';
    hidden = false;
  }
  if(full === animationstart+3 && hidden === false){
    drmbedamned.style.display = 'none';
    hidden = true;
  }
  if(full >= now) {
    path = new google.maps.Polyline({
        path: [startpos,pos[full]],
        strokeColor: "#c00",
        strokeOpacity: .7,
        strokeWeight: 10
    });
    path.setMap(map);
    map.panTo(pos[full])
    now = now + 1;
  }
},false);

我们还需要订阅的另一个事件是电影结束,这样我们就可以停止音乐并开始滚动字幕。

v.addEventListener('ended',function(o){
  a.pause();
  spirit.credslist.parentNode.style.display = 'block';
  spirit.creds();
},false)

由于主题对于整个动画来说太短,因此我们需要循环播放它。这可以通过测试 ended 事件并将时间回滚到 0 来完成。

a.addEventListener('ended', function(o) {
  a.currentTime = 0;
},false);

摘要

就是这样 - 使用开放服务和开放技术创建印第安纳琼斯风格的地图。对于受版权保护的音频(使用免费的Audacity 声音编辑器录制、编辑和转换)的解决方法,以及使用Google 的 Web 字体作为图形。

现在您可以使用它并对其进行更改以获得更令人惊叹的效果。

  • 用 Openstreetmap 替换 Google 地图,以避免超出限制。
  • 在从纽约到巴黎的路径上添加轻微的曲线,使其更准确(但同样,时间也不准确 - 查尔斯花费的时间更长)。
  • 使用静态地图并使用 Canvas 绘制路径,以加快和平滑动画。

为什么不尝试一下 - 它是免费的,并且玩起来很有趣。

关于 Chris Heilmann

HTML5 和开放 Web 的布道者。让我们解决这个问题!

Chris Heilmann 的更多文章……


9 条评论

  1. Derek

    我之前做过类似于地图组件的事情:http://swingley.appspot.com/maps/ij

    它不如最前沿,但它确实受到了印第安纳琼斯电影的启发。

    2010 年 12 月 16 日 上午 8:38

    1. Tom Skelton

      太棒了!

      2010 年 12 月 18 日 下午 12:14

  2. Shmerl

    非常棒的演示,谢谢!

    实际上,MP4 与 WebKit 无关 - 基于 WebKit 的 Google Chrome 可以完美播放 Theora 视频。罪魁祸首是 Safari(移动版才是真正的问题,因为无法像桌面版 Safari 一样使用 Quicktime 编解码器插件启用 Theora/WebM)。

    2010 年 12 月 16 日 上午 9:05

  3. Robert Kaiser

    现在,一个额外的不错的建议是使用开放地图数据,并使用 OpenStreetMap/OpenLayers 内容 - 但我不知道是否可以在上面完美地绘制您需要的内容。尽管如此,这将是很棒的 ;-)

    2010 年 12 月 16 日 上午 10:07

    1. cheilmann

      是的,正如我在摘要中所说 :) 回家后我会试一试 - 这周会议很多。

      2010 年 12 月 16 日 上午 10:09

  4. tack

    这是一个很棒的项目,但是 Google 地图是否错误地获取了林德伯格所走的路线?它是在一个平面地图上形成直线,而不是曲线吗?地球是圆的。

    2010 年 12 月 16 日 下午 12:40

  5. Robert Longson

    这很棒,但你能不使用 SMIL 并使其更简单吗?所有这些 setTimeout 代码都会消失,你仍然可以使用 SMIL 动画上的基于事件的计时来同步视频和动画。

    2010 年 12 月 18 日 下午 03:51

  6. paul

    实际上,印第安纳·琼斯的地图是 Google Analytics 图表设计的灵感来源。

    2010 年 12 月 18 日 下午 14:56

  7. Ninna

    哈哈,太有趣了!

    2011 年 1 月 7 日 上午 08:20

本文的评论已关闭。