14

I have an SVG hex grid tilted at a 45 degree angle. On individual hexes, I would like to place images (represented by the red rectangles) that appear to be standing upright respective to the plane of the grid. The images/rectangles don't necessarily have to be at a full 90 degrees, but I'm having the hardest time getting them to have any perspective that is even a little different from the plane.

Is there a way to unset the perspective for child elements or rework the CSS transforms somehow to make this look right?

Code

.display {
    animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    -webkit-animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    background: #000;
    display: block;
    border-left: 0.25rem solid #000;
    border-right: 0.25rem solid #000;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    height: 480px;
    overflow: hidden;
    width: 1096px;
}
#hexGrid {
    box-sizing: border-box;
    -moz-box-sizing: border-box;    
    display: block;
    height: 100%;
    -webkit-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6); 
    -moz-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);    
    -ms-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6); 
    -o-transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);  
    transform: perspective(44vw) rotateX(45deg) scale3d(1.6, 1.6, 1.6);
    transform-style: preserve-3d;
    width: 100%;
}
.hexContainer {
    outline: none;
    transform-style: preserve-3d;
}
.hex {
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    display: inline-block;
    height: 4.4vmin;
    opacity: 1;
    outline: none;
    position: relative;
    stroke: #0CF;
    stroke-width: 0.0625rem;
    transform: scale3d(1, 1, 1);
    transition: all linear 300ms;
    width: 8vmin;
}
.hex.open {
    fill: rgba(0, 204, 255, 0.3);
}
.hex.blocked {
    fill: url(#blockedHexPattern);
    fill-opacity: 0.3;
}
.hexContainer:focus .open, .hexContainer:hover .open {
    cursor: pointer;
    fill: rgba(0, 204, 255, 0.8);
    outline: none;
}
.hexContainer:focus .blocked, .hexContainer:hover .blocked {
    cursor: pointer;
    fill: url(#blockedHexPattern);
    fill-opacity: 1;
    outline: none;
}
.hexContainer:focus .occupied, .hexContainer:hover .occupied {
    cursor: pointer;
    fill: rgba(50, 50, 50, 0.8);
    outline: none;
}
.hexContainer:focus .open, .hexContainer:focus .open.unblock {
    transform-origin: 50% 0%;
}
.hexContainer:focus .blocked {
    opacity: 1; 
    transform-origin: 50% 0%;
}
.hexContainer.active .open {
    fill: rgba(0, 204, 255, 0.8);
    opacity: 1; 
}
#blockedHexPattern line {
    stroke: #0CF;
    stroke-width: 0.0625rem;
}
#hexGrid .rect {
    transform: rotateX(0deg);   
}
<div id="stationMap" class="display">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="55 -30 360 360" id="hexGrid">
    <defs>
        <pattern x="0" y="0" height="10" width="10" patternUnits="userSpaceOnUse" id="blockedHexPattern">
            <line x1="0" y1="10" x2="10" y2="0"></line>
        </pattern>
    </defs>
    <a id="hex0-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,45 55.98076211353316,60 30,45 30.000000000000004,14.999999999999996 55.98076211353315,0 81.96152422706632,14.999999999999986"></polygon>
    </a>
    <a id="hex0-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,45 159.9038105676658,60 133.92304845413264,45 133.92304845413264,14.999999999999996 159.9038105676658,0 185.88457268119896,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex0-6" class="hexContainer">
        <polygon class="hex blocked" points="393.7306695894642,45 367.749907475931,60 341.76914536239786,45 341.76914536239786,14.999999999999996 367.749907475931,0 393.7306695894642,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex0-7" class="hexContainer">
        <polygon class="hex blocked" points="445.6921938165305,45 419.71143170299734,60 393.7306695894642,45 393.7306695894642,14.999999999999996 419.71143170299734,0 445.6921938165305,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex1-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,90 30.000000000000004,105 4.01923788646684,90 4.019237886466843,60 29.999999999999993,45 55.98076211353315,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="5" y="67.5" width="50" height="40"/>
    </a>
    <a id="hex1-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,90 185.88457268119893,105 159.90381056766577,90 159.90381056766577,60 185.88457268119893,45 211.8653347947321,59.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex1-4" class="hexContainer">
        <polygon class="hex open" points="263.82685902179844,90 237.84609690826525,105 211.8653347947321,90 211.8653347947321,60 237.84609690826525,45 263.8268590217984,59.999999999999986"></polygon>
    </a>
    <a id="hex1-5" class="hexContainer">
        <polygon class="hex open" points="315.7883832488647,90 289.80762113533154,105 263.8268590217984,90 263.8268590217984,60 289.80762113533154,45 315.7883832488647,59.999999999999986"></polygon>
    </a>
    <a id="hex1-6" class="hexContainer">
        <polygon class="hex open" points="367.749907475931,90 341.76914536239786,105 315.7883832488647,90 315.7883832488647,60 341.76914536239786,45 367.749907475931,59.999999999999986"></polygon>
    </a>
    <a id="hex1-7" class="hexContainer">
        <polygon class="hex open" points="419.71143170299734,90 393.7306695894642,105 367.749907475931,90 367.749907475931,60 393.7306695894642,45 419.71143170299734,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="369" y="67.5" width="50" height="40"/>
    </a>
    <a id="hex2-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,134.99999999999997 55.98076211353316,150 30,134.99999999999997 30.000000000000004,104.99999999999999 55.98076211353315,89.99999999999999 81.96152422706632,104.99999999999997"></polygon>
    </a>
    <a id="hex2-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,134.99999999999997 159.9038105676658,150 133.92304845413264,134.99999999999997 133.92304845413264,104.99999999999999 159.9038105676658,89.99999999999999 185.88457268119896,104.99999999999997" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex2-3" class="hexContainer">
        <polygon class="hex open" points="237.84609690826525,134.99999999999997 211.8653347947321,150 185.88457268119893,134.99999999999997 185.88457268119893,104.99999999999999 211.8653347947321,89.99999999999999 237.84609690826525,104.99999999999997"></polygon>
    </a>
    <a id="hex2-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,134.99999999999997 263.8268590217984,150 237.84609690826522,134.99999999999997 237.84609690826522,104.99999999999999 263.8268590217984,89.99999999999999 289.80762113533154,104.99999999999997"></polygon>
    </a>
    <a id="hex2-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,134.99999999999997 315.7883832488647,150 289.80762113533154,134.99999999999997 289.80762113533154,104.99999999999999 315.7883832488647,89.99999999999999 341.76914536239786,104.99999999999997"></polygon>
    </a>
    <a id="hex2-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,134.99999999999997 367.749907475931,150 341.76914536239786,134.99999999999997 341.76914536239786,104.99999999999999 367.749907475931,89.99999999999999 393.7306695894642,104.99999999999997"></polygon>
    </a>
    <a id="hex2-7" class="hexContainer">
        <polygon class="hex open" points="445.6921938165305,134.99999999999997 419.71143170299734,150 393.7306695894642,134.99999999999997 393.7306695894642,104.99999999999999 419.71143170299734,89.99999999999999 445.6921938165305,104.99999999999997"></polygon>
    </a>
    <a id="hex3-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,179.99999999999997 30.000000000000004,194.99999999999997 4.01923788646684,179.99999999999997 4.019237886466843,149.99999999999997 29.999999999999993,134.99999999999997 55.98076211353315,149.99999999999994"></polygon>
    </a>
    <a id="hex3-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,179.99999999999997 185.88457268119893,194.99999999999997 159.90381056766577,179.99999999999997 159.90381056766577,149.99999999999997 185.88457268119893,134.99999999999997 211.8653347947321,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex3-5" class="hexContainer">
        <polygon class="hex blocked" points="315.7883832488647,179.99999999999997 289.80762113533154,194.99999999999997 263.8268590217984,179.99999999999997 263.8268590217984,149.99999999999997 289.80762113533154,134.99999999999997 315.7883832488647,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex3-7" class="hexContainer">
        <polygon class="hex blocked" points="419.71143170299734,179.99999999999997 393.7306695894642,194.99999999999997 367.749907475931,179.99999999999997 367.749907475931,149.99999999999997 393.7306695894642,134.99999999999997 419.71143170299734,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,224.99999999999997 55.98076211353316,239.99999999999997 30,224.99999999999997 30.000000000000004,194.99999999999997 55.98076211353315,179.99999999999997 81.96152422706632,194.99999999999994"></polygon>
    </a>
    <a id="hex4-1" class="hexContainer">
        <polygon class="hex blocked" points="133.92304845413264,224.99999999999997 107.94228634059948,239.99999999999997 81.96152422706632,224.99999999999997 81.96152422706632,194.99999999999997 107.94228634059948,179.99999999999997 133.92304845413264,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,224.99999999999997 159.9038105676658,239.99999999999997 133.92304845413264,224.99999999999997 133.92304845413264,194.99999999999997 159.9038105676658,179.99999999999997 185.88457268119896,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-3" class="hexContainer">
        <polygon class="hex blocked" points="237.84609690826525,224.99999999999997 211.8653347947321,239.99999999999997 185.88457268119893,224.99999999999997 185.88457268119893,194.99999999999997 211.8653347947321,179.99999999999997 237.84609690826525,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
    <a id="hex4-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,224.99999999999997 263.8268590217984,239.99999999999997 237.84609690826522,224.99999999999997 237.84609690826522,194.99999999999997 263.8268590217984,179.99999999999997 289.80762113533154,194.99999999999994"></polygon>
    </a>
    <a id="hex4-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,224.99999999999997 315.7883832488647,239.99999999999997 289.80762113533154,224.99999999999997 289.80762113533154,194.99999999999997 315.7883832488647,179.99999999999997 341.76914536239786,194.99999999999994"></polygon>
    </a>
    <a id="hex4-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,224.99999999999997 367.749907475931,239.99999999999997 341.76914536239786,224.99999999999997 341.76914536239786,194.99999999999997 367.749907475931,179.99999999999997 393.7306695894642,194.99999999999994"></polygon>
    </a>
