Create a segmented control-like with a draggable function - javascript

I have 2 divs positioned next to each other, and a background div. We'll call the background div "bg div". Whenever one of the 2 divs get selected, the bg div gets positioned on top of the selected div with a transition. Basically, something like a segmented controller.
The next step I want to do is, I want to make the bg div draggable. If it gets dragged, but not all the way to either side, then it should snap to whichever side the bg div is mostly at.
I'm looking for something like this:
When I set the bg div to be draggable, (using JQuery UI) it wasn't draggable. Only when I removed z-index: -1 did it become draggable. It also didn't snap to either side. It only snapped when the bg div got dragged basically all the way. Also, when I drag it, it has a weird effect to it. It waits a bit then drags. I think that's because the transition.
Problems
How can I make it draggable with of index: -1?
How can I make it snap to whichever side the bg div is mostly at?
How can I make it have a transition without working weird?
Without issues, but not draggable functionality: JSFiddle
With issues: JSFiddle
$('#bckgrnd').draggable({
axis: "x",
containment: "parent",
snap: ".labels"
});
#radios {
position: relative;
width: 370px;
}
input {
display: none;
}
#bckgrnd,
#bckgrndClear,
.labels {
width: 50%;
height: 30px;
text-align: center;
display: inline-block;
float: left;
padding-top: 10px;
cursor: pointer;
}
.labels {
outline: 1px solid green;
}
#bckgrnd {
background-color: orange;
position: absolute;
left: 0;
top: 0;
transition: left linear 0.3s;
}
#rad1:checked ~ #bckgrnd {
left: 0;
}
#rad2:checked ~ #bckgrnd {
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="radios">
<input id="rad1" type="radio" name="radioBtn" checked>
<label class="labels" for="rad1">First Option</label>
<input id="rad2" type="radio" name="radioBtn">
<label class="labels" for="rad2">Second Option</label>
<div id="bckgrnd"></div>
</div>

Working solution: http://jsfiddle.net/6j0538cr/ (I know you wont use it :))
How can I make it draggable with of index: -1?
Add two elements one that hold the label with 'pointer-events:none;' which will ignore all mouse events and 'z-index:3',
And second that will be the 'button' and will have 'z-index:1'.
Like that you will have one label that ignores all mouse events and float above all the elements with z-index:3, and the 'background' will still be draggable
How can I make it snap to whichever side the bg div is mostly at?
You can calculate it very easily using 'offset' and 'width' functions like so
//calculating the middle of the 'background'
var backgroundX = $('#bckgrnd').offset().left;
var backgroundWidth = $('#bckgrnd').outerWidth();
var backgroundMiddle = backgroundX + (backgroundWidth/2);
//calculating the middle of the radios on the page
var radiosX = $('#radios').offset().left;
var radiosWidth = $('#radios').outerWidth();
var radiosMiddle = radiosX + (radiosWidth/2);
//compare the two
if(radiosMiddle > backgroundMiddle){
//closer to the left
}else{
//closer to the right
}
How can I make it have a transition without working weird?
You can set the transition using jQuery 'animate' instad of mixing css and js animation.

draggable with index -1: Have a container div for the whole thing (radios?) trapping mouse events. mousedown you record the mouse x value. mousemove (with button down I suppose) you calculate the "delta" from current mouse x to mousedown x, and add that to the original x value of the thing you are "dragging".
snapping: just using min / max function to limit the delta, but it sounds like some animation is there even for the "snap". So for a mouse up within a certain end zone range, fire that animation to "snap" to one side or the other.
Also, the click inside certain bounds close to the edge fires that same snap.

