HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div class="demo-container">
<h1>How was the help you received?</h1>
<div class="rating-control">
<div class="rating-option" rating="1" selected-fill="#FFA98D">
<div class="icon">
<svg width="100%" height="100%" viewBox="0 0 50 50">
<path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="#C6CCD0"></path>
<path d="M25,31.5 C21.3114356,31.5 17.7570324,32.4539319 14.6192568,34.2413572 C13.6622326,34.7865234 13.3246514,36.0093483 13.871382,36.9691187 C14.4181126,37.9288892 15.6393731,38.2637242 16.5991436,37.7169936 C19.1375516,36.2709964 22.0103269,35.5 25,35.5 C27.9896731,35.5 30.8610304,36.2701886 33.4008564,37.7169936 C34.3606269,38.2637242 35.5818874,37.9288892 36.128618,36.9691187 C36.6753486,36.0093483 36.3405137,34.7880878 35.3807432,34.2413572 C32.2429676,32.4539319 28.6885644,31.5 25,31.5 Z" class="mouth" fill="#FFFFFF"></path>
<path d="M30.6486386,16.8148522 C31.1715727,16.7269287 31.2642212,16.6984863 31.7852173,16.6140137 C32.3062134,16.529541 33.6674194,16.3378906 34.5824585,16.1715729 C35.4974976,16.0052551 35.7145386,15.9660737 36.4964248,15.8741891 C36.6111841,15.9660737 36.7220558,16.0652016 36.8284271,16.1715729 C37.7752853,17.118431 38.1482096,18.4218859 37.9472002,19.6496386 C37.8165905,20.4473941 37.4436661,21.2131881 36.8284271,21.8284271 C35.26633,23.3905243 32.73367,23.3905243 31.1715729,21.8284271 C29.8093655,20.4662198 29.6350541,18.3659485 30.6486386,16.8148522 Z" class="right-eye" fill="#FFFFFF"></path>
<path d="M18.8284271,21.8284271 C20.1906345,20.4662198 20.3649459,18.3659485 19.3513614,16.8148522 C18.8284273,16.7269287 18.7357788,16.6984863 18.2147827,16.6140137 C17.6937866,16.529541 16.3325806,16.3378906 15.4175415,16.1715729 C14.5025024,16.0052551 14.2854614,15.9660737 13.5035752,15.8741891 C13.3888159,15.9660737 13.2779442,16.0652016 13.1715729,16.1715729 C12.2247147,17.118431 11.8517904,18.4218859 12.0527998,19.6496386 C12.1834095,20.4473941 12.5563339,21.2131881 13.1715729,21.8284271 C14.73367,23.3905243 17.26633,23.3905243 18.8284271,21.8284271 Z" class="left-eye" fill="#FFFFFF"></path>
</svg>
</div>
<div class="label">Terrible</div>
<div class="touch-marker"></div>
</div>
<div class="rating-option" rating="2" selected-fill="#FFC385">
<div class="icon">
<svg width="100%" height="100%" viewBox="0 0 50 50">
<path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="#C6CCD0"></path>
<path d="M25,31.9996 C21.7296206,31.9996 18.6965022,32.5700242 15.3353795,33.7542598 C14.2935825,34.1213195 13.7466,35.2634236 14.1136598,36.3052205 C14.4807195,37.3470175 15.6228236,37.894 16.6646205,37.5269402 C19.617541,36.4865279 22.2066846,35.9996 25,35.9996 C28.1041177,35.9996 31.5196849,36.5918872 33.0654841,37.4088421 C34.0420572,37.924961 35.2521232,37.5516891 35.7682421,36.5751159 C36.284361,35.5985428 35.9110891,34.3884768 34.9345159,33.8723579 C32.7065288,32.6948667 28.6971052,31.9996 25,31.9996 Z" class="mouth" fill="#FFFFFF"></path>
<path d="M30.7014384,16.8148522 C30.8501714,16.5872449 31.0244829,16.3714627 31.2243727,16.1715729 C32.054483,15.3414625 33.1586746,14.9524791 34.2456496,15.0046227 C34.8805585,15.7858887 34.945378,15.8599243 35.5310714,16.593811 C36.1167648,17.3276978 36.1439252,17.3549194 36.5988813,17.9093628 C37.0538374,18.4638062 37.2801558,18.7149658 38,19.6496386 C37.8693903,20.4473941 37.496466,21.2131881 36.8812269,21.8284271 C35.3191298,23.3905243 32.7864699,23.3905243 31.2243727,21.8284271 C29.8621654,20.4662198 29.6878539,18.3659485 30.7014384,16.8148522 Z" class="right-eye" fill="#FFFFFF"></path>
<path d="M18.8284271,21.8284271 C20.1906345,20.4662198 20.3649459,18.3659485 19.3513614,16.8148522 C19.2026284,16.5872449 19.0283169,16.3714627 18.8284271,16.1715729 C17.9983168,15.3414625 16.8941253,14.9524791 15.8071502,15.0046227 C15.1722413,15.7858887 15.1074218,15.8599243 14.5217284,16.593811 C13.9360351,17.3276978 13.9088746,17.3549194 13.4539185,17.9093628 C12.9989624,18.4638062 12.772644,18.7149658 12.0527998,19.6496386 C12.1834095,20.4473941 12.5563339,21.2131881 13.1715729,21.8284271 C14.73367,23.3905243 17.26633,23.3905243 18.8284271,21.8284271 Z" class="left-eye" fill="#FFFFFF"></path>
</svg>
</div>
<div class="label">Bad</div>
<div class="touch-marker"></div>
</div>
<div class="rating-option" rating="3">
<div class="icon">
<svg width="100%" height="100%" viewBox="0 0 50 50">
<path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="#C6CCD0"></path>
<path d="M25.0172185,32.7464719 C22.4651351,33.192529 19.9789584,33.7240143 17.4783686,34.2837667 C16.4004906,34.5250477 15.7222686,35.5944568 15.9635531,36.6723508 C16.2048377,37.7502449 17.2738374,38.4285417 18.3521373,38.1871663 C20.8031673,37.6385078 23.2056119,37.1473427 25.7416475,36.6803253 C28.2776831,36.2133079 30.8254642,35.7953113 33.3839467,35.4267111 C34.4772031,35.2692059 35.235822,34.2552362 35.0783131,33.1619545 C34.9208042,32.0686729 33.89778,31.3113842 32.8135565,31.4675881 C30.2035476,31.8436117 27.6044107,32.2700339 17.4783686,34.2837667 Z" class="mouth" fill="#FFFFFF"></path>
<path d="M30.6486386,16.8148522 C30.7973716,16.5872449 30.9716831,16.3714627 31.1715729,16.1715729 C32.0016832,15.3414625 33.1058747,14.9524791 34.1928498,15.0046227 C35.0120523,15.0439209 35.8214759,15.3337764 36.4964248,15.8741891 C36.6111841,15.9660737 36.7220558,16.0652016 36.8284271,16.1715729 C37.7752853,17.118431 38.1482096,18.4218859 37.9472002,19.6496386 C37.8165905,20.4473941 37.4436661,21.2131881 36.8284271,21.8284271 C35.26633,23.3905243 32.73367,23.3905243 31.1715729,21.8284271 C29.8093655,20.4662198 29.6350541,18.3659485 30.6486386,16.8148522 Z" class="right-eye" fill="#FFFFFF"></path>
<path d="M18.8284271,21.8284271 C20.1906345,20.4662198 20.3649459,18.3659485 19.3513614,16.8148522 C19.2026284,16.5872449 19.0283169,16.3714627 18.8284271,16.1715729 C17.9983168,15.3414625 16.8941253,14.9524791 15.8071502,15.0046227 C14.9879477,15.0439209 14.1785241,15.3337764 13.5035752,15.8741891 C13.3888159,15.9660737 13.2779442,16.0652016 13.1715729,16.1715729 C12.2247147,17.118431 11.8517904,18.4218859 12.0527998,19.6496386 C12.1834095,20.4473941 12.5563339,21.2131881 13.1715729,21.8284271 C14.73367,23.3905243 17.26633,23.3905243 18.8284271,21.8284271 Z" class="left-eye" fill="#FFFFFF"></path>
</svg>
</div>
<div class="label">Okay</div>
<div class="touch-marker"></div>
</div>
<div class="rating-option" rating="4">
<div class="icon" style="transform: scale(0);">
<svg width="100%" height="100%" viewBox="0 0 50 50">
<path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="#C6CCD0"></path>
<path d="M25,35 C21.9245658,35 18.973257,34.1840075 16.3838091,32.6582427 C15.4321543,32.0975048 14.2061178,32.4144057 13.64538,33.3660605 C13.0846422,34.3177153 13.401543,35.5437517 14.3531978,36.1044896 C17.5538147,37.9903698 21.2054786,39 25,39 C28.7945214,39 32.4461853,37.9903698 35.6468022,36.1044896 C36.598457,35.5437517 36.9153578,34.3177153 36.35462,33.3660605 C35.7938822,32.4144057 34.5678457,32.0975048 33.6161909,32.6582427 C31.026743,34.1840075 28.0754342,35 25,35 Z" class="mouth" fill="#FFFFFF"></path>
<path d="M30.6486386,16.8148522 C30.7973716,16.5872449 30.9716831,16.3714627 31.1715729,16.1715729 C32.0016832,15.3414625 33.1058747,14.9524791 34.1928498,15.0046227 C35.0120523,15.0439209 35.8214759,15.3337764 36.4964248,15.8741891 C36.6111841,15.9660737 36.7220558,16.0652016 36.8284271,16.1715729 C37.7752853,17.118431 38.1482096,18.4218859 37.9472002,19.6496386 C37.8165905,20.4473941 37.4436661,21.2131881 36.8284271,21.8284271 C35.26633,23.3905243 32.73367,23.3905243 31.1715729,21.8284271 C29.8093655,20.4662198 29.6350541,18.3659485 30.6486386,16.8148522 Z" class="right-eye" fill="#FFFFFF"></path>
<path d="M18.8284271,21.8284271 C20.1906345,20.4662198 20.3649459,18.3659485 19.3513614,16.8148522 C19.2026284,16.5872449 19.0283169,16.3714627 18.8284271,16.1715729 C17.9983168,15.3414625 16.8941253,14.9524791 15.8071502,15.0046227 C14.9879477,15.0439209 14.1785241,15.3337764 13.5035752,15.8741891 C13.3888159,15.9660737 13.2779442,16.0652016 13.1715729,16.1715729 C12.2247147,17.118431 11.8517904,18.4218859 12.0527998,19.6496386 C12.1834095,20.4473941 12.5563339,21.2131881 13.1715729,21.8284271 C14.73367,23.3905243 17.26633,23.3905243 18.8284271,21.8284271 Z" class="left-eye" fill="#FFFFFF"></path>
</svg>
</div>
<div class="label" style="transform: translateY(9px); color: rgb(49, 59, 63);">Good</div>
<div class="touch-marker"></div>
</div>
<div class="rating-option" rating="5">
<div class="icon">
<svg width="100%" height="100%" viewBox="0 0 50 50">
<path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="#C6CCD0"></path>
<path d="M25.0931396,31 C22.3332651,31 16.6788329,31 13.0207,31 C12.1907788,31 11.6218259,31.4198568 11.2822542,32.0005432 C10.9061435,32.6437133 10.8807853,33.4841868 11.3937,34.17 C14.4907,38.314 19.4277,41 24.9997,41 C30.5727,41 35.5097,38.314 38.6067,34.17 C39.0848493,33.5300155 39.0947422,32.7553501 38.7884086,32.1320187 C38.4700938,31.4843077 37.8035583,31 36.9797,31 C34.3254388,31 28.6616205,31 25.0931396,31 Z" class="mouth" fill="#FFFFFF"></path>
<path d="M30.6486386,16.8148522 C30.7973716,16.5872449 30.9716831,16.3714627 31.1715729,16.1715729 C32.0016832,15.3414625 33.1058747,14.9524791 34.1928498,15.0046227 C35.0120523,15.0439209 35.8214759,15.3337764 36.4964248,15.8741891 C36.6111841,15.9660737 36.7220558,16.0652016 36.8284271,16.1715729 C37.7752853,17.118431 38.1482096,18.4218859 37.9472002,19.6496386 C37.8165905,20.4473941 37.4436661,21.2131881 36.8284271,21.8284271 C35.26633,23.3905243 32.73367,23.3905243 31.1715729,21.8284271 C29.8093655,20.4662198 29.6350541,18.3659485 30.6486386,16.8148522 Z" class="right-eye" fill="#FFFFFF"></path>
<path d="M18.8284271,21.8284271 C20.1906345,20.4662198 20.3649459,18.3659485 19.3513614,16.8148522 C19.2026284,16.5872449 19.0283169,16.3714627 18.8284271,16.1715729 C17.9983168,15.3414625 16.8941253,14.9524791 15.8071502,15.0046227 C14.9879477,15.0439209 14.1785241,15.3337764 13.5035752,15.8741891 C13.3888159,15.9660737 13.2779442,16.0652016 13.1715729,16.1715729 C12.2247147,17.118431 11.8517904,18.4218859 12.0527998,19.6496386 C12.1834095,20.4473941 12.5563339,21.2131881 13.1715729,21.8284271 C14.73367,23.3905243 17.26633,23.3905243 18.8284271,21.8284271 Z" class="left-eye" fill="#FFFFFF"></path>
</svg>
</div>
<div class="label">Great</div>
<div class="touch-marker"></div>
</div>
<div class="current-rating">
<div class="svg-wrapper"></div>
<div class="touch-marker"></div>
</div>
</div>
</div>
* {
margin: 0;
padding: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: none;
font-family: -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif
}
body {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #FAFAFB
}
.demo-container {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
box-sizing: border-box;
position: relative;
width: 100%;
max-width: 400px;
height: 300px;
padding: 20px;
text-align: center
}
@media screen and (max-width: 479px) {
.demo-container {
padding: 10px
}
}
.demo-container h1 {
font-size: 14px;
font-weight: 500;
margin-top: -5px;
margin-bottom: 20px;
color: #6E787C
}
body.dragging,
body.dragging .rating-option {
cursor: -webkit-grabbing !important;
cursor: grabbing !important
}
.touch-marker {
position: absolute;
width: 37px;
height: 37px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 4px 6px rgba(0, 0, 0, 0.06);
-webkit-transform: scale(2);
transform: scale(2);
opacity: 0;
transition-property: -webkit-transform, opacity;
transition-property: transform, opacity;
transition-duration: .25s;
transition-timing-function: cubic-bezier(.215, .61, .355, 1);
pointer-events: none;
will-change: transform
}
.show-touch .touch-marker {
-webkit-transform: none;
transform: none;
opacity: 1
}
.rating-control {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
position: relative;
width: 100%;
max-width: 400px;
padding-bottom: 9px
}
.rating-control::before {
content: "";
position: absolute;
width: 80%;
height: 2px;
top: 50%;
margin-top: -13px;
left: 10%;
background-color: #E9ECEE
}
.rating-control .current-rating {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
position: absolute;
width: 20%;
height: 55px;
top: 0;
left: 0;
will-change: transform;
cursor: -webkit-grab;
cursor: grab
}
.rating-control .current-rating:active {
cursor: -webkit-grabbing;
cursor: grabbing
}
.rating-control .current-rating .svg-wrapper {
position: relative;
width: 55px;
height: 55px;
border-radius: 50%;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08);
pointer-events: none
}
.rating-control .current-rating .svg-wrapper svg {
position: absolute;
width: 55px;
height: 55px;
top: 0;
left: 0;
will-change: transform
}
@media (-webkit-min-device-pixel-ratio: 2),
(min-device-pixel-ratio: 2),
(min-resolution: 2dppx) {
.rating-control .current-rating .svg-wrapper svg {
-webkit-transform: translate(.5px, .5px);
transform: translate(.5px, .5px)
}
}
.rating-control .current-rating .touch-marker {
bottom: -10px;
left: 50%;
margin-left: -5px
}
.rating-control .rating-option {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
position: relative;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
margin-top: 9px;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}
.rating-control .rating-option:active .icon svg .base,
.rating-control .rating-option.active .icon svg .base {
fill: #8B959A
}
.rating-control .rating-option:active .label,
.rating-control .rating-option.active .label {
color: #313B3F !important
}
.rating-control .rating-option .icon {
width: 36px;
height: 36px;
will-change: transform;
pointer-events: none
}
.rating-control .rating-option .icon svg {
display: block
}
.rating-control .rating-option .icon svg .base {
transition: fill .1s ease-in-out
}
.rating-control .rating-option .label {
font-size: 12px;
font-weight: 500;
color: #ABB2B6;
margin-top: 8px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
will-change: transform;
transition: color .1s ease-in-out
}
.rating-control .rating-option .label.no-transition {
transition: none
}
.rating-control .rating-option .touch-marker {
bottom: 15px;
left: 50%;
margin-left: -18px
}
document.addEventListener("DOMContentLoaded", function() {
var RatingControl = function(element) {
var self = this;
self.containerElement = element;
self.selectedRatingElement = self.containerElement.querySelector(".current-rating");
self.selectedRatingSVGContainer = self.selectedRatingElement.querySelector(".svg-wrapper");
self.ratingElements = [].slice.call(self.containerElement.querySelectorAll(".rating-option")).map(function(element) {
return {
container: element,
icon: element.querySelector(".icon"),
label: element.querySelector(".label"),
selectedFill: self.hexToRGB(element.getAttribute("selected-fill") || "#FFD885")
};
});
self.selectedRating;
self.sliderPosition = 0;
self.facePaths = [];
self.labelColor = self.hexToRGB("#ABB2B6");
self.labelSelectedColor = self.hexToRGB("#313B3F");
self.dragging = false;
self.handleDragOffset = 0;
self.ratingTouchStartPosition = {x:0, y:0};
self.onRatingChange = function() {};
self.easings = {
easeInOutCubic: function(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t + b;
return c/2*((t-=2)*t*t + 2) + b;
},
easeInOutQuad: function(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
linear: function (t, b, c, d) {
return c*t/d + b;
}
};
self.onHandleDrag = self.onHandleDrag.bind(this);
self.onHandleRelease = self.onHandleRelease.bind(this);
self.ratingElements.forEach(function(element) {
// Copy face path data from HTML
var paths = {};
[].forEach.call(element.icon.querySelectorAll("path:not(.base)"), function(path) {
var pathStr = path.getAttribute("d");
paths[path.getAttribute("class")] = self.splitString(pathStr);
});
self.facePaths.push(paths);
// On rating selected
element.container.addEventListener("ontouchend" in document ? "touchend" : "click", function(e) {
if ("ontouchend" in document) {
var ratingTouchCurrentPosition = {x: e.pageX, y: e.pageY};
var dragDistance = Math.sqrt(Math.pow(ratingTouchCurrentPosition.x - self.ratingTouchStartPosition.x, 2) + Math.pow(ratingTouchCurrentPosition.y - self.ratingTouchStartPosition.y, 2));
if (dragDistance > 10) {
return;
}
}
var newRating = element.container.getAttribute("rating") - 1;
self.setRating(newRating, {fireChange: true});
});
});
if ("ontouchend" in document) {
document.body.addEventListener("touchstart", function(e) {
if (e.target.classList.contains("rating-option")) {
self.ratingTouchStartPosition = {x: e.touches[0].pageX, y: e.touches[0].pageY};
}
});
self.selectedRatingElement.addEventListener("touchstart", function(e) {
self.dragging = true;
self.handleDragOffset = e.touches[0].pageX - self.selectedRatingElement.getBoundingClientRect().left;
self.setLabelTransitionEnabled(false);
});
self.selectedRatingElement.addEventListener("touchmove", self.onHandleDrag);
self.selectedRatingElement.addEventListener("touchend", self.onHandleRelease);
} else {
document.body.addEventListener("mousedown", function(e) {
if (e.target == self.selectedRatingElement) {
e.preventDefault();
self.dragging = true;
self.handleDragOffset = e.offsetX;
self.setLabelTransitionEnabled(false);
document.body.classList.add("dragging");
document.body.addEventListener("mousemove", self.onHandleDrag);
}
});
document.body.addEventListener("mouseup", function(e) {
if (self.dragging) {
document.body.classList.remove("dragging");
document.body.removeEventListener("mousemove", self.onHandleDrag);
self.onHandleRelease(e);
}
});
}
self.setRating(3, {duration: 0});
}
RatingControl.prototype = {
setRating: function(rating, options) {
var self = this;
var options = options || {};
var startTime;
var fireChange = options.fireChange || false;
var onComplete = options.onComplete || function() {};
var easing = options.easing || self.easings.easeInOutCubic;
var duration = options.duration == undefined ? 550 : options.duration;
var startXPosition = self.sliderPosition;
var endXPosition = rating * self.selectedRatingElement.offsetWidth;
if (duration > 0) {
var anim = function(timestamp) {
startTime = startTime || timestamp;
var elapsed = timestamp - startTime;
var progress = easing(elapsed, startXPosition, endXPosition - startXPosition, duration);
self.setSliderPosition(progress);
if (elapsed < duration) {
requestAnimationFrame(anim);
} else {
self.setSliderPosition(endXPosition);
self.setLabelTransitionEnabled(true);
if (self.onRatingChange && self.selectedRating != rating && fireChange) {
self.onRatingChange(rating);
}
onComplete();
self.selectedRating = rating;
}
};
self.setLabelTransitionEnabled(false);
requestAnimationFrame(anim);
} else {
self.setSliderPosition(endXPosition);
if (self.onRatingChange && self.selectedRating != rating && fireChange) {
self.onRatingChange(rating);
}
onComplete();
self.selectedRating = rating;
}
},
setSliderPosition: function(position) {
var self = this;
self.sliderPosition = Math.min(Math.max(0, position), self.containerElement.offsetWidth - self.selectedRatingElement.offsetWidth);
var stepProgress = self.sliderPosition / self.containerElement.offsetWidth * self.ratingElements.length;
var relativeStepProgress = stepProgress - Math.floor(stepProgress);
var currentStep = Math.round(stepProgress);
var startStep = Math.floor(stepProgress);
var endStep = Math.ceil(stepProgress);
// Move handle
self.selectedRatingElement.style.transform = "translateX(" + (self.sliderPosition / self.selectedRatingElement.offsetWidth * 100) + "%)";
// Set face
var startPaths = self.facePaths[startStep];
var endPaths = self.facePaths[endStep];
var interpolatedPaths = {};
for (var featurePath in startPaths) {
if (startPaths.hasOwnProperty(featurePath)) {
var startPath = startPaths[featurePath];
var endPath = endPaths[featurePath];
var interpolatedPoints = self.interpolatedArray(startPath.digits, endPath.digits, relativeStepProgress);
var interpolatedPath = self.recomposeString(interpolatedPoints, startPath.nondigits);
interpolatedPaths[featurePath] = interpolatedPath;
}
}
var interpolatedFill = self.interpolatedColor(self.ratingElements[startStep]["selectedFill"], self.ratingElements[endStep]["selectedFill"], relativeStepProgress);
self.selectedRatingSVGContainer.innerHTML = '<svg width="55px" height="55px" viewBox="0 0 50 50"><path d="M50,25 C50,38.807 38.807,50 25,50 C11.193,50 0,38.807 0,25 C0,11.193 11.193,0 25,0 C38.807,0 50,11.193 50,25" class="base" fill="' + interpolatedFill + '"></path><path d="' + interpolatedPaths["mouth"] + '" class="mouth" fill="#655F52"></path><path d="' + interpolatedPaths["right-eye"] + '" class="right-eye" fill="#655F52"></path><path d="' + interpolatedPaths["left-eye"] + '" class="left-eye" fill="#655F52"></path></svg>';
// Update marker icon/label
self.ratingElements.forEach(function(element, index) {
var adjustedProgress = 1;
if (index == currentStep) {
adjustedProgress = 1 - Math.abs((stepProgress - Math.floor(stepProgress) - 0.5) * 2);
}
element.icon.style.transform = "scale(" + adjustedProgress + ")";
element.label.style.transform = "translateY(" + self.interpolatedValue(9, 0, adjustedProgress) + "px)";
element.label.style.color = self.interpolatedColor(self.labelSelectedColor, self.labelColor, adjustedProgress);
});
},
onHandleDrag: function(e) {
var self = this;
e.preventDefault();
if (e.touches) {
e = e.touches[0];
}
var offset = self.selectedRatingElement.offsetWidth / 2 - self.handleDragOffset;
var xPos = e.clientX - self.containerElement.getBoundingClientRect().left;
self.setSliderPosition(xPos - self.selectedRatingElement.offsetWidth / 2 + offset);
},
onHandleRelease: function(e) {
var self = this;
self.dragging = false;
self.setLabelTransitionEnabled(true);
var rating = Math.round(self.sliderPosition / self.containerElement.offsetWidth * self.ratingElements.length);
self.setRating(rating, {duration: 200, fireChange: true});
},
setLabelTransitionEnabled: function(enabled) {
var self = this;
self.ratingElements.forEach(function(element) {
if (enabled) {
element.label.classList.remove("no-transition");
} else {
element.label.classList.add("no-transition");
}
});
},
interpolatedValue: function(startValue, endValue, progress) {
return (endValue - startValue) * progress + startValue;
},
interpolatedArray: function(startArray, endArray, progress) {
return startArray.map(function(startValue, index) {
return (endArray[index] - startValue) * progress + startValue;
});
},
interpolatedColor: function(startColor, endColor, progress) {
var self = this;
var interpolatedRGB = self.interpolatedArray(startColor, endColor, progress).map(function(channel) {
return Math.round(channel);
});
return "rgba(" + interpolatedRGB[0] + "," + interpolatedRGB[1] + "," + interpolatedRGB[2] + ",1)";
},
easeInQuint: function(t, b, c, d) {
return c*(t/=d)*t*t + b;
},
hexToRGB: function(hex) {
// Expand shorthand form to full form
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
},
splitString: function(value) {
var re = /-?\d*\.?\d+/g;
var toStr = function toStr(val) {
return typeof val == "string" ? val : String(val);
};
return {
digits: toStr(value).match(re).map(Number),
nondigits: toStr(value).split(re)
};
},
recomposeString: function(digits, nondigits) {
return nondigits.reduce(function (a, b, i) {
return a + digits[i - 1] + b;
});
},
simulateRatingTap(rating, delay, complete) {
var self = this;
var ratingElement = self.ratingElements[rating];
setTimeout(function() {
ratingElement.container.classList.add("show-touch");
setTimeout(function() {
ratingElement.container.classList.remove("show-touch");
self.setRating(rating, {
onComplete: function() {
if (complete) {
complete();
}
}
});
}, 250);
}, delay || 0);
},
simulateRatingDrag(rating, delay, complete) {
var self = this;
setTimeout(function() {
self.selectedRatingElement.classList.add("show-touch");
setTimeout(function() {
self.setRating(rating, {
duration: 3000,
easing: self.easings.easeInOutQuad,
onComplete: function() {
self.selectedRatingElement.classList.remove("show-touch");
if (complete) {
complete();
}
}
});
}, 250);
}, delay || 0);
}
}
document.querySelector(".demo-container").classList.add("clip-marker");
var ratingControl = new RatingControl(document.querySelector(".rating-control"));
});
Also see: Tab Triggers