Skip to content

Instantly share code, notes, and snippets.

@Rudis1261
Last active July 28, 2017 11:57
Show Gist options
  • Save Rudis1261/acc12049a286d97d8f4ed1d9dfb191df to your computer and use it in GitHub Desktop.
Save Rudis1261/acc12049a286d97d8f4ed1d9dfb191df to your computer and use it in GitHub Desktop.
Standalone Range Slider Directive With. OnSet, OnDrag bindings
/**
* @ngdoc function
* @name siteBuilderApp.directives
* @description
* # siteBuilderApp.directives
* Directives of the siteBuilderApp
*/
angular.module('siteBuilderAppDirectives')
.directive('ngMobileClick', function ($parse) {
return function (scope, elem, attrs) {
var fn = $parse(attrs["ngMobileClick"]);
elem.bind("touchstart click", function (e) {
e.preventDefault();
e.stopPropagation();
scope.$apply(function() { fn(scope, { $event: e }); });
});
scope.$on('$destroy', function() {
elem.off('touchstart click');
});
}
})
.directive('ngMobileTouchStart', function ($parse) {
return function (scope, elem, attrs) {
var fn = $parse(attrs["ngMobileTouchStart"]);
elem.bind("touchstart mousedown", function (e) {
e.preventDefault();
e.stopPropagation();
scope.$apply(function() { fn(scope, { $event: e }); });
});
scope.$on('$destroy', function() {
elem.off('touchstart mousedown');
});
}
})
.directive('ngMobileTouchEnd', function ($parse) {
return function (scope, elem, attrs) {
var fn = $parse(attrs["ngMobileTouchEnd"]);
elem.bind("touchend mouseup", function (e) {
e.preventDefault();
e.stopPropagation();
scope.$apply(function() { fn(scope, { $event: e }); });
});
scope.$on('$destroy', function() {
elem.off('touchend mouseup');
});
}
});
/* ==========================================================================
Mixins
========================================================================== */
@mixin vendor($property, $value){
-webkit-#{$property}:$value;
-moz-#{$property}:$value;
-ms-#{$property}:$value;
-o-#{$property}:$value;
#{$property}:$value;
}
@mixin clearfix() {
&:before,
&:after {
content: " "; // 1
display: table; // 2
}
&:after {
clear: both;
}
}
@mixin noselect() {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin linearGradient($top, $bottom, $important: false){
@if ($important == 'important' or $important == true) {
background: $top!important; /* Old browsers */
background: -moz-linear-gradient(top, $top 0%, $bottom 100%)!important; /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom))!important; /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, $top 0%,$bottom 100%)!important; /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, $top 0%,$bottom 100%)!important; /* Opera 11.10+ */
background: -ms-linear-gradient(top, $top 0%,$bottom 100%)!important; /* IE10+ */
background: linear-gradient(to bottom, $top 0%,$bottom 100%)!important; /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#000000', GradientType=0)!important; /* IE6-9 */
}
@else {
background: $top; /* Old browsers */
background: -moz-linear-gradient(top, $top 0%, $bottom 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, $top 0%,$bottom 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, $top 0%,$bottom 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, $top 0%,$bottom 100%); /* IE10+ */
background: linear-gradient(to bottom, $top 0%,$bottom 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
}
}
@mixin horizontalGradient($start-colour, $end-colour) {
ackground-color: $start-colour;
background-image: -webkit-gradient(linear, left top, right top, from($start-colour), to($end-colour));
background-image: -webkit-linear-gradient(left, $start-colour, $end-colour);
background-image: -moz-linear-gradient(left, $start-colour, $end-colour);
background-image: -ms-linear-gradient(left, $start-colour, $end-colour);
background-image: -o-linear-gradient(left, $start-colour, $end-colour);
background-image: linear-gradient(left, $start-colour, $end-colour);
filter: progid:DXImageTransform.Microsoft.gradient(start-colourStr='#{$start-colour}', end-colourStr='#{$end-colour}', gradientType='1');
}
@mixin info-gradient($startColor, $endColor: #000) {
background: -moz-linear-gradient(left, $startColor 0%, $startColor 20%, $endColor 50%, $endColor 100%); /* FF3.6-15 */
background: -o-linear-gradient(right, $startColor, $endColor); /* For Opera 11.1 to 12.0 */
background: -webkit-linear-gradient(left, $startColor 0%, $startColor 20%, $endColor 50%, $endColor 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to right, $startColor 0%, $startColor 20%, $endColor 50%, $endColor 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
}
@mixin opacity($opacity) {
opacity: $opacity;
$opacity-ie: ($opacity * 100);
filter: alpha(opacity=$opacity-ie);
}
@mixin background-opacity($color, $opacity: 0.8) {
background: $color !important; /* The Fallback */
background: rgba($color, $opacity) !important;
}
@mixin border-radius($radius){
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}
@mixin sharpen-image {
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
-ms-interpolation-mode: nearest-neighbor;
}
@mixin animation($animation) {
-webkit-animation: $animation;
-o-animation: $animation;
animation: $animation;
}
@mixin animation-name($name) {
-webkit-animation-name: $name;
animation-name: $name;
}
@mixin animation-duration($duration) {
-webkit-animation-duration: $duration;
animation-duration: $duration;
}
@mixin animation-timing-function($timing-function) {
-webkit-animation-timing-function: $timing-function;
animation-timing-function: $timing-function;
}
@mixin animation-delay($delay) {
-webkit-animation-delay: $delay;
animation-delay: $delay;
}
@mixin animation-iteration-count($iteration-count) {
-webkit-animation-iteration-count: $iteration-count;
animation-iteration-count: $iteration-count;
}
@mixin animation-direction($direction) {
-webkit-animation-direction: $direction;
animation-direction: $direction;
}
@mixin animation-fill-mode($fill-mode) {
-webkit-animation-fill-mode: $fill-mode;
animation-fill-mode: $fill-mode;
}
@mixin box-shadow($shadow...) {
-webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1
box-shadow: $shadow;
}
@mixin box-sizing($boxmodel) {
-webkit-box-sizing: $boxmodel;
-moz-box-sizing: $boxmodel;
box-sizing: $boxmodel;
}
// CSS3 Content Columns
@mixin content-columns($column-count, $column-gap: $grid-gutter-width) {
-webkit-column-count: $column-count;
-moz-column-count: $column-count;
column-count: $column-count;
-webkit-column-gap: $column-gap;
-moz-column-gap: $column-gap;
column-gap: $column-gap;
}
@mixin transition($trans) {
-webkit-transition: $trans;
-moz-transition: $trans;
-o-transition: $trans;
transition: $trans;
}
@mixin keyframes($animationName) {
@-webkit-keyframes #{$animationName} {
@content;
}
@-moz-keyframes #{$animationName} {
@content;
}
@-o-keyframes #{$animationName} {
@content;
}
@keyframes #{$animationName} {
@content;
}
}
@mixin transform($trans, $important: false) {
-webkit-transform: $trans;
-moz-transform: $trans;
-ms-transform: $trans;
-o-transform: $trans;
transform: $trans;
@if ($important == true) {
-webkit-transform: $trans!important;
-moz-transform: $trans!important;
-ms-transform: $trans!important;
-o-transform: $trans!important;
transform: $trans!important;
}
}
@mixin transform-style($trans) {
-webkit-transform-style: $trans;
-moz-transform-style: $trans;
-ms-transform-style: $trans;
-o-transform-style: $trans;
transform-style: $trans;
}
@mixin scale($ratio...) {
-webkit-transform: scale($ratio);
-ms-transform: scale($ratio); // IE9 only
-o-transform: scale($ratio);
transform: scale($ratio);
}
@mixin scaleX($ratio) {
-webkit-transform: scaleX($ratio);
-ms-transform: scaleX($ratio); // IE9 only
-o-transform: scaleX($ratio);
transform: scaleX($ratio);
}
@mixin scaleY($ratio) {
-webkit-transform: scaleY($ratio);
-ms-transform: scaleY($ratio); // IE9 only
-o-transform: scaleY($ratio);
transform: scaleY($ratio);
}
@mixin skew($x, $y) {
-webkit-transform: skewX($x) skewY($y);
-ms-transform: skewX($x) skewY($y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
-o-transform: skewX($x) skewY($y);
transform: skewX($x) skewY($y);
}
@mixin translate($x, $y) {
-webkit-transform: translate($x, $y);
-ms-transform: translate($x, $y); // IE9 only
-o-transform: translate($x, $y);
transform: translate($x, $y);
}
@mixin translate3d($x, $y, $z) {
-webkit-transform: translate3d($x, $y, $z);
transform: translate3d($x, $y, $z);
}
@mixin rotate($degrees) {
-webkit-transform: rotate($degrees);
-ms-transform: rotate($degrees); // IE9 only
-o-transform: rotate($degrees);
transform: rotate($degrees);
}
@mixin rotateX($degrees) {
-webkit-transform: rotateX($degrees);
-ms-transform: rotateX($degrees); // IE9 only
-o-transform: rotateX($degrees);
transform: rotateX($degrees);
}
@mixin rotateY($degrees) {
-webkit-transform: rotateY($degrees);
-ms-transform: rotateY($degrees); // IE9 only
-o-transform: rotateY($degrees);
transform: rotateY($degrees);
}
@mixin perspective($perspective) {
-webkit-perspective: $perspective;
-moz-perspective: $perspective;
perspective: $perspective;
}
@mixin perspective-origin($perspective) {
-webkit-perspective-origin: $perspective;
-moz-perspective-origin: $perspective;
perspective-origin: $perspective;
}
@mixin transform-origin($origin) {
-webkit-transform-origin: $origin;
-moz-transform-origin: $origin;
-ms-transform-origin: $origin; // IE9 only
transform-origin: $origin;
}
@mixin transition($transition...) {
-webkit-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
@mixin transition-property($transition-property...) {
-webkit-transition-property: $transition-property;
transition-property: $transition-property;
}
@mixin transition-delay($transition-delay) {
-webkit-transition-delay: $transition-delay;
transition-delay: $transition-delay;
}
@mixin transition-duration($transition-duration...) {
-webkit-transition-duration: $transition-duration;
transition-duration: $transition-duration;
}
@mixin transition-timing-function($timing-function) {
-webkit-transition-timing-function: $timing-function;
transition-timing-function: $timing-function;
}
@mixin transition-transform($transition...) {
-webkit-transition: -webkit-transform $transition;
-moz-transition: -moz-transform $transition;
-o-transition: -o-transform $transition;
transition: transform $transition;
}
@mixin ms-flex-align($direction: column) {
-ms-flex-pack: center;
-ms-flex-direction: $direction;
}
@mixin flex-direction($direction: row) {
-webkit-flex-direction: $direction;
-ms-flex-direction: $direction;
flex-direction: $direction;
}
@mixin flex-wrap($wrap: nowrap) {
@if $wrap == nowrap {
-ms-flex-wrap: none;
}
@else {
-ms-flex-wrap: $wrap;
}
-webkit-flex-wrap: $wrap;
flex-wrap: $wrap;
}
@mixin flex-order($order: 0) {
-ms-flex-order: $order;
-webkit-order: $order;
-ms-order: $order;
order: $order;
}
@mixin justify-content($justify: flex-start) {
@if $justify == flex-start {
-ms-flex-pack: start;
}
@else if $justify == flex-end {
-ms-flex-pack: end;
}
@elseif $justify == space-between {
-ms-flex-pack: justify;
}
@else {
-ms-flex-pack: $justify;
}
-webkit-justify-content: $justify;
-ms-justify-content: $justify;
justify-content: $justify;
}
@mixin align-items($align: auto) {
@if $align == flex-start {
-ms-flex-align: start;
}
@else if $align == flex-end {
-ms-flex-align: end;
}
@else {
-ms-flex-align: $align;
}
-webkit-align-items: $align;
-ms-align-items: $align;
align-items: $align;
}
@mixin align-content($align: auto) {
@if $align == flex-start {
-ms-flex-line-pack: start;
}
@else if $align == flex-end {
-ms-flex-line-pack: end;
}
@else {
-ms-flex-line-pack: $align;
}
-webkit-align-content: $align;
-ms-align-content: $align;
align-content: $align;
}
@mixin align-self($align: auto) {
@if $align == flex-start {
-ms-flex-item-align: start;
}
@else if $align == flex-end {
-ms-flex-item-align: end;
}
@else {
-ms-flex-item-align: $align;
}
-webkit-align-self: $align;
-ms-align-self: $align;
align-self: $align;
}
@mixin flex($value, $important: false){
@if ($important) {
-webkit-box-flex: $value!important;
-moz-box-flex: $value!important;
-webkit-flex: $value!important;
-ms-flex: $value!important;
flex: $value!important;
}
@else {
-webkit-box-flex: $value;
-moz-box-flex: $value;
-webkit-flex: $value;
-ms-flex: $value;
flex: $value;
}
}
@mixin flex-display($important: false){
@if ($important) {
display: -webkit-box!important;
display: -moz-box!important;
display: -ms-flexbox!important;
display: -webkit-flex!important;
display: flex!important;
}
@else {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
}
@mixin respond-from($size) {
@media screen and (min-width: $size) {
@content;
}
}
@mixin respond-to($size) {
@media screen and (max-width: $size) {
@content;
}
}
@mixin respond-between($lower, $upper) {
@media screen and (min-width: $lower) and (max-width: $upper) {
@content;
}
}
/**
* @ngdoc function
* @name siteBuilderApp.directives
* @description
* # siteBuilderApp.directives
* Directives of the siteBuilderApp
*/
angular.module('siteBuilderAppDirectives')
.directive('rangeSliderTest', function () {
return {
restrict: 'E',
link: function(scope) {
scope.pos = 0;
scope.setValue = function(value) {
scope.pos = value;
};
scope.setDrag = function(value) {
scope.pos = value;
};
}
}
})
.directive('rangeSlider', function ($timeout) {
return {
restrict: 'E',
replace: true,
scope: {
onValueSet: '&onValueSet',
onDrag: '&onDrag'
},
template: '<div class="range-slider">\
<div \
class="range-handle"\
ng-mobile-touch-start="start()" \
ng-mobile-touch-end="stop()" \
ng-style="{ \'left\': dragging.posX + \'px\' }" \
ng-class="{ \'active\': dragging.active }" \
></div>\
<div class="range-track" ng-mobile-click="tap($event)" ng-mobile-touch-end="stop()">\
<div class="range-track-inner" ng-style="{\'left\': dragging.posX + \'px\'}"></div>\
</div>\
</div>',
link: function(scope, element, attrs) {
scope.start = function() {
scope.dragging.active = true;
};
scope.stop = function() {
scope.dragging.active = false;
scope.onValueSet({ 'value': scope.dragging.value });
};
scope.tap = function(e) {
scope.start();
scope.position(e, true);
scope.stop();
};
scope.setPosition = function(posPercentile) {
posPercentile = (posPercentile > 100) ? 100: posPercentile;
posPercentile = (posPercentile < 0) ? 0: posPercentile;
var pos = Math.ceil((posPercentile / 100.) * scope.width) - scope.handleWidthHalf;
if (pos < 0) pos = 0;
if (pos > scope.maxWidth) pos = scope.maxWidth;
scope.dragging.value = posPercentile;
scope.dragging.posX = pos;
scope.onValueSet({ 'value': scope.dragging.value });
};
scope.position = function(e, tap) {
if (scope.dragging.active == false) return false;
if (e.type && (e.type == 'touchmove' || e.type == 'touchstart' || e.type == 'touchend')) {
var pos = parseInt(e.changedTouches[0].pageX - element[0].getBoundingClientRect().left * 1.);
} else {
var pos = parseInt(e.offsetX + e.target.offsetLeft * 1.);
}
pos = pos - scope.cursorOffSet;
if (pos < 0) pos = 0;
if (pos > scope.maxWidth) pos = scope.maxWidth;
if (!tap) {
// Prevent applying left / right when vertically out of element
var parentPos = element[0].getBoundingClientRect();
if (e.clientY > (parentPos.bottom - scope.overflowPaddingY) || e.clientY < (parentPos.top + scope.overflowPaddingY)) {
scope.stop();
return false;
}
if (e.clientX > (parentPos.right - scope.overflowPaddingX) || e.clientX < (parentPos.left + scope.overflowPaddingX)) {
scope.stop();
return false;
}
}
scope.dragging.posX = pos;
var value = (pos == scope.maxWidth) ? 100 : Math.ceil(pos / scope.maxWidth * 100.);
if (scope.dragging.value !== value) {
scope.dragging.value = value;
scope.onDrag({'value': scope.dragging.value});
}
};
scope.positionThrottle = false;
angular.element(element).on('mousemove touchmove', function(e){
$timeout.cancel(scope.positionThrottle);
scope.positionThrottle = $timeout(function() {
scope.position(e);
}, scope.choke);
});
scope.$on('$destroy', function() {
angular.element(element).off('mouseleave');
angular.element(element).off('mousemove touchmove');
});
scope.dragging = {
active: false,
value: 0,
posX: 0
};
scope.width = element[0].getBoundingClientRect().width || 0;
scope.handle = element[0].querySelector('.range-handle');
scope.handleWidth = scope.handle.getBoundingClientRect().width;
scope.handleWidthHalf = scope.handleWidth / 2;
scope.cursorOffSet = (scope.handleWidth / 2);
scope.maxWidth = scope.width - scope.handleWidth;
scope.choke = 5;
scope.overflowPaddingX = 10;
scope.overflowPaddingY = 30;
angular.element(document).ready(function(){
scope.width = element[0].getBoundingClientRect().width || 0;
scope.handleWidth = scope.handle.getBoundingClientRect().width;
scope.handleWidthHalf = scope.handleWidth / 2;
scope.cursorOffSet = (scope.handleWidth / 2);
scope.maxWidth = scope.width - scope.handleWidth;
});
}
}
});
$rangeSliderHeight: 80px;
$rangeSliderLineHeight: 80px;
$rangeSliderBackground: none;
$rangeSliderWidth: 320px;
$rangeSliderHandleTop: 50%;
$rangeSliderHandleLeft: 0;
$rangeSliderHandleWidth: 40px;
$rangeSliderHandleHeight: 40px;
$rangeSliderHandleBackground: #fff;
$rangeSliderHandleDisplay: block;
$rangeSliderHandleCursor: pointer;
$rangeSliderHandleZIndex: 2;
$rangeSliderHandleBoxShadow: 0 4px 20px 0 rgba(0,0,0, 0.2);
$rangeSliderHandleTransform: translateY(-50%);
$rangeSliderHandleBorderRadius: 40px;
$rangeSliderHandleTransition: box-shadow 200ms, margin 200ms;
$rangeSliderHandleActiveMargin: 1px 0 0 1px;
$rangeSliderHandleActiveBackground: darken(#fff, 2%);
$rangeSliderHandleActiveBoxShadow: 0 4px 20px 0 rgba(0,0,0, 0.3);
$rangeSliderTrackOuterHeight: 20px;
$rangeSliderTrackOuterWidth: auto;
$rangeSliderTrackOuterLeft: 20px;
$rangeSliderTrackOuterRight: 20px;
$rangeSliderTrackOuterBackground: none;
$rangeSliderTrackOuterTop: 50%;
$rangeSliderTrackOuterZIndex: 1;
$rangeSliderTrackOuterOverflow: hidden;
$rangeSliderTrackOuterTransform: translateY(-50%);
$rangeSliderTrackInnerPosition: absolute;
$rangeSliderTrackInnerDisplay: block;
$rangeSliderTrackInnerHeight: 4px;
$rangeSliderTrackInnerTop: 50%;
$rangeSliderTrackInnerLeft: 0;
$rangeSliderTrackInnerRight: 0;
$rangeSliderTrackInnerTransform: translateY(-50%);
$rangeSliderTrackInnerBorderRadius: 2px;
$rangeSliderTrackInnerBackground: #899199;
$rangeSliderTrackInnerAfterBackground: #E3E7E9;
$rangeSliderTrackInnerAfterZIndex: 1;
.range-slider {
margin: 0 auto;
position: relative;
height: $rangeSliderHeight;
line-height: $rangeSliderLineHeight;
background: $rangeSliderBackground;
width: $rangeSliderWidth;
@include noselect();
.range-handle,
.range-track {
position: absolute;
}
&,
.range-handle,
.range-track,
.range-track-inner {
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.range-handle {
top: $rangeSliderHandleTop;
left: $rangeSliderHandleLeft;
width: $rangeSliderHandleWidth;
height: $rangeSliderHandleHeight;
background: $rangeSliderHandleBackground;
content: "";
display: $rangeSliderHandleDisplay;
cursor: $rangeSliderHandleCursor;
z-index: $rangeSliderHandleZIndex;
box-shadow: $rangeSliderHandleBoxShadow;
@include transform($rangeSliderHandleTransform);
@include border-radius($rangeSliderHandleBorderRadius);
@include transition($rangeSliderHandleTransition);
&.active {
margin: $rangeSliderHandleActiveMargin;
background: $rangeSliderHandleActiveBackground;
box-shadow: $rangeSliderHandleActiveBoxShadow;
}
}
.range-track {
height: $rangeSliderTrackOuterHeight;
width: $rangeSliderTrackOuterWidth;
left: $rangeSliderTrackOuterLeft;
right: $rangeSliderTrackOuterRight;
background: $rangeSliderTrackOuterBackground;
top: $rangeSliderTrackOuterTop;
z-index: $rangeSliderTrackOuterZIndex;
overflow: $rangeSliderTrackOuterOverflow;
@include noselect();
@include transform($rangeSliderTrackOuterTransform);
&:after,
&-inner {
position: $rangeSliderTrackInnerPosition;
content: "";
display: $rangeSliderTrackInnerDisplay;
height: $rangeSliderTrackInnerHeight;
top: $rangeSliderTrackInnerTop;
left: $rangeSliderTrackInnerLeft;
right: $rangeSliderTrackInnerRight;
@include transform($rangeSliderTrackInnerTransform);
@include border-radius($rangeSliderTrackInnerBorderRadius);
}
&:after {
background: $rangeSliderTrackInnerBackground;
}
&-inner {
background: $rangeSliderTrackInnerAfterBackground;
z-index: $rangeSliderTrackInnerAfterZIndex;
}
}
}
<range-slider-test>
<div>POS: {{pos + '%'}}</div>
<range-slider on-value-set="setValue(value)" on-drag="setDrag(value)"></range-slider>
</range-slider-test>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment