案例研究 - HTML5 MathBoard

Jeremy Chone
Jeremy Chone

简介

MathBoard 应用

iPad 上的 MathBoardPalaSoftware 应用,是一款经过精心打磨的应用,具有许多细微但自然的动画,以及独特逼真的外观和风格。目标是将 iPad 应用以最高保真度移植到 HTML5。

N2N-Apps 是一家软件开发公司,专注于使用 HTML5 技术构建新一代 Web 和移动应用。该公司由 Jeremy Chone 于 2010 年创立。Jeremy Chone 在 Netscape、Oracle 和 Adobe 积累了 11 年的工程和管理经验,决定与企业分享其专业知识,帮助他们构建高品质的 Web 和移动应用。N2N-Apps 专注于交付质量和速度。

下载适用于 Chrome 网上应用店的 MathBoard 下载适用于 Chrome 网上应用店的 MathBoard(免费版本)

要求

此 HTML5 移植项目的主要要求如下:

  1. 原始 iPad 应用外观和界面的高保真移植。
  2. 适应目标设备规格(例如,配备键盘/鼠标的 PC/Mac 与触摸屏)。
  3. 实现 100% 的适用功能。
  4. 主要定位到 HTML5 浏览器。
  5. 使应用变为“无服务器”应用,以便应用完全在客户端上运行,并且可以托管在静态服务器或 Google Chrome 打包应用上。
  6. 在不到一个月的时间内,制作出包含所有功能(但不含问题解决器)的 1.0 版。

架构

架构

根据这些要求,我们决定采用以下架构:

  1. HTML5:由于我们没有任何 HTML4 支持要求,因此决定以 HTML5 为基础。
  2. jQuery:虽然 HTML5 具有许多使 jQuery 如此出色的高级选择器,但我们还是决定坚持使用 jQuery,因为它提供了一种非常强大且成熟的方式来操控 DOM 和相关事件。jQuery 还有一个优势,就是更侧重于 DOM,这往往会使应用的设计和实现更接近 HTML。
  3. SnowUI:jQuery 提供了一个出色的 API 和与 DOM 交互的最佳实践,但对于 HTML5 MathBoard 应用,我们需要一个 MVC 或 MVP 风格的框架来协调所有不同的视图。SnowUI 是基于 jQuery 的简单而强大的 MVC 框架。它提供了以 DOM 为中心的 MVC 机制,并提供了一种灵活的方式来构建自定义组件,同时让应用开发者有机会使用他们认为最优的任何 widget/控件库或自定义代码。

从 iPad 传输到 PC 的注意事项

将应用移植到 HTML5 以供 PC 使用时,我们不得不对应用的设计和用户互动做出一些修改。

屏幕方向

iPad MathBoard 只能采用纵向模式,这对于 PC 显示屏来说并不理想,因为 PC 显示屏通常采用横向模式。因此,我们重新整理了界面设计,并将设置面板移到了右侧的滑动视图(通过 CSS3 过渡效果实现动画)。

屏幕方向
iPad 与 HTML5 屏幕方向

输入:键盘/鼠标与触控

iPad 版和网页版之间的另一个主要区别在于输入界面。在 iPad 上,您只有触控界面,而在 PC 上,您需要同时考虑鼠标和键盘。

iPad 上的 MathBoard 输入控件经过了精心打磨。我们希望在 Web 界面中也能获得同样的高保真呈现效果。解决方案是添加对键盘快捷键的支持,并使用 CSS 定位来复制界面控件。移植到 HTML5 后,像素完全准确:

界面控件
iPad 与 HTML5 版本设置

与 iPad 界面一样,我们允许用户点击左右箭头来更改控件的值。您还可以拖动垂直线来快速更改值。为 clickkeydown 实现了重复行为,以便用户在按下鼠标或键盘时加快值更改速度。

添加了 TAB 键支持,以便从一个输入字段移动到另一个输入字段,并且 ← 和 → 键可循环切换值。

iPad 版中有一项功能在 PC 界面上没有多大意义,那就是画板。虽然实现起来很炫酷,但用鼠标绘制数字并不实用。相反,我们决定花更多时间优化键盘界面,而不是实现画板。

HTML5 功能

在 MathBoard 的网页版中,我们使用了许多 HTML5 功能:

本地存储空间

MathBoard 允许用户保存自己的测验,以便日后重玩。HTML5 MathBoard 使用 SnowUI DAO 接口通过 HTML5 localStorage 实现此功能。

由于数据足够简单且不需要高级索引,因此 localStorage 是自然之选。我们将所有知识问答都存储为 JSON 格式,并将其 JSON.stringify 为文本。

snowUI DAO 是一个简单的 CRUD 接口封装容器,可让界面提取数据,而无需担心数据的实际存储方式。DAO 实现会处理存储细节。

在 MathBoard 中,存储空间要求非常简单。我们只需存储用户设置和知识问答数据。这两者均存储在 localStorage 中,以 JSON 字符串的形式存储。

例如,设置值的 DAO 如下所示:

snow.dm.registerDao('settingValue', (function() {

  var _settingValues = null;

  function SettingValueDao() {};

  // ------ DAO CRUD Interface ------ //
  // get
  SettingValueDao.prototype.get = function(objectType, id) {
    return $.extend({},getSettingValues()[id]);
  };

  // find, remove

  // save
  SettingValueDao.prototype.save = function(objectType, data) {
    var storeValue = getSettingValues('settingValue')[data.id];
    if (!storeValue) {
      storeValue = {};
      getSettingValues()[data.id] = storeValue;
    }

    $.extend(storeValue, data);
    saveSettingValues();
  };
  // ------ /DAO CRUD Interface ------ //

  function getSettingValues() {
    if (_settingValues == null) {
      var settingValuesString = localStorage.getItem('settingValues');
      if (settingValuesString) {
        _settingValues = JSON.parse(settingValuesString);
      } else{
        _settingValues = {};
      }
    }

    return _settingValues;
  }

  function saveSettingValues(){
    var settingValues = getSettingValues();
    if (settingValues != null) {
      localStorage.removeItem('settingValues');
      localStorage.setItem('settingValues', JSON.stringify(settingValues)); 
    }
  }

  return new SettingValueDao();
})());