</svg>
</div>
web-tiki
  • 99,765
  • 32
  • 217
  • 249
VirtuosiMedia
  • 52,016
  • 21
  • 93
  • 140
  • 1
    Unfortunately, there's no (easy) way to reset the the child elements. When you transform an svg, you also transform it's entire coordinate system. You might be able to do some matrix math to undo the transform of the coordinate system for the red squares but then they would no longer line up. There may be some advanced matrix transform you could do, but at a certain point it may be easier to use a real 3d engine like three.js (http://threejs.org/) which is built to do what you want. – Rob Louie Oct 22 '15 at 22:32
  • @RobLouie I'm "kind of" fixing it right now using CSS transforms on the child elements, specifically skewX and translate, but it's really touchy, it requires different transforms for each browser, and I have to adjust the content for each hex individually by eye. Ideally, I'd like something a little more robust than that, but I'm afraid you may be right. – VirtuosiMedia Oct 23 '15 at 05:56

3 Answers3

6

As 3d transforms can't be handled properly on svg elements, I would suggest a different approach for the grid of hexagons. It can be achieved with plain html and css as shown in this question : Responsive grid of hexagons.

This allows to make 3d transforms on child elements with the transform-style property.

Adapted to your use case, it can look like this :

DEMO

body{
  background:rgb(123, 158, 158);
  perspective:500px;
}
#categories{
  width:70%;
  margin:0 auto;
  transform:rotateX(45deg);
  transform-style: preserve-3d;
}
#categories:after{
  content:"";
  display:block;
  clear:both;
}
#categories li{
  position:relative;
  list-style-type:none;
  width:17.364%; /* = (100-4.5) / 5.5 */
  padding-bottom: 20.05%; /* =  width /0.866 */
  float:left;
  overflow:hidden;
  visibility:hidden;  
  transform: rotate(-60deg) skewY(30deg);
}

