这里是一款旅游相关的安卓应用,其中虚拟旅游的功能采用html5的360度全景图技术实现,使用户能够身临其境的感受旅游景点的风光。

此处引入了ddpanorama插件,它的原理是在canvas上绘制全景图,手指滑动时重绘canvas来实现。它包括通过手指滑动循环查看全景图,点击热点可进入另一全景图,缩放,离线访问等功能。

热点的计算和绘制:

可以在ddpanorama.js中看到在redraw这个方法也就是canvas重绘的时候定义了一个事件:

  1. $(this.img).trigger(
  2. jQuery.Event(ddpanoramas.event_prefix+"redraw", {
  3. scrollX : scrollX,
  4. canvas : this.canvas,
  5. speed : $(this.canvas).prop("speedX") / ddpanoramas.max_speed,
  6. loaded : loaded
  7. }));

并且传出了一些参数,其中scrollX这个参数是针对原图比例的手指滑动时图片的偏移量,它在计算热点位置时起到至关重要的作用。因此在绑定ddredraw这个事件,在该事件触发时候进行热点的计算和绘制及点击事件的绑定。这里为了方便,我们还需要一个参数,就是针对canvas比例的手指滑动时图片的偏移量。这个在ddpanorama.js中setScrollX这个方法中的scrollX取得,我们可以定义一个全局变量canvasScrollX,将这个值存储起来,随时使用。

至于计算过程,需要慢慢调试,这里上个代码:

  1. imgEle.ddpanorama({ width: bodyWidth, height: bodyHeight }).bind("ddredraw", function (event) {
  2. var canvas = event.canvas;
  3. var ctx = canvas.getContext("2d");
  4. var imgNatualWidth = imgEle.get()[0].naturalWidth;
  5. var imgNatualHeight = imgEle.get()[0].naturalHeight;
  6. var fontSize = imgNatualHeight / 40;
  7. if (hotPointInfo != null) {
  8. for (var i = 0; i < hotPointInfo.length; i++) {
  9. if (hotPointInfo[i] != null && hotPointInfo[i].PanImgHotType != null && hotPointInfo[i].PanImgInfoID != null && hotPointInfo[i].PanImgHotType == 0 && hotPointInfo[i].PanImgInfoID == GetHotPanImgInfoID) {
  10. var hotPanImgInfoId = hotPointInfo[i].HotPanImgInfoID;
  11. var scrollX = event.scrollX + hotPointInfo[i].HotPosX;
  12. var canvasNatualWidth = bodyWidth * imgNatualHeight / bodyHeight; //原始图可见区域的宽
  13. if (event.scrollX > 0) {
  14. if (hotPointInfo[i].HotPosX > canvasNatualWidth) {
  15. scrollX = event.scrollX - imgNatualWidth + hotPointInfo[i].HotPosX;
  16. }
  17. }
  18. if (event.scrollX < -hotPointInfo[i].HotPosX - hotPointInfo[i].PanImgHotName.length * fontSize) {
  19. scrollX = event.scrollX + hotPointInfo[i].HotPosX + imgNatualWidth;
  20. }
  21. ctx.beginPath();
  22. ctx.globalAlpha = 0.6;
  23. ctx.fillStyle = "black";
  24. showRoundRect(ctx, scrollX - fontSize, hotPointInfo[i].HotPosY - fontSize * 4 / 3, (hotPointInfo[i].PanImgHotName.length + 2) * fontSize, fontSize * 2, fontSize / 2);
  25. ctx.globalAlpha = 1;
  26. showText(ctx, fontSize + "px 微软雅黑, Arial", "#fff", hotPointInfo[i].PanImgHotName, scrollX, hotPointInfo[i].HotPosY);
  27. ctx.closePath();
  28. }
  29. }
  30. }
  31. $(canvas).unbind("click").click(function (e) {
  32. var mouseCoord = getMouseCoord(e);
  33. var isOnHotPoint = false;
  34. if (hotPointInfo != null) {
  35. for (var i = 0; i < hotPointInfo.length; i++) {
  36. if (hotPointInfo[i].PanImgHotType == 0) {
  37. var canvasX = hotPointInfo[i].HotPosX * bodyHeight / imgNatualHeight;
  38. var canvasY = hotPointInfo[i].HotPosY * bodyHeight / imgNatualHeight;
  39. var totalWidth = imgNatualWidth * bodyHeight / imgNatualHeight;
  40. var canvasFontSize = fontSize * bodyHeight / imgNatualHeight;
  41. if (canvasScrollX < bodyWidth - canvasX && canvasScrollX > -canvasX - hotPointInfo[i].PanImgHotName.length * canvasFontSize - 20) {
  42. var isOntheArea = detectMousePos(mouseCoord, canvasScrollX + canvasX - canvasFontSize * 2, canvasY - canvasFontSize * 2, (hotPointInfo[i].PanImgHotName.length + 4) * canvasFontSize, canvasFontSize * 4);
  43. if (isOntheArea == true) {
  44. isOnHotPoint = true;
  45. }
  46. canvasClick(isOntheArea, hotPointInfo[i].HotPanImgInfoID);
  47. } else if (canvasScrollX > -canvasX || canvasScrollX < bodyWidth - canvasX - totalWidth) {
  48. var isOntheArea;
  49. if (canvasX + canvasScrollX - totalWidth - canvasFontSize * 2 < 0) {
  50. isOntheArea = detectMousePos(mouseCoord, canvasX + canvasScrollX + totalWidth - canvasFontSize * 2, canvasY - canvasFontSize * 2, (hotPointInfo[i].PanImgHotName.length + 4) * canvasFontSize, canvasFontSize * 4);
  51. } else {
  52. isOntheArea = detectMousePos(mouseCoord, canvasX + canvasScrollX - totalWidth - canvasFontSize * 2, canvasY - canvasFontSize * 2, (hotPointInfo[i].PanImgHotName.length + 4) * canvasFontSize, canvasFontSize * 4);
  53. }
  54. if (isOntheArea == true) {
  55. isOnHotPoint = true;
  56. }
  57. canvasClick(isOntheArea, hotPointInfo[i].HotPanImgInfoID);
  58. }
  59. }
  60. }
  61. }
  62. //去除隐藏缩略图
  63. if (!isOnHotPoint) {
  64. // showOrHide();
  65. }
  66. });
  67. try {
  68. isOnLine = Virtual.checkConnectNet();
  69. } catch (e) {
  70. hideloding();
  71. }
  72. if (isOnLine == 1) {
  73. localStorage.setItem("virtualTravelInfoObj" + sceAreaId, JSON.stringify(virtualTravelInfoObj));
  74. }
  75. hideloding();
  76. });