settingValue 注册此 DAO 后,界面便可以执行以下调用,而无需担心存储逻辑:

var addition = snow.dm.get('settingValue', 'operator_addition');
addition.value = true; // to check the addition checkbox
snow.dm.save('settingValue', addition);

CSS3 字体

MathBoard 使用自定义字体。得益于 CSS3 字体支持,我们可以轻松地将“Chalkduster”TrueType 字体添加到应用中:

@font-face {
  font-family: Chalkduster;
  src: url(Chalkduster.ttf);
}

由于此字体是应用中几乎所有文本的默认字体,因此我们将其设为正文的默认字体。

body {
  background: #333333;
  font-family: Chalkduster;
  color: #ffffff;
}

CSS3 渐变、阴影、圆角

所有渐变、阴影、透明度和圆角均使用 CSS3 完成。与传统的 .png 界面开发方式相比,这真是帮了大忙。

我们还使用了高级 CSS3 属性来自定义滚动条的外观和风格,使其更细腻(如需在 WebKit 浏览器上设置滚动条样式,请参阅 http://webkit.org/blog/363/styling-scrollbars/)。

CSS3 过渡

对于 HTML5 MathBoard,我们复制了 iPad 的所有动画,甚至为滑动式右侧面板添加了一个新动画。得益于 CSS3 过渡,添加动画变得非常简单,并且可以实现最佳性能。

应用中有三种主要动画。

1.) 滑动式右侧窗格

第一个动画位于右侧窗格 (#rightPane) 中,当用户开始新的知识问答时,该窗格会滑动关闭,当用户结束知识问答时,该窗格会滑动打开。为了实现此效果,我们使用了以下 CSS 过渡并通过 JavaScript 触发了它。rightPane 的默认样式处于打开状态:

#rightPane {
  /* look and feel, and layout property */
  position: absolute;
  width: 370px;
  height: 598px;
  top: 28px;
  left: 720px; /* open */
  -webkit-transition: all .6s ease-in-out;
}

当用户开始测验时,我们的 JavaScript 逻辑会移动该面板:

var $rightPane = $('#rightPane');
var left = $rightPane.position().left - 400;
setTimeout(function() {
  $rightPane.css('left', left + 'px');
}, 0);

关于此实现的一些说明:

  1. 由于应用大小是固定的,我们可以使用 CSS 类“.close”,并像对开启按钮一样对关闭按钮的位置进行硬编码。
  2. 我们还可以使用 CSS“translate”,其性能要优于为窗格的“left”属性添加动画效果。对于采用硬件加速 3D 转换的移动设备(例如 iOS 设备),这一点尤为重要。
  3. 在本例中,setTimeout 并不是严格必须的,因为原始位置是在修改之前设置的。不过,它允许浏览器在滑动右侧窗格之前显示测验,从而使动画更流畅。

2.) “设置”对话框动画

当用户点击右侧的某个设置时,设置对话框会从屏幕底部显示,并滚动到底部相应部分。

为此,我们在右侧窗格中采用了类似的转换效果。唯一花了一些时间的是解决对话框首次显示时出现的卡顿问题。为了指示浏览器缓存对话框界面,我们最终显示了该界面一次,并滚动到该界面。起初,我们尝试使用 display: none。这种方法是错误的,因为浏览器会假定不需要显示该对话框。解决方案是在初始化时使用 z-index: -1 显示设置,使其对用户不可见,但对浏览器可见。

3.) 知识问答成功或消息动画不正确

第三个动画实际上是两者合一。当“成功”或“不正确”消息显示时,先缩放到一个点,稍等片刻,最后再缩放得更大,然后消失。为此,我们使用了两种 CSS3 动画样式,并通过 JavaScript 在 webkitTransitionEnd 事件上进行编排。

.quiz-result > div.anim1 {
  opacity: 0.8;
  -webkit-transform: scale(6,6);
}
.quiz-result > div.anim2{
  opacity: 0;
  -webkit-transform: scale(9,9);
}
setTimeout(function() {
  $msg.addClass("anim1");
  $msg.bind("webkitTransitionEnd", function(){
    if ($msg.hasClass("anim1")) {
      setTimeout(function() {
        $msg.removeClass("anim1");
        $msg.addClass("anim2");
      }, 300);
    } else {
      $msg.remove();
      displayNextItem();
      freezeInput = false;
    }
  });
}, 0);

音频标签

当用户回答知识问答时,应用会发出成功或失败提示音。简单的选择是使用音频标记并对其调用 play()。这些音频内容会添加到应用的主页面:

<audio id="audioCorrect" src="correct.mp3" preload="auto" autobuffer></audio>
<audio id="audioWrong" src="wrong.mp3" preload="auto" autobuffer></audio>

总结

HTML5 真正支持了新一代 Web、桌面和移动应用。 CSS3 有助于自定义应用的外观和风格,使其与 MathBoard for iPad 的高度复杂性相得益彰;HTML5 存储空间非常适合我们的数据持久化;HTML5 音频的简单性使我们能够精确复制 iPad 应用。