#categories li:nth-child(10n+6), #categories li:nth-child(10n+7), #categories li:nth-child(10n+8), #categories li:nth-child(10n+9), #categories li:nth-child(10n+10) {
    margin-top: -4.2%;
    margin-bottom: -4.2%;
    transform: translateX(50%) rotate(-60deg) skewY(30deg);
  }
#categories li:nth-child(10n+6){
    margin-left:0.5%;
  }
  #categories li:nth-child(5n+2) {
    margin-left:1%;
    margin-right:1%;
  }
  #categories li:nth-child(5n+3),#categories li:nth-child(5n+4){
    margin-right:1%;
  }

#categories li div{
  position:absolute;
  visibility:visible;
  width:100%; height:100%;
  text-align:center;
  color:#fff;
  overflow:hidden;  
  transform: skewY(-30deg) rotate(60deg);
  background-color:rgba(0,0,0,.2);
  transition:background-color .3s;
  border-left:2px solid #000;  
  border-right:2px solid #000;
  box-sizing:border-box;
  -webkit-backface-visibility:hidden;
}
#categories li div:hover, #categories .up:hover span:after{
  background-color:rgba(0,0,0,.5);
}
#categories li div:before, #categories li div:after{
  content:'';
  position:absolute;
  width:100%;height:49.6%;
  left:-2px;top:25.5%;
  
  border-left:2px solid #000;
  border-right:2px solid #000;
  transform:rotate(60deg);
  visibility:visible;
}
#categories li div:before{
    transform:rotate(-60deg);
}

