Enyo JS Vertical Sliders - javascript

I am trying to code a vertical slider in enyo (Like a control on mixing desk). I was trying to avoid starting from scratch so I started tweaking the onyx.Slider class. I changed to styles from left to top and from width to height and with a few other tweaks, it's working. I'm now stuck on getting the slider to fill from bottom to top as at the minute it is vertical but it fills from the top down. Thanks in advance for any help.
Here are the code changes I have done:
in ProgressBar.js:
updateBarPosition: function(inPercent) {
this.$.bar.applyStyle("height", inPercent + "%");
},
in Slider.js (dividing by 64 is a temporary hack):
valueChanged: function() {
this.value = this.clampValue(this.min, this.max, this.value);
var p = this.calcPercent(this.value);
this.updateKnobPosition(p/64);
if (this.lockBar) {
this.setProgress(this.value);
}
},
updateKnobPosition: function(inPercent) {
this.$.knob.applyStyle("top", inPercent + "%");
},
calcKnobPosition: function(inEvent) {
var y = inEvent.clientY - this.hasNode().getBoundingClientRect().top;
return (y / this.getBounds().height) * (this.max - this.min) + this.min;
},
CSS:
/* ProgressBar.css */
.onyx-progress-bar {
margin: 8px;
height: 400px;
width: 8px;
border: 1px solid rgba(15, 15, 15, 0.2);
border-radius: 3px;
background: #b8b8b8 url(./../images/gradient-invert.png) repeat-x;
background-size: auto 100%;
}
.onyx-progress-bar-bar {
height: 100%;
border-radius: 3px;
background: #58abef url(./../images/gradient.png) repeat-x;
background-size: auto 100%;
}
Tom