这里如何获取点击事件呢?

将整个canvas元素绑定click事件,然后通过click事件触发的坐标来计算,需要引入以下两个方法:

  1. //获取鼠标事件的坐标
  2. function getMouseCoord(e) {
  3. var mx = 0,
  4. my = 0;
  5. if (e.layerX || e.layerX == 0) {
  6. mx = e.layerX;
  7. my = e.layerY;
  8. } else if (e.offsetX || e.offsetX == 0) {
  9. mx = e.offsetX;
  10. my = e.offsetY;
  11. }
  12. var coord = { x: mx, y: my };
  13. return coord;
  14. }
  15. //检测鼠标是否在某个区域里
  16. function detectMousePos(mouseCoord, x, y, w, h) {
  17. var isOntheArea = false;
  18. if (mouseCoord.x > x && mouseCoord.x < x + w && mouseCoord.y > y && mouseCoord.y < y + h) {
  19. isOntheArea = true;
  20. }
  21. return isOntheArea;
  22. }

宽高自适应屏幕:

在插件初始化时候传入width,height可以设置canvas的宽高:

imgEle.ddpanorama({ width: bodyWidth, height: bodyHeight });

js获取屏幕宽:screen.availWidth,屏幕高:screen.availHeight

由于在移动端屏幕顶部有信号条,还有app壳占用了一些高度,所以更好的办法是由客户端开发人员通过url参数传webview的宽和高的值给我们调用。

离线访问:通过离线缓存和本地存储结合使用来实现。

设置一个全局对象来缓存数据(一般是JSON格式),每次ajax请求的数据都缓存在该对象中,待所有数据取得后,将该对象通过JSON.stringify方法转换成字符串格式,然后存到localStorage中。

通过navigator.onLine来判断网络状态(目前测过chrome支持),但在手机中会出现无效的情况,这时候客户端提供一个接口来判断网络状态,如果是onLine,那么ajax请求数据,如果是offLine,那么从localStoage中取数据,然后通过JSON.parse方法转换为JSON格式的对象。

对于嵌在APP中的网页来说,离线缓存和本地存储都需要客户端代码的支持,不然目前会出现无效的情况,这点要注意。