#categories li img{
  display:block;
  left:-100%; right:-100%;
  width: auto; height:100%;
  margin:0 auto;
  visibility:visible;
}
#categories .up, #categories .up div{
  transform-style:preserve-3d;
  overflow:visible;
  visibility:hidden;
  background-color:transparent;
}
#categories .up span{
  display:block;
  width:100%;height:100%;
  position:absolute;
  top:0; left:0;
  overflow:hidden;
}
#categories .up span:after{
  content:'';
  position:absolute;
  left:0;top:0;
  width:100%;height:100%;
  border-left:2px solid #000;
  border-right:2px solid #000;
  box-sizing:border-box;
  background-color:rgba(0,0,0,.2);
  transform: skewY(-30deg) rotate(60deg);
  transition:background-color .3s;
  visibility:visible;
}

#categories .up img{
  width:100%; height:auto;
  position:absolute;
  transform-origin: 50% 100%;
  transform: rotateX(-45deg);
  z-index:1;
}
<ul id="categories" class="clr">
   <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt=""/></div></li>
  <li><div></div></li>  
  <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt=""/></div></li>
  <li class="pusher"></li>
  <li class="pusher"></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li><div></div></li>
  <li><div></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li class="up"><span></span><div><img src="https://farm5.staticflickr.com/4144/5053682635_b348b24698.jpg" alt=""/></div></li>
  <li class="pusher"></li>
  <li><div></div></li>
  <li><div></div></li>
</ul>

This grid of hexagons can be adapted to several use cases (number of hexagons per row, hexagon alignment...) more examples in this collection : Responsive grids of hexagons

Community
  • 1
  • 1
