├── LICENSE ├── README.md ├── demo ├── imgs │ ├── 301_01_01_0.png │ ├── 301_01_01_0_tn.png │ ├── 301_01_01_1.png │ ├── 301_01_01_1_tn.png │ ├── 301_01_01_2.png │ ├── 301_01_01_2_tn.png │ ├── 301_01_01_3.png │ ├── 301_01_01_3_tn.png │ ├── 301_01_01_4.png │ ├── 301_01_01_4_tn.png │ ├── 301_01_01_5.png │ └── 301_01_01_5_tn.png └── index.html └── src └── htmlcubemap.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Javi Agenjo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # htmlcubemap 2 | A simple class to embed a panoramic view in a website from six pictures. 3 | It uses CSS with transforms. 4 | 5 | [Demo here](https://tamats.com/projects/htmlcubemap/demo/) 6 | 7 | ## Usage 8 | 9 | Just call from javascript: 10 | ```js 11 | var cubemap = new HTMLCubemap("imgs/301_01_01_",".png","cubemap", {low_post_url: "_tn.png", width: 512,height: 512}); 12 | ``` 13 | 14 | Where params are: 15 | - prefix to url of images 16 | - postfix of url of images 17 | - DOM container where to insert the cubemap 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/imgs/301_01_01_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_0.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_0_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_0_tn.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_1.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_1_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_1_tn.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_2.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_2_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_2_tn.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_3.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_3_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_3_tn.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_4.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_4_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_4_tn.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_5.png -------------------------------------------------------------------------------- /demo/imgs/301_01_01_5_tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jagenjo/htmlcubemap/2fbc7174c039dc1d2d648549f44617a61472e361/demo/imgs/301_01_01_5_tn.png -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 9 | -------------------------------------------------------------------------------- /src/htmlcubemap.js: -------------------------------------------------------------------------------- 1 | // Created by Javi Agenjo @tamat 2 | // https://github.com/jagenjo/htmlcubemap 3 | // Usage: var cubemap = new HTMLCubemap("imgs/301_01_01_",".png","cubemap", {low_post_url: "_tn.png", width: 512,height: 512}); 4 | 5 | function HTMLCubemap(pre_url, post_url, container_id, options) 6 | { 7 | options = options || {}; 8 | 9 | this.pitch = 0; //vertical orientation 10 | this.yaw = 0; //horizontal orientation 11 | this.speed = 0.25; //rotation velocity when dragging 12 | this.perspective = options.perspective || 300; //controls the fov 13 | 14 | this.faces = {}; 15 | this.box_size = 512; 16 | this.border_margin = 0.4; 17 | 18 | this.pre_url = pre_url; 19 | this.post_url = post_url; 20 | 21 | var root = document.createElement("div"); 22 | root.className = "htmlcubemap"; 23 | var parent = document.getElementById(container_id); 24 | if(!parent) throw("parent node not found"); 25 | parent.appendChild(root); 26 | this.root = root; 27 | var that = this; 28 | 29 | var rect = this.root.getClientRects()[0]; 30 | if(options.width) root.style.width = options.width + "px"; 31 | else root.style.width = rect.width + "px"; 32 | if(options.height) root.style.height = options.height + "px"; 33 | else root.style.height = rect.height + "px"; 34 | root.style.backgroundColor = options.backgroundColor || "black"; 35 | root.style.position = "relative"; 36 | root.style.overflow = "hidden"; 37 | 38 | root.addEventListener("mousedown",ondown); 39 | root.addEventListener("touchstart",ondown); 40 | var last_pos = [0,0]; 41 | 42 | function ondown(e) 43 | { 44 | if(e.type == "touchstart") 45 | { 46 | document.addEventListener("touchmove",onmove); 47 | document.addEventListener("touchend",onup); 48 | } 49 | else 50 | { 51 | document.body.addEventListener("mousemove",onmove); 52 | document.body.addEventListener("mouseup",onup); 53 | } 54 | 55 | var rect = that.root.getClientRects()[0]; 56 | last_pos = [ e.pageX - rect.left, e.pageY - rect.top ]; 57 | 58 | e.stopPropagation(); 59 | e.preventDefault(); 60 | return false; 61 | 62 | } 63 | 64 | function onmove(e) 65 | { 66 | 67 | var rect = that.root.getClientRects()[0]; 68 | var x = e.pageX - rect.left; 69 | var y = e.pageY - rect.top; 70 | var deltax = x - last_pos[0]; 71 | var deltay = y - last_pos[1]; 72 | 73 | that.yaw -= deltax * that.speed; 74 | that.pitch += deltay * that.speed; 75 | that.update(); 76 | 77 | last_pos = [x,y]; 78 | e.stopPropagation(); 79 | e.preventDefault(); 80 | return false; 81 | } 82 | 83 | function onup(e) 84 | { 85 | document.body.removeEventListener("mousemove",onmove); 86 | document.body.removeEventListener("mouseup",onup); 87 | document.body.removeEventListener("touchmove",onmove); 88 | document.body.removeEventListener("touchend",onup); 89 | 90 | e.stopPropagation(); 91 | e.preventDefault(); 92 | return false; 93 | } 94 | 95 | var center = document.createElement("div"); 96 | center.className = "cubemapcenter"; 97 | root.appendChild(center); 98 | this.center = center; 99 | this.center.style.transformStyle = "preserve-3d"; 100 | this.center.style.mozTransformStyle = "preserve-3d"; 101 | this.center.style.webkitTransformStyle = "preserve-3d"; 102 | this.center.style.width = "100%"; 103 | this.center.style.height = "100%"; 104 | 105 | if(pre_url && options.low_post_url) 106 | this.load( pre_url, options.low_post_url); 107 | if(pre_url && post_url) 108 | this.load( pre_url, post_url); 109 | 110 | this.update(); 111 | } 112 | 113 | HTMLCubemap.RIGHT = "0"; 114 | HTMLCubemap.LEFT = "1"; 115 | HTMLCubemap.TOP = "2"; 116 | HTMLCubemap.BOTTOM = "3"; 117 | HTMLCubemap.FRONT = "4"; 118 | HTMLCubemap.BACK = "5"; 119 | 120 | HTMLCubemap.prototype.load = function(pre_url, post_url) 121 | { 122 | this.buildFace("front",pre_url + HTMLCubemap.FRONT + post_url); 123 | this.buildFace("left",pre_url + HTMLCubemap.LEFT + post_url); 124 | this.buildFace("right",pre_url + HTMLCubemap.RIGHT + post_url); 125 | this.buildFace("top",pre_url + HTMLCubemap.TOP + post_url); 126 | this.buildFace("bottom",pre_url + HTMLCubemap.BOTTOM + post_url); 127 | this.buildFace("back",pre_url + HTMLCubemap.BACK + post_url); 128 | } 129 | 130 | HTMLCubemap.prototype.buildFace = function(face, url) 131 | { 132 | var element = document.createElement("div"); 133 | element.className = "cubemapface " + face + "face"; 134 | this.center.appendChild(element); 135 | 136 | var halfsize = this.box_size * 0.5 - this.border_margin; 137 | var transform = ""; 138 | switch(face) 139 | { 140 | case 'front': transform = "translateZ(-"+halfsize.toFixed(1)+"px) rotateY(0deg) rotateX(180deg)"; break; 141 | case 'left': transform = "translateX(-"+halfsize.toFixed(1)+"px) rotateY(90deg) rotateX(180deg)"; break; 142 | case 'right': transform = "translateX("+halfsize.toFixed(1)+"px) rotateY(-90deg) rotateX(180deg)";break; 143 | case 'top': transform = "translateY(-"+halfsize.toFixed(1)+"px) rotateX(90deg)";break; 144 | case 'bottom': transform = "translateY("+halfsize.toFixed(1)+"px) rotateX(-90deg)";break; 145 | case 'back': transform = "translateZ("+halfsize.toFixed(1)+"px) rotateX(180deg) rotateY(180deg)";break; 146 | default: throw "wrong face"; 147 | } 148 | 149 | element.style.position = "absolute"; 150 | element.style.left = "0"; 151 | element.style.top = "0"; 152 | element.style.width = this.box_size + "px"; 153 | element.style.height = this.box_size + "px"; 154 | element.style.transform = transform; 155 | element.style.mozTransform = transform; 156 | element.style.webkitTransform = transform; 157 | 158 | //create image 159 | var that = this; 160 | var img = new Image(); 161 | img.src = url; 162 | img.onload = function() { 163 | this.width = that.box_size; 164 | this.height = that.box_size; 165 | that.yaw += 0.1; //HACK: forces refresh 166 | that.update(); 167 | }; 168 | 169 | element.appendChild(img); 170 | 171 | //store 172 | if(this.faces[face]) 173 | this.faces[face].parentNode.removeChild(this.faces[face]); 174 | this.faces[face] = element; 175 | } 176 | 177 | HTMLCubemap.prototype.update = function() 178 | { 179 | var perspective = this.perspective; 180 | //perspective = 100 / Math.atan(0.0174532925 * this.fov); 181 | var distance = perspective; 182 | 183 | this.root.style.perspective = perspective.toFixed(0) + "px"; 184 | this.root.style.webkitPerspective = perspective + "px"; 185 | this.root.style.mozPerspective = perspective + "px"; 186 | 187 | var rect = this.root.getClientRects()[0]; 188 | var offsetX = (rect.width - this.box_size) * 0.5; 189 | var offsetY = (rect.height - this.box_size) * 0.5; 190 | var transform = "translateZ("+distance+"px) rotateX("+this.pitch.toFixed(1)+"deg) rotateY("+this.yaw.toFixed(1)+"deg) translateX("+offsetX+"px) translateY("+offsetY+"px)"; 191 | this.center.style.transform = transform; 192 | this.center.style.webkitTransform = transform; 193 | this.center.style.mozTransform = transform; 194 | } --------------------------------------------------------------------------------