安卓端360度全景图的html5实现的更多相关文章

  1. HTML5 Canvas实现360度全景图

    原文:http://blog.csdn.net/jia20003/article/details/17172571 很多购物网站现在都支持360实物全景图像,可以360度任意选择查看样品,这样 对购买 ...

  2. Three.js制作360度全景图

    这是个基于three.js的插件,预览地址:戳这里 使用方法: 1.这个插件的用法很简单,引入如下2个js <script src="js/three.min.js"> ...

  3. JS+CSS3 360度全景图插件 - Watch3D.js

    日常闲扯 从上一篇文章到这篇中间快过了一年了,时间真滴过得快.不是在下中间没想过写新的文章,而是自己确实变懒了(体重+1 +1 +1 +1....) ..OTL...不过到最后觉得还是需要写点东西,不 ...

  4. html5人物图片360度立体旋转

    体验效果:http://hovertree.com/texiao/html5/10.htm 下载:http://hovertree.com/hvtart/bjae/t16oddyt.htm 代码如下: ...

  5. 利用Canvas实现360度浏览

    前言:最近几个月来到新公司,主要从事移动端方面的开发,有时候也挺忙挺累的,于是就好一段时间没写博客了.其实自己在这几个月里,自己对canvas以及createjs和egret都有了一定程度上的认识与掌 ...

  6. 基于Three.js的360X180度全景图预览插件

    基于Three.js的360X180度全景图预览插件 时间 2015-08-12 10:01:10  HTML5中国 原文  http://www.html5cn.org/article-8621-1 ...

  7. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

    本文来自融云技术团队原创分享,原文发布于“ 融云全球互联网通信云”公众号,原题<IM 即时通讯之链路保活>,即时通讯网收录时有部分改动. 1.引言 众所周知,IM 即时通讯是一项对即时性要 ...

  8. jQuery Panorama Viewer – 360度全景展示插件

    jQuery Panorama Viewer 这款插件可以帮助你在网站中嵌入全景图片.要做到这一点,首先只需要在页面中引入最新的 jQuery 库,以及 jquery.panorama_viewer. ...

  9. 使用Javascript来创建一个响应式的超酷360度全景图片查看幻灯效果

    360度的全景图片效果常常可以用到给客户做产品展示,今天这里我们推荐一个非常不错的来自Robert Pataki的360全景幻灯实现教程,这里教程中将使用javascript来打造一个超酷的全景幻灯实 ...

随机推荐

  1. Spark on YARN的部署

    Spark on YARN的原理就是依靠yarn来调度Spark,比默认的Spark运行模式性能要好的多,前提是首先部署好hadoop HDFS并且运行在yarn上,然后就可以开始部署spark on ...

  2. java方法强制传递引用参数(做为返回值),改变被传递参数值。

    Java传递参数分为2种: 值类型,Java里面也叫简单类型,这种参数类型的传递的是它的副本拷贝: 引用类型,传递的是对象引用地址,如果在方法内改变该参数对象属性即是对原引用对象的改变:如果不想这样传 ...

  3. Lintcode 166. 链表倒数第n个节点

    ----------------------------------- 最开始的想法是先计算出链表的长度length,然后再从头走 length-n 步即是需要的位置了. AC代码: /** * De ...

  4. scp 从远程服务器上一下载文件

    scp -P202 xx3.x6.xx.xx:/usr/local/zookeeper-.zip /tmp #指定远程服务器的端口和远程服务器的目标文件 ,最后指定要下载到本的地目录 也可以从远程服务 ...

  5. Breakpad Google的crash捕获、抓取开源库

    简介: Breadpad为google chrominum项目下用于处理dump的一套工具:内部采用跨平台方式实现捕获.生成.解析与平台无关的dump,便于统一处理:支持进程内与进程外捕获,当为进程外 ...

  6. .Net中Remoting通信机制简单实例

    .Net中Remoting通信机制 前言: 本程序例子实现一个简单的Remoting通信案例 本程序采用语言:c# 编译工具:vs2013工程文件 编译环境:.net 4.0 程序模块: Test测试 ...

  7. C# 通过反射获取扩展方法

    注意,扩展方法本质上是静态方法,所以拿到MethodInfo时,应该这么调用 methodInfo.Invoke(null, new object[]{params}) static IEnumera ...

  8. 解决 U 盘写保护的问题

    插了一个 U 盘,想格式化或者创建文件,但是提示我 U 盘是写保护的. 解决方法如下: Open a command prompt type DISKPART press type LIST VOLU ...

  9. P87LPC760/61/62/64/67/68/69/78/79芯片解密单片机破解价格

    NXP恩智浦P87LPC760/61/62/64/67/68/69/78/79芯片解密单片机破解 NXP LPC700系列单片机解密型号: P87LPC759.P87LPC760.P87LPC761. ...

  10. 进击的Python【第二十章】

    1.Django请求的生命周期 路由系统 -> 试图函数(获取模板+数据=>渲染) -> 字符串返回给用户 2.路由系统 /index/ -> 函数或类.as_view() / ...