web-tiki
  • 99,765
  • 32
  • 217
  • 249
  • Unfortunately this doesn't work for my use case. I need the hexagons to appear as they do in my example with the border and I also need the images to stand up from the angled plane (yours are parallel with the plane). – VirtuosiMedia Oct 23 '15 at 13:06
  • @VirtuosiMedia I see what you mean. I tweaked the answer and the images are now standing up from the angled panel. If this suits you, I'll find a solution for the hexagon borders. – web-tiki Oct 23 '15 at 13:25
  • It's closer, but I can't quite tell in your example if the perspective is the same as there aren't enough rows/columns. Also, the images would need to be inside the same container as a hex, with both appearing at the same time. – VirtuosiMedia Oct 23 '15 at 13:38
  • @VirtuosiMedia I added a few rows/columns here for the perspective : http://codepen.io/web-tiki/pen/WQMyyZ – web-tiki Oct 23 '15 at 14:00
  • Perspective looks fine on the codepen, but the borders and images and hexes in the same container would still be needed. Also, the hexes would have a semi-transparent background color, not a background image, which would make a difference on the borders showing through. I did previously try this method previously, but wasn't able to make it work. – VirtuosiMedia Oct 23 '15 at 15:04
  • @VirtuosiMedia what browsers do you need to support? I also updated the answer with transparent hexagons instead of images. – web-tiki Oct 23 '15 at 17:09
  • IE11+, Edge, Firefox, Chrome, Safari. If you're able to get the borders on this cleanly with CSS (not an image) and I'm able to adapt it successfully, I'll be more than happy to award the bounty to you. – VirtuosiMedia Oct 23 '15 at 18:33
  • @VirtuosiMedia I edited the pen and answer with borders. – web-tiki Oct 24 '15 at 12:29
  • 2
    Very impressive! Thanks for the time you've put in. It looks like it works everywhere so far except IE. If that can be resolved, I'll go this route, which also has better keyboard support than SVG. My alternative solution to yours is to get the hex's position and absolutely position the image over the hex with JavaScript. That method works, but it ruins hover states, responsiveness, and keyboard support, so I would much prefer this if it can also work in IE. – VirtuosiMedia Oct 24 '15 at 13:38
  • @VirtuosiMedia Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93248/discussion-between-web-tiki-and-virtuosimedia). – web-tiki Oct 24 '15 at 13:48
  • I'm going to mark this as the accepted answer so you get full credit. It's not quite where I need it to be yet because of the IE requirement, but it's the closest and it solves a few other issues I'm having with the SVG implementation. I'm hoping that I can get it there on IE as well. Thanks for your help! – VirtuosiMedia Oct 28 '15 at 08:07
1

Since handling 3d transform on SVGElements is a problem a solution could be creating another overlapping element for adding the transformed elements;

the hardest thing in this solution is finding the values for optimal rendering;

apart from removing the perspective in #hexGrid transform property (CSS) the markup should be the same as in the original question , all the work is done through JS .

//function for checking transform property in css
function checkCSS(selector,prop){
    var sel;
    [].slice.call(document.styleSheets).forEach(function(x){
        sel= [].slice.call(x.rules).filter(function(rule){
            return rule.selectorText=='#hexGrid';
        })
        return sel
    })
    return sel[sel.length-1].style[prop]
    
}
//store transform property
var storeTrans = checkCSS('#hexGrid','transform');

//straighten svg
var hexGrid = document.getElementById('hexGrid');
hexGrid.style.transform = 'rotateX(0)';

//get the position/dimensions for perfectly tilted red squares
var rects=document.querySelectorAll('rect');
var coorArray = [].slice.call(rects).map(function(x){return x.getBoundingClientRect()})



var stationMap = document.getElementById('stationMap');
//create element for creating an layer and append
var container = document.createElement('div');
container.className='container';
container.style.perspective='33vW';//reduced for simulating foreground
container.style.height=container.style.width =  '100%';
container.style.transform='translateY(-100%) rotateX(45deg) scale(1.6)';
stationMap.appendChild(container);

//create perfectly tilted red squares
coorArray.forEach(function(x){
   
var el = document.createElement('div')
el.style.position='absolute';
el.style.top= x.top+'px';
el.style.left=x.left+'px';
el.style.width= x.width+'px';
el.style.height= x.height+'px';
el.style.background= 'tomato';
el.style.transform='perspective(12vw) rotateX(130deg) translate3d(-15%, 50%,0)';

container.appendChild(el)
})