I've could probably done this using <input> radio elements...
But any way on submit you can send the data-* value.
Here's my take:
$(".io-toggler").each(function(){
var io = $(this).data("io"),
$opts = $(this).find(".io-options"),
$clon = $opts.clone(),
$span = $clon.find("span"),
width = $opts.width()/2;
$(this).append($clon);
function swap(x) {
$clon.stop().animate({left: x}, 150);
$span.stop().animate({left: -x}, 150);
$(this).data("io", x===0 ? 0 : 1);
}
$clon.draggable({
axis:"x",
containment:"parent",
drag:function(evt, ui){
$span.css({left: -ui.position.left});
},
stop:function(evt, ui){
swap( ui.position.left < width/2 ? 0 : width );
}
});
$opts.on("click", function(){
swap( $clon.position().left>0 ? 0 : width );
});
// Read and set initial predefined data-io
if(!!io)$opts.trigger("click");
// on submit read $(".io-toggler").data("io") value
});
.io-toggler{
cursor:pointer;
display:inline-block;
position:relative;
font:20px/1.5 sans-serif;
background:url(http://i.stack.imgur.com/XVCAQ.png);
color:#fff;
border:4px solid transparent;
border-radius: 50px;
user-select:none;
-webkit-user-select:none;
-webkit-touch-callout:none;
}
.io-options{
border-radius:50px;
top:0;
left:0;
overflow:hidden;
}
.io-options span{
position:relative;
text-align:center;
display:inline-block;
padding: 3px 35px;
}
/* the jQ clone */
.io-options + .io-options{
position:absolute;
background:#fff;
width:50%;
height:100%;
white-space:nowrap;
}
.io-options + .io-options span{
color:#006cff;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<span class="io-toggler" data-io="0">
<span class="io-options">
<span>Thing1</span>
<span>Thing2</span>
</span>
</span>
<br><br>
<span class="io-toggler" data-io="1">
<span class="io-options">
<span>Yes</span>
<span>No</span>
</span>
</span>

Related

highlighting characters in text depending on position of page

I have a text on my website that scrolls horizontal through the page. I’m trying to get around 8 characters highlighted in black, while the rest is grey. But those characters are meant to vary as you scroll though, the highlighted bit should remain in place.
In case this doesn’t make any sense, if grey was an x, it should look something like this:
xxxxx xpsum dolox xxx xxxx
xxxx xxsum dolox sxx xxxx
xxx xxxum dolox six xxxx x
xx xxxxm dolox sit xxxx xx
I’m trying to get this done in jQuery, but I can’t get it to work. I also like to say that I’m not at all an expert in webdesign, so I don’t know what I’m doing. Anyway, I’ve tried two different approaches, one is to say “change colour of text when going over an underlying div”. The other approach is to change the colour of the text depending on the scrolling position, but the problem here is that it takes the scrolling position of the whole div, instead of a fixed position on the page. Both don’t work at the moment, examples are here:
jsfiddle 9p29tz2f
jsfiddle 9p29tz2f/1
If anyone has any ideas how to approach this, or needs some more clarification, please let me know. Many thanks!
Clone the text and set it as a child of the overlay box then scroll them together:
$(function(){
var $bodytext = $('#bodytext'),
$clone = $bodytext.clone();
//copy the text and append it to #black:
$clone.attr("id","clone").prependTo("#black");
//scroll #clone with #bodytext:
$bodytext.scroll(function(){
$clone.scrollLeft($bodytext.scrollLeft());
});
});
http://jsfiddle.net/9p29tz2f/2/
I've taken Teemu's solution and modified it a bit: http://jsfiddle.net/9af91wcL/2/
The important bits: The code moves a white DIV (#grey-overlay) on top of the text and makes it transparent. By adding black and white pixels, you get grey. The grey level is determined by the alpha channel (0.7 in the rgba() function).
You need to assign a height or it will look odd. I use 1.5em to make sure it doesn't overlap with the scroll bar of the #bodytext div.
Also make sure that the top/left position of both div's is the same.
In your real code, you can make the horizontal scrollbar disappear and scroll with JavaScript.
HTML
<div id="grey-overlay"></div>
<div id="bodytext">text...</div>
CSS
body {
background: #ffffff;
color: #000000;
font-family: sans-serif;
font-size: 200%;
}
#bodytext {
top: 15%;
width:200px;
height: 2em;
padding: 0;
position:absolute;
overflow-x:scroll;
overflow-y:hidden;
white-space: nowrap;
}
#grey-overlay {
background-color: rgba(255, 255, 255, 0.7);
width:40px;
height: 1.5em;
top:15%;
position:fixed;
z-index: 10;
}
You need to show the same content within #black as in #bodytext, and synchronize its position relative to #bodytext scrolling. This can be achieved by using an extra wrapper around #black. Something like this:
CSS:
#cover {
top: 15%;
height:50%;
width: 120px;
padding: 0;
position:fixed;
overflow-x: hidden;
background-color: #D8D8D8;
}
#black {
color: #000000;
width:100%;
height:100%;
top:0px;
left: 0px;
position:absolute;
white-space: nowrap;
z-index: 10;
}
#bodytext {
top: 15%;
width:100%;
height:85%;
padding: 0;
position:absolute;
overflow-x:scroll;
white-space: nowrap;
color: #D8D8D8;
}
HTML:
<div id="cover">
<div id="black"></div>
</div>
JS:
$(document).ready(function () {
var black = $('#black'),
btext = $('#bodytext');
black.text(btext.text()); // Clone the content
btext.scroll(function () {
var pos = btext.scrollLeft();
black.css('left', -pos + 'px'); // Set the position to match #bodytext
});
});
A live demo at jsFiddle.
Notice, that if you need some left margin, it has also to be "calculated in" to pos.

