eNzGWG ('-' * 6)
Forked from Derek Kolluri's Pen VLjZBo.
A Pen by Kris Dages on CodePen.
eNzGWG ('-' * 6)
Forked from Derek Kolluri's Pen VLjZBo.
A Pen by Kris Dages on CodePen.
<div ng-app="myApp" ng-controller="Ctrl as m" ng-model-options="{ debounce: 500 }" class="root"> | |
<div class="frame"> | |
<div class="panel" ng-style="m.transformStyle"> | |
<div class="panel-front"> | |
<h5>Rotate, deg</h5> X | |
<input type="number" ng-model="m.rotateX"> Y | |
<input type="number" ng-model="m.rotateY"> Z | |
<input type="number" ng-model="m.rotateZ"> | |
<h5>Translate, px</h5> X | |
<input type="number" ng-model="m.translate.x"> Y | |
<input type="number" ng-model="m.translate.y"> Z | |
<input type="number" ng-model="m.translate.z"> | |
<table> | |
<tr> | |
<th>Transition,s</th> | |
<th>Perspective, px</th> | |
</tr> | |
<tr> | |
<td> | |
<input type=number ng-model="m.transition"> | |
</td> | |
<td> | |
<input type=number ng-model="m.perspective"> | |
</td> | |
</tr> | |
</table> | |
</div> | |
<div class="panel-back"> | |
<h5>Background Color</h5> | |
</div> | |
</div> | |
<div class=controls> | |
<h1>La Mala Educacion</h1> | |
<ui-select ng-model="m.activeWinder" theme="bootstrap" style="width: 300px;"> | |
<ui-select-match placeholder="Select a property">{{$select.selected.name}}</ui-select-match> | |
<ui-select-choices repeat="winder in m.winders track by $index" refresh-delay="0"> | |
<div style="width:100%, height:100px;">{{winder.name}}</div> | |
</ui-select-choices> | |
</ui-select> | |
<button class="btn btn-primary" ng-click="m.windUp()">wind me up</button> <button class="btn btn-primary" ng-click="m.windDown()">wind me down</button> | |
<button class="btn btn-default" ng-click="m.unwind()">volver</button> | |
</div> | |
</div> | |
</div> |
'use strict'; | |
class Winder { | |
constructor(name, windUp, windDown, unwind) { | |
Object.assign(this, { name, windUp,windDown, unwind }); | |
} | |
} | |
class PropWinder extends Winder { | |
constructor(name, prop, upAmt, unwindAmt) { | |
super(name, | |
c => c[prop] += upAmt, | |
c => c[prop] -= (upAmt/2), | |
c => c[prop] = unwindAmt | |
); | |
} | |
} | |
class SpinWinder extends PropWinder { | |
constructor(axis) { | |
super("spin" + axis, "rotate" +axis, 30,0); | |
} | |
} | |
class MoveWinder extends PropWinder { | |
constructor(axis) { | |
super("move" + axis, "translate" +axis, 50,0); | |
} | |
} | |
class Ctrl{ | |
constructor() { | |
Object.assign(this, { | |
rotateX: 0, | |
rotateY: 0, | |
rotateZ: 0, | |
translateX: 0, translateY: 0, translateZ: 0, | |
transition: 0.5, | |
perspective: 400, | |
backgroundColor: { | |
hue: 180, | |
saturation: 50, | |
lightness: 50, | |
alpha: 1.0 | |
}, | |
winders: [ | |
new SpinWinder('Y'),new SpinWinder('X'), new SpinWinder('Z'), | |
new MoveWinder('X'),new MoveWinder('Y'),new MoveWinder('Z'), | |
new PropWinder("perspective","perspective", | |
100,400) | |
] | |
}); | |
} | |
get activeWinder() { | |
return this._activeWinder || this.winders[0]; | |
} | |
set activeWinder(val) { | |
this._activeWinder = val; | |
} | |
get transformStyle() { | |
var fmtPerspective = `perspective(${this.perspective || 400}px)`; | |
var fmtRotate = `rotateX(${this.rotateX || 0 }deg) rotateY(${this.rotateY || 0}deg) rotateZ(${this.rotateZ || 0}deg)`; | |
var fmtTranslate = `translate3d(${this.translateX || 0}px,${this.translateY || 0}px,${this.translateZ || 0}px)`; | |
//the instructions for ngStyle say to return an object '{}' | |
//with keys and value for each CSS property you want to bind. | |
return { | |
transform: `${fmtPerspective} ${fmtRotate} ${fmtTranslate}`, | |
transition: `${this.transition}s` | |
} | |
} | |
windUp() { | |
this.activeWinder.windUp(this); | |
} | |
windDown() { | |
this.activeWinder.windDown(this); | |
} | |
unwind() { | |
this.winders.forEach(w=>w.unwind(this)); | |
} | |
} | |
angular.module("myApp",['ui.select']) | |
.controller("Ctrl", Ctrl) | |
.config(function(uiSelectConfig) { | |
uiSelectConfig.theme = 'bootstrap'; | |
uiSelectConfig.searchEnabled = false; | |
}); | |
h5, th {font-size: 1.25rem; font-weight: | |
500; line-height:1.1 } | |
th { padding-top:15px;padding-bottom: 10px; | |
width:50%; | |
} | |
div { box-sizing: border-box;} | |
.root { | |
display:flex; | |
align-items:center;; | |
justify-content: center; | |
height:100vh; | |
} | |
input[type="number"] { | |
width: 50px; | |
} | |
.controls { position: fixed; top:25px; left:25px;} | |
.frame { | |
width: 250px; | |
height: 250px; | |
position: relative; | |
border-radius: 25px; | |
border: 1px dashed #AAAAAA; | |
} | |
.panel { | |
position: absolute; | |
top: -1px;left: -1px; | |
width: 250px; | |
height: 250px; | |
border: 1px solid; | |
border-radius:25px; | |
box-shadow: 0px 1px 3px 1px rgba(0,0,0,0.3); | |
} | |
.btn { margin-top: 15px; } | |
.panel-front { | |
position: fixed;top:0;left:0; | |
width:100%;height:100%; | |
// border: 1px solid; | |
border-radius: 25px; | |
background-clip: padding-box; | |
padding: 15px; | |
background: hsla(45,100,50,1); | |
transform:perspective(800px) rotateY(0deg); | |
backface-visibility:hidden; | |
} | |
.panel-back { | |
position: fixed;top:0;left:0; | |
width:100%;height:100%; | |
border-radius: 25px; | |
background-clip: padding-box; | |
padding: 15px; | |
background: hsla(45,0,50,0.25); | |
transform:perspective(800px) rotateY(180deg); | |
backface-visibility:hidden; | |
h5 { position: absolute; bottom: 15px; } | |
} |