//set prosperctive and transform-style on common parent node
stationMap.style.transformStyle='preserve-3d';
stationMap.style.perspective='44vw';
//set transform value back and rip out old rect
hexGrid.style.transform = storeTrans;
Array.prototype.slice.call(rects).forEach(function(n){
    n.parentNode.removeChild(n)
})
.display {
    animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    -webkit-animation: displayFlicker 100ms cubic-bezier(.37, 0, .41, 1.74) 100ms 1 normal forwards;
    background: #000;
    display: block;
    border-left: 0.25rem solid #000;
    border-right: 0.25rem solid #000;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    height: 480px;
    overflow: hidden;
    width: 1096px;
}
#hexGrid {
    box-sizing: border-box;
    -moz-box-sizing: border-box;    
    display: block;
    height: 100%;
    -webkit-transform:  rotateX(45deg) scale3d(1.6, 1.6, 1.6); /*add perspective to parent*/
    -moz-transform:  rotateX(45deg) scale3d(1.6, 1.6, 1.6);    
    -ms-transform: rotateX(45deg) scale3d(1.6, 1.6, 1.6); 
    -o-transform:rotateX(45deg) scale3d(1.6, 1.6, 1.6);  
    transform:  rotateX(45deg) scale3d(1.6, 1.6, 1.6);
    transform-style: preserve-3d;
    width: 100%;
}
.hexContainer {
    outline: none;
    transform-style: preserve-3d;
}
.hex {
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    display: inline-block;
    height: 4.4vmin;
    opacity: 1;
    outline: none;
    position: relative;
    stroke: #0CF;
    stroke-width: 0.0625rem;
    transform: scale3d(1, 1, 1);
    transition: all linear 300ms;
    width: 8vmin;
}
.hex.open {
    fill: rgba(0, 204, 255, 0.3);
}
.hex.blocked {
    fill: url(#blockedHexPattern);
    fill-opacity: 0.3;
}
.hexContainer:focus .open, .hexContainer:hover .open {
    cursor: pointer;
    fill: rgba(0, 204, 255, 0.8);
    outline: none;
}
.hexContainer:focus .blocked, .hexContainer:hover .blocked {
    cursor: pointer;
    fill: url(#blockedHexPattern);
    fill-opacity: 1;
    outline: none;
}
.hexContainer:focus .occupied, .hexContainer:hover .occupied {
    cursor: pointer;
    fill: rgba(50, 50, 50, 0.8);
    outline: none;
}
.hexContainer:focus .open, .hexContainer:focus .open.unblock {
    transform-origin: 50% 0%;
}
.hexContainer:focus .blocked {
    opacity: 1; 
    transform-origin: 50% 0%;
}
.hexContainer.active .open {
    fill: rgba(0, 204, 255, 0.8);
    opacity: 1; 
}
#blockedHexPattern line {
    stroke: #0CF;
    stroke-width: 0.0625rem;
}
#hexGrid .rect {
    transform: rotateX(0deg);   
}
<div id="stationMap" class="display">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="55 -30 360 360" id="hexGrid">
        <defs>
            <pattern x="0" y="0" height="10" width="10" patternUnits="userSpaceOnUse" id="blockedHexPattern">
                <line x1="0" y1="10" x2="10" y2="0"></line>
            </pattern>
        </defs> <a id="hex0-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,45 55.98076211353316,60 30,45 30.000000000000004,14.999999999999996 55.98076211353315,0 81.96152422706632,14.999999999999986"></polygon>
    </a>
 <a id="hex0-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,45 159.9038105676658,60 133.92304845413264,45 133.92304845413264,14.999999999999996 159.9038105676658,0 185.88457268119896,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex0-6" class="hexContainer">
        <polygon class="hex blocked" points="393.7306695894642,45 367.749907475931,60 341.76914536239786,45 341.76914536239786,14.999999999999996 367.749907475931,0 393.7306695894642,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex0-7" class="hexContainer">
        <polygon class="hex blocked" points="445.6921938165305,45 419.71143170299734,60 393.7306695894642,45 393.7306695894642,14.999999999999996 419.71143170299734,0 445.6921938165305,14.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex1-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,90 30.000000000000004,105 4.01923788646684,90 4.019237886466843,60 29.999999999999993,45 55.98076211353315,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="5" y="67.5" width="50" height="40"/>
    </a>
 <a id="hex1-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,90 185.88457268119893,105 159.90381056766577,90 159.90381056766577,60 185.88457268119893,45 211.8653347947321,59.999999999999986" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex1-4" class="hexContainer">
        <polygon class="hex open" points="263.82685902179844,90 237.84609690826525,105 211.8653347947321,90 211.8653347947321,60 237.84609690826525,45 263.8268590217984,59.999999999999986"></polygon>
    </a>
 <a id="hex1-5" class="hexContainer">
        <polygon class="hex open" points="315.7883832488647,90 289.80762113533154,105 263.8268590217984,90 263.8268590217984,60 289.80762113533154,45 315.7883832488647,59.999999999999986"></polygon>
    </a>
 <a id="hex1-6" class="hexContainer">
        <polygon class="hex open" points="367.749907475931,90 341.76914536239786,105 315.7883832488647,90 315.7883832488647,60 341.76914536239786,45 367.749907475931,59.999999999999986"></polygon>
    </a>
 <a id="hex1-7" class="hexContainer">
        <polygon class="hex open" points="419.71143170299734,90 393.7306695894642,105 367.749907475931,90 367.749907475931,60 393.7306695894642,45 419.71143170299734,59.999999999999986"></polygon>
        <rect class="rect" fill="red" x="369" y="67.5" width="50" height="40"/>
    </a>
 <a id="hex2-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,134.99999999999997 55.98076211353316,150 30,134.99999999999997 30.000000000000004,104.99999999999999 55.98076211353315,89.99999999999999 81.96152422706632,104.99999999999997"></polygon>
    </a>
 <a id="hex2-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,134.99999999999997 159.9038105676658,150 133.92304845413264,134.99999999999997 133.92304845413264,104.99999999999999 159.9038105676658,89.99999999999999 185.88457268119896,104.99999999999997" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex2-3" class="hexContainer">
        <polygon class="hex open" points="237.84609690826525,134.99999999999997 211.8653347947321,150 185.88457268119893,134.99999999999997 185.88457268119893,104.99999999999999 211.8653347947321,89.99999999999999 237.84609690826525,104.99999999999997"></polygon>
    </a>
 <a id="hex2-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,134.99999999999997 263.8268590217984,150 237.84609690826522,134.99999999999997 237.84609690826522,104.99999999999999 263.8268590217984,89.99999999999999 289.80762113533154,104.99999999999997"></polygon>
    </a>
 <a id="hex2-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,134.99999999999997 315.7883832488647,150 289.80762113533154,134.99999999999997 289.80762113533154,104.99999999999999 315.7883832488647,89.99999999999999 341.76914536239786,104.99999999999997"></polygon>
    </a>
 <a id="hex2-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,134.99999999999997 367.749907475931,150 341.76914536239786,134.99999999999997 341.76914536239786,104.99999999999999 367.749907475931,89.99999999999999 393.7306695894642,104.99999999999997"></polygon>
    </a>
 <a id="hex2-7" class="hexContainer">
        <polygon class="hex open" points="445.6921938165305,134.99999999999997 419.71143170299734,150 393.7306695894642,134.99999999999997 393.7306695894642,104.99999999999999 419.71143170299734,89.99999999999999 445.6921938165305,104.99999999999997"></polygon>
    </a>
 <a id="hex3-0" class="hexContainer">
        <polygon class="hex open" points="55.98076211353316,179.99999999999997 30.000000000000004,194.99999999999997 4.01923788646684,179.99999999999997 4.019237886466843,149.99999999999997 29.999999999999993,134.99999999999997 55.98076211353315,149.99999999999994"></polygon>
    </a>
 <a id="hex3-3" class="hexContainer">
        <polygon class="hex blocked" points="211.8653347947321,179.99999999999997 185.88457268119893,194.99999999999997 159.90381056766577,179.99999999999997 159.90381056766577,149.99999999999997 185.88457268119893,134.99999999999997 211.8653347947321,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex3-5" class="hexContainer">
        <polygon class="hex blocked" points="315.7883832488647,179.99999999999997 289.80762113533154,194.99999999999997 263.8268590217984,179.99999999999997 263.8268590217984,149.99999999999997 289.80762113533154,134.99999999999997 315.7883832488647,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex3-7" class="hexContainer">
        <polygon class="hex blocked" points="419.71143170299734,179.99999999999997 393.7306695894642,194.99999999999997 367.749907475931,179.99999999999997 367.749907475931,149.99999999999997 393.7306695894642,134.99999999999997 419.71143170299734,149.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex4-0" class="hexContainer">
        <polygon class="hex open" points="81.96152422706632,224.99999999999997 55.98076211353316,239.99999999999997 30,224.99999999999997 30.000000000000004,194.99999999999997 55.98076211353315,179.99999999999997 81.96152422706632,194.99999999999994"></polygon>
    </a>
 <a id="hex4-1" class="hexContainer">
        <polygon class="hex blocked" points="133.92304845413264,224.99999999999997 107.94228634059948,239.99999999999997 81.96152422706632,224.99999999999997 81.96152422706632,194.99999999999997 107.94228634059948,179.99999999999997 133.92304845413264,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex4-2" class="hexContainer">
        <polygon class="hex blocked" points="185.88457268119896,224.99999999999997 159.9038105676658,239.99999999999997 133.92304845413264,224.99999999999997 133.92304845413264,194.99999999999997 159.9038105676658,179.99999999999997 185.88457268119896,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex4-3" class="hexContainer">
        <polygon class="hex blocked" points="237.84609690826525,224.99999999999997 211.8653347947321,239.99999999999997 185.88457268119893,224.99999999999997 185.88457268119893,194.99999999999997 211.8653347947321,179.99999999999997 237.84609690826525,194.99999999999994" fill="url(#blockedHexPattern)"></polygon>
    </a>
 <a id="hex4-4" class="hexContainer">
        <polygon class="hex open" points="289.80762113533154,224.99999999999997 263.8268590217984,239.99999999999997 237.84609690826522,224.99999999999997 237.84609690826522,194.99999999999997 263.8268590217984,179.99999999999997 289.80762113533154,194.99999999999994"></polygon>
    </a>
 <a id="hex4-5" class="hexContainer">
        <polygon class="hex open" points="341.76914536239786,224.99999999999997 315.7883832488647,239.99999999999997 289.80762113533154,224.99999999999997 289.80762113533154,194.99999999999997 315.7883832488647,179.99999999999997 341.76914536239786,194.99999999999994"></polygon>
    </a>
 <a id="hex4-6" class="hexContainer">
        <polygon class="hex open" points="393.7306695894642,224.99999999999997 367.749907475931,239.99999999999997 341.76914536239786,224.99999999999997 341.76914536239786,194.99999999999997 367.749907475931,179.99999999999997 393.7306695894642,194.99999999999994"></polygon>
    </a>

    </svg>