jquery pan a large image within small div container using buttons

Hi there I need to an interactive element using a large image. This image sized 1000x1000 pixel with simple imagery will contain several questions with yes or no. What I want to do is place this image within a small div (say 500x300) with hidden overflow and add hotspots on the image for the yes/no option. What I want is when the user clicks yes, then the hotspot link pans to specific x/y coordinates of the same large image. Viewer will only see within the 500x300 window. So on and so forth. Is this possible? It seems so simple yet only option I can find is the pan by mouse option or iframe option with complicated divs and anchors. I'm not an expert in java/jquery but would love to find a script that is adaptable. Please help!
This sounded fun so I made a custom solution real quick. Demo here: jsBin
It's heavily reliant on the proper CSS, so check that in the bin, but here's the JS part:
var choice = document.querySelectorAll('.choice'),
image = document.getElementById('image')
for ( var i=0; i<choice.length; i++) {
choice[i].addEventListener('click', function (event) {
var x = this.dataset['x'],
y = this.dataset['y'];
image.style.top = '-'+y+'px';
image.style.left = '-'+x+'px';
})
}
Use css transitions for animation. Set up the positions you want the buttons to move the image around to in the image using a series of javascript objects. Then, set up your anchors, text, etc using absolute positioning on top of the image inside of a div container. Finally, add a click action in jQuery to assign your different positions to the top and left css of that container.
The end result, then, will be that you click an anchor, the left and top positions are assigned to the container via css in jQuery, and the transitions will slide the image around with the anchors.
I set up a fiddle here.
Here's the html from the fiddle:
<div id="window">
<div id="container">
<img src="http://upload.wikimedia.org/wikipedia/en/1/1f/Kill_The_Lights_1000x1000.jpg" id="image">
<ul>
<li><a id="city" href="#">City</a></li>
<li><a id="bottom" href="#">Bottom</a></li>
</ul>
</div>
</div>
And the CSS:
#window {
width:500px;
height:300px;
overflow:hidden;
position:relative;
}
#window a {
position: absolute;
z-index: 2;
display: block;
padding: 10px;
background: rgba(255,255,255,.5);
}
#city {
top: 20px;
left: 20px;
}
#bottom {
top: 220px;
left: 220px;
}
#container {
-webkit-transition:left 2s, top 2s, -webkit-transform 2s;
transition:left 2s, top 2s, transform 2s;
position: absolute;
z-index: 1;
top: 0px;
left: 0px;
}
Here's some javascript to give an example of setting up the positions as objects.
var city = {
top: -200,
left: -200
};
var bottom = {
top: -700,
left: -100
}
$('a').click(function() {
var t = this.id;
var c = $('#container');
if (typeof eval(t) !== 'undefined') {
c.css({
'top': eval(t).top,
'left': eval(t).left
});
}
});
I've just made a Fiddle with a demo image from where you could proceed.
HTML:
<div class="imgHolder">
<div class="hotspot one">Click</div>
<img src="image.jpg" />
</div>
CSS:
.imgHolder {
overflow:hidden;
width:300px;
height:300px;
position:relative;
}
.hotspot.one {
position:absolute;
top:10px;
padding:2px;
background-color:#fff;
left:10px;
}
.hotspot:hover {
cursor:pointer;
}
img {
position:relative;
z-index:-1;
}
jQuery:
$(".hotspot").on("click", function () {
$("img").animate({
"right": "+=100px"
});
});
For reference: http://api.jquery.com/animate/
You could e.g. fade hotspots in and out on specific positions and use animate() to move to the next hotspot.

jQuery click on border of a div