There are a couple of approaches you could take. The most obvious (except for the fact it didn't occur to me first) is just to swap the background/gradient of the bar and the bar-bar. This will give you the appearance of filling from the bottom. I would recommend this.
The other method is what I did in this jsFiddle here: http://jsfiddle.net/RoySutton/b9PmA/ (Do ignore the doubled updateBarPosition function)
Instead of modifying those files directly, I derived from Slider and overrode the appropriate functions and added a new class for the vertical slider.
I changed the 'fill' to be absolutely positioned within the slider.
Now, your next problem is that value '0' is fully filled and '100' is fully empty. I handled that by modifying your calcKnobPosition to adjust from max and inverting the positioning logic as seen in this fiddle here: http://jsfiddle.net/RoySutton/b9PmA/2/
return this.max - (y / this.getBounds().height) * (this.max - this.min);

Related

Javascript animate Method Accumulation Problem

I am trying to do an animation example but there is a problem about accumulation. At first click on the button, the translate animation is done and the position of the element changes permanently. However, on second click it does the translate animation again but this time does not keep the last position. How to overcome this? I went through MDN document and applied the optional section but failed to complete this challenge. Regards,
https://jsfiddle.net/ja218pbr/19/
document.getElementsByTagName("button")[0].addEventListener("click", function() {
document.querySelectorAll("div")[0].animate([
{transform: 'translate(100%, 0)'}
], {
duration: 250,
composite: "accumulate",
iterationComposite: "accumulate",
fill: "forwards"
});
});
If I'm understanding this correctly, you want to be able to let the object slide again from the position it ended in earlier. To do this we can get the boundingClientRect each time the button is clicked and calculate the new translation distance by basically taking the width of the object and adding the left distance of the client rect, this will effectively allow the rectangle to keep moving from the distance it ended in before. Also I removed the composite property because it caused the rectangle to jump over the correct position.
document.getElementsByTagName("button")[0].addEventListener("click", function() {
const clientRect = document.querySelectorAll("div")[0].getBoundingClientRect();
const translationX = clientRect.width + clientRect.left;
document.querySelectorAll("div")[0].animate([{
transform: `translate(${translationX}px, 0)`
}], {
duration: 250,
iterationComposite: "accumulate",
fill: "forwards"
});
});
body {
margin: 0;
}
div {
position: relative;
height: 150px;
width: 150px;
background-color: yellow;
text-align: center;
line-height: 150px;
}
<div>Moving Object</div>
<button>Press</button>

Convert vh units to px in JS

Unfortunately 100vh is not always the same as 100% browser height as can be shown in the following example.
html,
body {
height: 100%;
}
body {
overflow: scroll;
}
.vh {
background-color: blue;
float: left;
height: 50vh;
width: 100px;
}
.pc {
background-color: green;
float: left;
height: 50%;
width: 100px;
}
<div class="vh"></div>
<div class="pc"></div>
The issue is more pronounced on iPhone 6+ with how the upper location bar and lower navigation bar expand and contract on scroll, but are not included in the calculation for 100vh.
The actual value of 100% height can be acquired by using window.innerHeight in JS.
Is there a convenient way to calculate the current conversion of 100vh to pixels in JS?
I'm trying to avoid needing to generate dummy elements with inline styles just to calculate 100vh.
For purposes of this question, assume a hostile environment where max-width or max-height may be producing incorrect values, and there isn't an existing element with 100vh anywhere on the page. Basically, assume that anything that can go wrong has with the exception of native browser functions, which are guaranteed to be clean.
The best I've come up with so far is:
function vh() {
var div,
h;
div = document.createElement('div');
div.style.height = '100vh';
div.style.maxHeight = 'none';
div.style.boxSizing = 'content-box';
document.body.appendChild(div);
h = div.clientHeight;
document.body.removeChild(div);
return h;
}
but it seems far too verbose for calculating the current value for 100vh, and I'm not sure if there are other issues with it.
How about:
function viewportToPixels(value) {
var parts = value.match(/([0-9\.]+)(vh|vw)/)
var q = Number(parts[1])
var side = window[['innerHeight', 'innerWidth'][['vh', 'vw'].indexOf(parts[2])]]
return side * (q/100)
}
Usage:
viewportToPixels('100vh') // window.innerHeight
viewportToPixels('50vw') // window.innerWidth / 2
The difference comes from the scrollbar scrollbar.
You'll need to add the height of the scrollbar to the window.innerHeight. There doesn't seem to be a super solid way of doing this, per this other question:
Getting scroll bar width using JavaScript

CSS div fixed height, min width but expands width on content

The title says it all really, but despite several tries I cant actually get this to work.
Im looking for a DIV to have a fixed height, and min-width, I will display text in the div (dynamically changing), should any text be long enough to reach the bottom of DIV I want the the width of the div to increase to accomodate all the text.
Is there a CSS solution ?
From what I've gathered, here is what I got
https://jsfiddle.net/Lu3tu98b/2/
div{
padding: 20px;
background-color: wheat;
}
.myDiv {
height: 100px;
min-width: 150px;
overflow: scroll;
}
Could you please provide your code.
OK, so its not possible to do this in CSS, so Javascript is the way to go.
For anyone else searching for a similar solution here is the javascript routine that I built to give me the functionality I required.
Basically it checks if the div is in overflow and if so increases the width by 5% increments until the overflow is resolved, if on load the div isnt in overflow it decreases the width by 5% until it finds the overflow point then steps back one notch.
function changedivsize(){
widthmin = 35; // in percent
widthmax = 80; // in percent
modified = false; // flag to signify when wheve modified the div larger
while ( $("#quotation").prop('scrollHeight') > $("#quotation").height() ) { // if div is in overflow
modified = true; // set flag so we dont start making div smaller in section below
var widthpixels = $('#quotation').width();
var parentWidth = $('#quotation').offsetParent().width();
var widthpercent = 100*widthpixels/parentWidth; // find current width % of div (3lines)
if (widthpercent < widthmax) { // if not at limit
widthpercent = Math.round(widthpercent+5); // add 5%
$("#quotation").width(widthpercent+"%"); // change div width
}else{
break; // if we are at limit call it a day
}
} // repeat adding 5% until either we are out of overload or at limit
while (modified == false){ // basically same as above but reduce div for smaller texts
var widthpixels = $('#quotation').width();
var parentWidth = $('#quotation').offsetParent().width();
var widthpercent = 100*widthpixels/parentWidth;
if (widthpercent > widthmin) {
widthpercent = Math.round(widthpercent-5);
$("#quotation").width(widthpercent+"%"); // change div width
if ( $("#quotation").prop('scrollHeight') > $("#quotation").height() ){
widthpercent = widthpercent+5;
$("#quotation").width(widthpercent+"%"); // change div width
break;
}
}else{
break;
}
}
};
Is this good for what you need?
http://jsfiddle.net/KefJ2/343/
#container {
position: relative; /* needed for absolutely positioning #a and #c */
padding: 0; /* will offset for width of #a and #c; and center #b */
border: green 3px dotted; /* just for the show */
float: left; /* To dynamicaly change width according to children */
height: 300px;
}
#a {
white-space: nowrap;
}