</div>

fiddle

Summarizing :

  1. we tilt the svg-element to it's normal position;

  2. get the coordinates of where the images/boxes are placed in a non transformed scenario;

  3. create a new element of same dimensions appended underneath svg layer;

  4. make elements to replace images boxes on new element (using coordinates taken from point-2);

  5. transform new element adding translateY(-100%) as first value so it will overlap svg;

  6. transform svg element to same values of added element (clearly without translateY(-100%)).


To keep the hover effect on svg elements we could play with stacking contents (but it is limited - example).

Tested only on latest chrome - missing any other browser support .

maioman
  • 18,154
  • 4
  • 36
  • 42
0

SVG doesn't yet support 3D transforms; even if you can transform your .hexGrid svg element (which is still in the html context and therefore accepts the 3D transform), its content will lay flat inside it, there's no transform-style that will reverse this behavior.

Your best bet would be to have each hexagon as its own SVG element so they can be transformed in 3D separately. Something like:

<div class="hexGrid" style="{3d transform}">
    <svg class="hex" style="{reversed 3d transform}">
        <polygon />
        <rect />
    </svg>
    <svg class="hex">
        ...
    </svg>
</div>

You're also mixing HTML tags with SVG tags: <a> doesn't exist in SVG. You can use the xlink:href attribute on any element.

fregante
  • 29,050
  • 14
  • 119
  • 159