I have a div that scrolls with a lot of text in it. My question is, is it possible to detect a click on the border of the div?
What I'd like to accomplish is if the user clicks on the bottom border (which is styled 4px wide with CSS), the div scrolls all the way to the bottom. Is this even possible without adding more markup?
You can try this:
$('div').click(function(e){
if(e.offsetY >$(this).outerHeight() - 4){
alert('clicked on the bottom border!');
}
});
Demo.
The .outerHeight() just returns the height of the content (including border). The e.offsetY returns the clicked Y relative to the element. Note about the outerHeight, if passing a bool true argument, it will include margin in the calculated value, the default is false, so it just returns content height + padding + border.
UPDATE: Looks like FireFox has its own way of behavior. You can see that when clicking, holding mouse down on an element, it's very natural and convenient to know the coordinates of the clicked point relative to the element. But looks like we have no convenient way to get that coordinates in the so-called FireFox because the e.offsetX and e.offsetY simply don't work (have no value). Instead you have to use the pageX and pageY to subtract the .offset().left and .offset().top respectively to get the coordinates relative to the element.
Updated demo
I never tried it, But I don't see why it shouldn't work :
Calculate the height of the element.
calculate the bottom border
calculate the offset inside the element itself, like in here
jQuery get mouse position within an element
Now you can check if the mouse position is inside the bottom border using some math.
I'm not sure how box-sizing fits into this, But that's how I would start around.
You have a wrapper around your element and set the padding to what ever you want to be detected.
jQuery
$("#border").click(function (e) {
if(e.target !== e.currentTarget) return;
console.log("border-clicked")
});
#border {
padding: 4px;
background: blue;
box-sizing: border-box;
cursor: pointer;
}
.box{
height: 100px;
width: 100%;
background: white;
cursor: default;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="border">
<div class="box"></div>
</div>
Vanilla JS
var border = document.getElementById("border");
border.onclick = function(e) {
if(e.target !== e.currentTarget) return;
console.log("border-clicked")
}
#border {
padding: 4px;
background: blue;
box-sizing: border-box;
cursor: pointer;
}
.box{
height: 100px;
width: 100%;
background: white;
cursor: default;
}
<div id="border">
<div class="box"></div>
</div>

How to make an element slide in with CSS3 transitions?

