刘宇同学选择失读症作为其毕业设计主题,希望通过用设计的方式能够帮助到这一特殊群体。在确立内容后,开始尝试建立思维导图,但是由于前期经验不足,故在这个节点上就有多次的调整和修改,其最主要的原因还是无法正确的,有逻辑的将一个新产品用思维导图的形式去表达。
界面设计的确立
开始选定手机为最终的呈现终端,但突然发现由于手机屏幕普遍较小,对于目标受众来说,平板也许的一个更好的解决方案,由于屏幕相对较大,可以在里边加入更多的细节,比如场景的细致刻画,大面积的热点交互(有效解决目标受众无法精确点击的问题)。
遇到的问题:
1.奇葩的调试环境
RP可以制作app原型,虽然相对其他软件来说容易使用,但存在的问题还是较多,比如页面的自适应。如果在设计之处没有很好的把控设计尺寸和屏幕本身尺寸的高度统一,后期出现的问题就是页面会被撑开,而且可以随意拖动。
解决方案:
为了能够让演示效果能更接近原生App的那种感觉,无论如何,我们都要禁止页面可以上下左右的随意拖动,这会给使用者一个很糟糕的用户体验。而在PR的界面中,虽然有禁止页面放大,自适应页面等配置选项,但是由于我们在页面中增加了载入动画,而这些动画元素默认是隐藏在屏幕外部的,所以刚打开页面的时候这些动画元素会将本来设置好的页面尺寸破坏掉,导致页面比屏幕尺寸还大,可以随意的拖动。
其实这个解决方法很简单,我觉得以后再有类似的事情出现,可直接在控制全局的css中加入下面这段即可。
body {
position: fixed !important;
top: 0 !important;
bottom: 0 !important;
right: 0 !important;
left: 0 !important;
overflow: hidden !important;
}
2.可替换的本地视频
由于RP软件本身的局限性,我们无法在其设计和制作的过程中加入额外想加入的内容,例如视频,在RP中只可以调用 iframe 标签,这个标签必须要引入一个全新的页面才能正常显示,而我们的需求仅仅是需要载入一个本地视频。
如果直接采用iframe ,那就需要将在显示屏插入进来,但其存在不好修改更新和替换等弊端,所以最终我们选择在PR的基础上进行二次加工。
解决方案:
由于终端浏览器为最新的现代浏览器,所以加入视频只需一个video标签即可搞定,其代码简单直观,更容易更新和维护。
<video width="1024" height="768" id="shakeVideo" src='files/视频/1.mp4' autoplay controls style="background:url(img/shaking_bg.jpg);" webkit-playsinline playsinline></video>
3.让书本可以真正的翻阅
在整个界面中,有部分页面由于整体设计较为单一,如果直接静态展示,显然达不到最初的设计目的,如书本和眼中的世界这两个页面,如果没有加入有趣的交互,那么基本失却他本来该有的意义。
界面中呈现的一本翻开状态的书原本是一张jpg图片,除了上面有多段文本外,无法达到翻阅的效果。
解决方案:
和上一个局限性一样,RP无法满足这些交互要求,也无法在其界面中直观的修改来达到想要的效果。所以,最终的解决方案还是修改其源代码,让其能够实现我们想要的需求。
通过修改源代码,我们在jquery的基础上,增加了可以touch触摸的翻页交互效果,其最终呈现和操作都可以让整个界面变的更加真实有趣。
其代码如下:
首先引入自带jquery,然后在加入TweenMax
<script src='/jquery.min.js'></script>
<script src="/TweenMax.min.js"></script>
下面是控制翻书JS
TweenLite.set(".pageBg", {
xPercent: -50,
yPercent: -50
});
TweenLite.set(".pageWrapper", {
left: "50%",
perspective: 1000
});
TweenLite.set(".page", {
transformStyle: "preserve-3d"
});
TweenLite.set(".back", {
rotationY: -180
});
TweenLite.set([".back", ".front"], {
backfaceVisibility: "hidden"
});
$(".page").click(function() {
if (pageLocation[this.id] === undefined || pageLocation[this.id] == "right") {
zi = ($(".left").length) + 1;
TweenMax.to($(this), 1, {
force3D: true,
rotationY: -180,
transformOrigin: "-1px top",
className: '+=left',
z: zi,
zIndex: zi
});
TweenLite.set($(this), {
className: '-=right'
});
pageLocation[this.id] = "left";
} else {
zi = ($(".right").length) + 1;
TweenMax.to($(this), 1, {
force3D: true,
rotationY: 0,
transformOrigin: "left top",
className: '+=right',
z: zi,
zIndex: zi
});
TweenLite.set($(this), {
className: '-=left'
});
pageLocation[this.id] = "right";
}
});
$(".front").hover(function() {
TweenLite.to($(this).find(".pageFoldRight"), 0.3, {
width: "50px",
height: "50px",
backgroundImage: "linear-gradient(45deg, #fefefe 0%,#f2f2f2 49%,#ffffff 50%,#ffffff 100%)"
});
},
function() {
TweenLite.to($(this).find(".pageFoldRight"), 0.3, {
width: "0px",
height: "0px"
});
});
$(".back").hover(function() {
TweenLite.to($(this).find(".pageFoldLeft"), 0.3, {
width: "50px",
height: "50px",
backgroundImage: "linear-gradient(135deg, #ffffff 0%,#ffffff 50%,#f2f2f2 51%,#fefefe 100%)"
});
},
function() {
TweenLite.to($(this).find(".pageFoldLeft"), 0.3, {
width: "0px",
height: "0px"
});
})
var pageLocation = [],
lastPage = null;
zi = 0;
下面则是HTML结构
<div class="bookWrapper">
<div class="bookBg">
<div class="pageBg">
<div class="pageWrapper">
<div id="page2" class="page">
<div class="pageFace front">
<img class="bookimg " src="images/图书馆书/book/003.jpg"/><!--第三页-->
<div class="pageFoldRight"></div>
</div>
<div class="pageFace back">
<img class="bookimg " src="images/图书馆书/book/004.jpg"/><!--第四页-->
<div class="pageFoldLeft"></div>
</div>
</div>
<div id="page1" class="page">
<div class="pageFace front">
<img class="bookimg " src="images/图书馆书/book/001.jpg"/><!--第一页-->
<div class="pageFoldRight"></div>
</div>
<div class="pageFace back">
<img class="bookimg " src="images/图书馆书/book/002.jpg"/><!--第二页-->
<div class="pageFoldLeft"></div>
</div>
</div>
</div>
</div>
</div>
</div>
4.解决了上面的问题,出现了兼容问题。
好不容易解决了翻书等效果的问题,因为翻书效果中的jquery代码相对版本较高,而RP自带的jquery版本为1.7.1,这导致虽然翻书效果出现了,但是无法正常的点击返回按钮返回到上一个,因为RP的所有超链接都用js去控制,而并非是一个带有a标签的href超链接。
如果直接将其改成a标签,再添加上跳转目标页也是可以的,但是我们在ipad的呈现方式是将其添加到主屏幕,然后点击主屏幕的图标启动访问(仿造一个app),如果在这个页面中加入a标签,当点击后他会自动在Safari打开下一个页面,这显然不是我们想要的操作流程。
解决方案
想要修改jquery代码实现版本兼容,很显然是一件麻烦是事情,而且我们的时间并不是很充裕,所以,有一个讨巧的方案,可以完美实现因为代码冲突而无法工作的返回按钮。
代码如下:
<a onClick="javascript :history.back(-1);">
<img id="u99_img" class="img " src="images/图书馆书/返回键浅_u99.png"/>
</a>
5.两个世界的不同感受
界面中为了表现患有失读症人群看到的文字世界和普通人看到的文字有所不同,需要设计出很直观的展示效果,但由于无法进行交互,所以,只能在这里进行取舍,留下失读症眼中的文字世界。
解决方案:
为了能够让两者并存,我们选择在这个界面加入另外一种可以通过touch触摸的交互元素——放大镜。这个功能在PR中也是不存在的,所以,还得修改最终的源文件。
其代码如下:
var svgElement = document.querySelector('svg');
var maskedElement = document.querySelector('#mask-circle');
var circleFeedback = document.querySelector('#circle-shadow');
var svgPoint = svgElement.createSVGPoint();
function cursorPoint(e, svg) {
svgPoint.x = e.clientX;
svgPoint.y = e.clientY;
return svgPoint.matrixTransform(svg.getScreenCTM().inverse());
}
function update(svgCoords) {
maskedElement.setAttribute('cx', svgCoords.x);
maskedElement.setAttribute('cy', svgCoords.y);
circleFeedback.setAttribute('cx', svgCoords.x);
circleFeedback.setAttribute('cy', svgCoords.y);
}
window.addEventListener('mousemove',
function(e) {
update(cursorPoint(e, svgElement));
},
false);
document.addEventListener('touchmove',
function(e) {
e.preventDefault();
var touch = e.targetTouches[0];
if (touch) {
update(cursorPoint(touch, svgElement));
}
},
false);
html如下
<div class="game">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
<rect width="100%" height="100%" fill="rgba(0,0,0,0)"/>
<image xmlns:xlink= "http://www.w3.org/1999/xlink" xlink:href="images/game/a-1.png" width="100%" height="100%" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
<defs>
<clipPath id="mask">
<circle id="mask-circle" cx="50%" cy="50%" r="15%" style="fill: #ffffff"/>
</clipPath>
</defs>
<g clip-path="url(#mask)">
<rect width="100%" height="100%" fill="#272730"/>
<image xmlns:xlink= "http://www.w3.org/1999/xlink" xlink:href="images/game/a-2.png" width="100%" height="100%" />
</g>
<circle id="circle-shadow" cx="50%" cy="50%" r="15%" style="stroke: #fff; fill: transparent; stroke-width: 5;" />
</svg>
</div>
最终,我们可以直接在这个界面中拖动放大镜,看到另外一个不同的世界。
6.旋转的文字世界
最后一个需要解决的问题是,最初的界面中需要加入一个可以触摸,点击然后增加笔画的这一一个互动页面,其需求是:操作者可以点击屏幕的任何页面,然后或随机出现不同的汉字的偏旁部首,如果点击的位置把握较准确,可以拼接出不同的汉字组合。同事这些文字会围绕一个中心点从左至右无限循环的旋转。
解决方案:
首先将所有文字的偏旁部首进行单独切割,并保存成为透明的png图像,然后在通过修改源文件,加入以jquery做基本支持的js代码,让其产生可以拖动,点击出现,循环等不同的功能和需要。
js代码如下:
var ge1doot = ge1doot || {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function(id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize',
function() {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function() {
return false;
}
this.elem.ondrag = function() {
return false;
}
initRes && this.resize();
return this;
},
resize: function() {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
},
pointer: {
screen: null,
elem: null,
callback: null,
pos: {
x: 0,
y: 0
},
mov: {
x: 0,
y: 0
},
drag: {
x: 0,
y: 0
},
start: {
x: 0,
y: 0
},
end: {
x: 0,
y: 0
},
active: false,
touch: false,
down: function(e, touch) {
this.touch = touch;
if (touch) e.preventDefault();
var pointer = touch ? e.touches[0] : e;
this.pos.x = this.start.x = pointer.clientX - this.screen.left;
this.pos.y = this.start.y = pointer.clientY - this.screen.top;
this.active = true;
this.callback.down && this.callback.down();
},
up: function(e, touch) {
this.touch = touch;
e.preventDefault();
this.end.x = this.drag.x;
this.end.y = this.drag.y;
this.active = false;
this.callback.up && this.callback.up();
},
move: function(e, touch) {
this.touch = touch;
e.preventDefault();
var pointer = touch ? e.touches[0] : e;
this.mov.x = pointer.clientX - this.screen.left;
this.mov.y = pointer.clientY - this.screen.top;
if (this.active) {
this.pos.x = this.mov.x;
this.pos.y = this.mov.y;
this.drag.x = this.end.x - (this.pos.x - this.start.x);
this.drag.y = this.end.y - (this.pos.y - this.start.y);
this.callback.move && this.callback.move();
}
},
init: function(callback) {
this.screen = ge1doot.screen;
this.elem = this.screen.elem;
this.callback = callback || {};
if ('ontouchstart' in window) {
// touch
this.elem.ontouchstart = function(e) {
this.down(e, true);
}.bind(this);
this.elem.ontouchmove = function(e) {
this.move(e, true);
}.bind(this);
this.elem.ontouchend = function(e) {
this.up(e, true);
}.bind(this);
this.elem.ontouchcancel = function(e) {
this.up(e, true);
}.bind(this);
}
// mouse
this.elem.addEventListener("mousedown",
function(e) {
this.down(e, false);
}.bind(this), true);
document.addEventListener("mousemove",
function(e) {
this.move(e, false);
}.bind(this), true);
document.addEventListener("mouseup",
function(e) {
this.up(e, false);
}.bind(this), true);
return this;
}
}
}
}
css代码
html, body {
touch-action: none;
content-zooming: none;
margin: 0;
padding: 0;
background: #000;
position: absolute;
width: 100%;
height: 100%;
}
#screen {
width: 100%;
height: 80%;
margin: auto auto;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #000;
cursor: pointer;
}
#screen img {
position: absolute;
}
#vb {
position: absolute;
left: 50%;
top: 10%;
height: 80%;
z-index: 10000;
background-image: url(../bg.png);
width: 8px;
}
}
#title {
position: absolute;
color: #fff;
font-family: arial;
font-weight: bold;
font-size: 1.5em;
text-align: center;
width: 100%;
top: 1em;
}
#particles {
visibility: hidden;
}
HTML代码
<div id="screen">
<div id="title">
请滑动屏幕
</div>
<div id="vb"></div>
</div>
<div id="particles"><!--元素-->
<img alt="" src="01.png">
<img alt="" src="02.png">
<img alt="" src="03.png">
<img alt="" src="04.png">
<img alt="" src="05.png">
<img alt="" src="06.png">
<img alt="" src="07.png">
<img alt="" src="08.png">
</div>