Resize positioned background image

I have span, and it's styles are represented below. My problem is, it was designed to fill 60px*60px span. But now, I have to make it to fill another span with 50px*50px size. But it can't work with background position, because if i change the background-size, all position slips away. So is there any way (css or javascript hack) to resize an image or a block element with bacground-image after the image has been drawn? I want to avoid rewriting all background positions (I've got classes for each icons like ".entertainment").
<span class="icon icon2 entertainment"></span>
span.icon2 {
float: left;
width: 50px;
height: 50px;
margin: 5px 0 0 0;
}
#wrapper span.icon.entertainment {
background-position: -60px -360px;
}
#wrapper span.icon {
background: url(https://teeg.hu/image/icon.png);
}
Thanks for any help!
There is no pure css solution.
There is a js solution. Resize the background (background-size) as you did, then for each element move the position with the difference between sizes / 2 (in your case 5px).
You don't rewrite the classes, just iterate through elements.
Note: This might become an extensive operation, it is better to rewrite classes, even though that is what you want to avoid (40 is not so much... at most 30 min - testing included).
Ok, I've written some hack. I resized the background:
background-size: 100px 1550px;
and did it with jQuery:
$(function() {
$("span.icon2").each(function(index, value) {
var pos = $(this).css("background-position").split(' ');
var newPos = [];
newPos[0] = parseInt(pos[0].replace("px", "")) / 60 * 50;
newPos[1] = parseInt(pos[1].replace("px", "")) / 60 * 50;
$(this).css("background-position", newPos[0] + "px " + newPos[1] + "px");
});
});

Two triangular clickable area within a square

Basically I want to split a square div diagonally in two resulting in two triangles.
Each triangle has to respond to the hover event.
This is what I have so far but the problem is: if you go from one corner of the div straight to the opposite corner it doesn't re-trigger the hover event since the event is applied to the div element and not the define triangle area within.
I'm open to any suggestions, I don't even mind if I need to approach the problem from a different angle all together. There's got to be an easier solution, at least I hope!
The HTML
<div class="day_box">
</div>
The CSS
html, body { margin: 0; }
.day_box, .upper_left_hover, .lower_right_hover, .full_day {
background: url(/images/corner-sprites.png);
border: 1px solid black;
width: 25px;
height: 25px;
float: left;
margin: 100px;
}
.upper_left_hover { background-position: 75px 0; }
.lower_right_hover { background-position: 50px 0; }
.full_day { background-position: 25px 0; }
The JS
$(".day_box").hover(function(event){
var offset = $(this).offset();
var h = $(this).height() + offset.top;
if((h - event.pageY)>(event.pageX - offset.left)) {
console.log("Upper left");
$(this).toggleClass("upper_left_hover");
} else {
console.log("Lower right");
$(this).toggleClass("lower_right_hover");
}
});
The Fiddle: http://jsfiddle.net/zsay6/
You can use the mousemove event like this (adding mouseout to remove both of the classes when you leave the square):
$(".day_box").mousemove(function(event){
var offset = $(this).offset();
var h = $(this).height() + offset.top;
if((h - event.pageY)>(event.pageX - offset.left)) {
console.log("Upper left");
$(this).removeClass("lower_right_hover");
$(this).addClass("upper_left_hover");
} else if ((h - event.pageY)<(event.pageX - offset.left)) {
console.log("Lower right");
$(this).removeClass("upper_left_hover");
$(this).addClass("lower_right_hover");
}
}).mouseout(function(event)
{
$(this).removeClass("lower_right_hover upper_left_hover");
});
http://jsfiddle.net/zsay6/14/
I altered your fiddle to produce the effect you wanted... and I didn't clean it up at all (was just fiddling... haha)
Using the right-triangle formula (here), I set the given style you set up in your original fiddle. It also throws up some values in a debugging div so you can see it in action a little more clearly.
You can also use HTML map areas for that purpose:
http://www.w3schools.com/tags/tag_map.asp
On hover, change the background of the element to which the usemap is applied.

Categories