I really want to know how to make a sliding transition and im not sure if it can be done with pure css or if javascript is needed. I will give an example website. The transition i am talking about is when you select one of the square icons on left side bar and the blue description slides in to the div.
into the arctic
You could use the CSS animate property to animate the object by changing the margin and/or padding to create a sliding effect
It's quite easy to do in CSS, just position the containing div (with a class or id) in the non visible position and add a class when it needs to be visible (for adding that class you need JavaScript).
The class for visibility gets the final positioning.
On the base class you define a CSS transition that animates the properties that change, eg:
div.base {
transition: left 2s;
position:relative;
left:-200px; /* behind something else */
}
div.visible {
left:0px;
}
Edit: if performance is an issue you should use transform instead of left, e.g. transform: translate(-200px,0);. This also makes it possible to position the element how you need it, e.g. floating.
It is possible to do this purely in CSS depending on what you want to use as a trigger for the animation.
For a more persistent state like the linked example, it can be done with the checkbox (or radio) hack.
Note: just because it can be done, doesn't mean it should be done. While there are cases where this might work well for you, in general, you will have more control over the behavior and more flexibility in your markup by using javascript to trigger the animation. Browser support will also be a consideration.
For more information on the checkbox hack:
CSS Tricks: Stuff you can do with the “Checkbox Hack”
The CSS Ninja: Pure CSS collapsible tree menu
A simplistic example:
HTML:
<label for="toggle-1">A</label>
<input class="A" type="checkbox" id="toggle-1">
<label for="toggle-2">B</label>
<input class="B" type="checkbox" id="toggle-2">
<label for="toggle-3">C</label>
<input class="C" type="checkbox" id="toggle-3">
<div class="A">Panel A</div>
<div class="B">Panel B</div>
<div class="C">Panel C</div>
CSS:
/* Positions the checkbox off the screen */
input[type=checkbox] {
position: absolute;
top: -9999px;
left: -9999px;
}
/* Initial DIV position off screen - this is the panel */
div {
position: absolute;
width: 400px;
height: 100px;
line-height: 100px;
left: -400px;
-webkit-transition: left .5s ease;
}
/* Toggled State */
input[type=checkbox].A:checked ~ div.A,
input[type=checkbox].B:checked ~ div.B,
input[type=checkbox].C:checked ~ div.C {
left: 0;
}
demo fiddle
How it works: The checkbox is positioned offscreen. When the user clicks on a label, the associated checkbox is toggled. If the checkbox is checked, the matching sibling selector is triggered setting left to 0px - moving the panel to the right. If the checkbox is unchecked, the selector no longer matches causing the left property to revert to its original -400px value, moving the panel to the left.
Problems with this version: because these are checkboxes, they remain checked until some user action is performed. If the user doesn't close one of the panels the next panel to open will slide over or under the already open panel depending on its order in the DOM or z-index.
It is possible to do this with radio buttons as well, but the problem there is that there is no way to unselect a radio button in a pure CSS implementation, so, once selected a panel would always be visible until the next panel is selected.
You could mixin some javascript with the above to get the behavior you like or place more control in javascript.
A simplistic javascript example (I'd suggest finding better code than this!):
HTML
<div class="sel">A</div>
<div class="sel">B</div>
<div class="sel">C</div>
<div class="panel A">Panel A</div>
<div class="panel B">Panel B</div>
<div class="panel C">Panel C</div>
CSS (similar to what you had before but without the checkbox selectors)
/* Default State */
.panel {
position: absolute;
background: green;
width: 400px;
height: 100px;
line-height: 100px;
color: white;
text-align: center;
left: -400px;
-webkit-transition: left .5s ease;
}
/* Toggled State */
.opened {
left: 0;
}
Code:
var selectors = document.querySelectorAll('.sel');
var curSelected;
function select(evt) {
var panels = document.querySelectorAll('.opened');
var target = evt.target.innerText.trim();
var i;
for(i = 0; i < panels.length; ++i) {
panels[i].classList.toggle('opened');
}
if(target !== curSelected) {
document.querySelector('.panel.' + target).classList.toggle('opened');
curSelected = target;
} else {
curSelected = false;
}
}
for(var i = 0; i < selectors.length; ++i) {
selectors[i].addEventListener('click', select);
}
demo fiddle

css/javascript: number above border

how to display a small number (left top border) above a border around an element?
basically I am looking for a way to highlight elements and identify them with a number.
UPDATE:
Basically the elements highlight on mouseover by having border property defined. on mouseout, border is transparent (disappears).
what I'd like to do is how to display a number outside of the border highlight selected?
Solution I just thought about is using a custom generated numbered image border and just use border-image dynamically
Assuming you want to insert this number dynamically for any element without having to worry about relatives and absolutes here is a solution.
Code:
<div id="box"></div>
#box{
background:red;
height:140px;
width:250px;
margin:30px;
}
.number{
background:#ccc;
display:block;
font-weight:bold;
border:1px solid #000;
font-size:10px;
}
// Create an span element that will have the number
var number = $("<span />").text("5").addClass("number");
// Set the number width and height
var numberWidth = 10;
var numberHeight = 10;
// Get the target element
var element = $("#box");
// Get width, height and position
var elementWidth = element.width();
// These two are only necesary if you want to position
// the number in a different corner (e.g bottom, right)
var elementHeight = element.height();
var elementPosition = element.offset();
// Apply css to the number element
// Position is based on the target element position
number.css({
position: "absolute",
left: elementPosition.left - numberWidth,
top: elementPosition.top - numberHeight,
width: numberWidth,
height: numberHeight
});
// Insert the number to the body
number.appendTo("body");
If the identification numbers are constant and you don't want to include them in the markup as content, you can include them as attribute values and use :before pseudo-elements:
CSS:
p { position : relative }
p:hover:before {
content : attr(title);
position : absolute;
left : 0;
top : -1em
}
HTML:
<p title="1">blah blah</p>
<p title="2">blah blah</p>
<p title="3">blah blah</p>
If the identification numbers can be generated each time the page is rendered, you can use an automatic counter instead:
CSS:
p {
position : relative;
counter-increment : idnum
}
p:hover:before {
content : counter(idnum);
position : absolute;
left : 0;
top : -1em
}
See here for more information: http://www.w3.org/TR/CSS2/generate.html
What do you mean by "highlight"? Mouseover? You can provision for such visual effects by first wrapping your element with another div which will hold your number. And example:
<style>
.container:hover .label {
visibility: visible;
}
.label {
visibility: hidden;
}
.content {
margin: 1px;
border: none;
}
.content:hover {
margin: 0px;
border: 1px solid black;
}
</style>
<div class="container">
<div class="label">
123
</div>
<div class="content">
My Element
</div>
</div>
Edited to only display border on mouse over.

Categories

Resources