Optimizing jQuery dynamic adding of inset border effect - javascript

I'm not that experienced with jquery and javascript but I managed to get this code working for my Drupal website (I've included the beginning and end of the required Drupal jQuery calling code for reference, as the 'context' part makes it work with Ajax refreshing there so as a reference of sorts, feel free to ignore)
(function ($) {
Drupal.behaviors.borderfarba = {
attach: function (context, settings) {
var nmbr = 1; /// this will be a counter
var backcolor; /// here I store the generated random color
$(".movierow", context).each(function () {
/// I declare a class + a number from the counter
var clrclass = "clr" + nmbr;
/// I add this class to each .movierow class
/// which is inside a div containing divs with the other classes
$(this).addClass(clrclass);
/// storing the random color
backcolor = get_random_color();
/// pass the class and color value to function
addborder(clrclass, backcolor);
/// up the counter
nmbr++;
});
function addborder(clrclass, backcolor) {
/// before the inset border effect I also
/// apply the backcolor to a title and rating field
/// that appear over the image
$("." + clrclass + " .views-field-field-screenrate").css("background", backcolor);
$("." + clrclass + " .screentitle").css("background", backcolor);
/// apply the inset border effect
$("." + clrclass + " img").insetBorder({
borderColor: backcolor,
inset: 5
});
}
/// randomization functions
function rand(min, max) {
return parseInt(Math.random() * (max - min + 1), 10) + min;
}
function get_random_color() {
var h = rand(40, 130);
var s = rand(30, 75);
var l = rand(40, 60);
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}
/// add a nice slide down/up effect
/// on mouse in/out for the title
$(".movierow").hover(
function () { $(this).children(".screentitle").slideDown(); },
function () { $(this).children(".screentitle").slideUp(); }
);
}
};
})(jQuery);
The point is I want a new random color within a specified range (like in my case from reddish hues to green) applied to the jQuery inset border effect found here which is then applied to each image on my page (which are generated dynamically). PS. I think I found the random color generation code snippet somewhere around here, so thanks to that one person, don't want credit where it's not due.
Thus I used a loop which adds a new class to each image and then applies the inset border function to each class.
I'm wondering if there's any way of optimizing this code to be more efficient, as this is the only way I figured how to do it.
Cheers and thanks for any advice, hoping to improve my under par programming skills
UPDATE I have modified the code a bit (and added comments), as I needed the same random background color for 2 additional fields that appear over the image (title, rating)

Not an answer, but a question...
Why do you convert 'nmbr' to a string?
/// I declare a class + a number from the counter
var clrclass = "clr" + nmbr.toString();
/// I add this class to each .movierow class
/// which is inside a div containing divs with the other classes
$(this).addClass(clrclass);
Wouldn't this be simpler?...
$(this).addClass('clr'+nmbr);
Otherwise, your code looks very performant to me, but I'm far from an expert.

Related

random background color generator with pure javascript (no jquery)

var color;
function randomColor() {
color = '#' + Math.random().toString(16).slice(2, 8); // Random number converted to hexadecimal with toString(16) and then slice to make it a 6 digit number. like fe2e4d or f4e22e
};
var change = document.getElementById('color_change');
change.addEventListener('click', function() {
document.getElementById('random_background').style.backgroundColor = "color" ;
});
div{
width:300px;
height:300px;
}
<div id="random_background"></div>
<button id="color_change" >Color Change</button>
I think the last part is where the problem lies, but i am not able to find anywhere how to implement it correctly. Please help.
As stated by #Teemu in the comments, you are setting a string to the backgroundColor property instead of setting the actual value of the color variable.
Here goes an example that will help you, without the use of the var color;
make your randomColor() function return the value directly. Then call that function in the backgroundColor property, see below:
function randomColor() {
return '#' + Math.random().toString(16).slice(2, 8);
};
var change = document.getElementById('color_change');
change.addEventListener('click', function() {
document.getElementById('random_background').style.backgroundColor = randomColor();
});
div{
width: 300px;
height: 150px;
}
<div id="random_background"></div>
<button id="color_change" >Color Change</button>
If you want to use the var color, then call randomColor() before set the backgroundColor property, and then set it as a variable, not a string:
...
randomColor();
document.getElementById('random_background').style.backgroundColor = color;
"div" has nothing height when is blank
you should initialize height to your div.
also use correct variable for color.
good luck
Here a solution using random numbers for each triplet:
function rT(){
//random number between 0 and 255
//you could change the limits or pass a parameter to this function
return Math.floor(Math.random() * (255 - 0)) + 0;
}
var change = document.getElementById('color_change');
change.addEventListener('click', function() {
document.getElementById('random_background').style.backgroundColor = "rgb("+rT()+" "+rT()+" "+rT()+")"; });
//in this case we use this form rgb(0-255,0-255,0-255)
Full example here: https://jsfiddle.net/ztavxrse/
Changing the limits https://jsfiddle.net/c5j6fpnL/

Calculate div number with distance

I'm making a carousel like a casino roulette but i can't find the way to know which div number is when i make the animation. I'm trying to calculate by distance when i make the animation loop but i doesn't work
Here's my example
https://codepen.io/anon/pen/xXbpJr?page=1&
var giftamount = 10;
var gw = $('.gift').outerWidth(true);
var giftcenter = gw/2;
var cycle = 7;
var containercenter = $('.boxwrapper').outerWidth(true)/2;
for(var i = 0; i <=5; i++)
{
var giftduplicate = $('.giftwrapper').children().clone(true,true);
$('.giftwrapper').append(giftduplicate);
}
$('.button').click(function(){
var btn = $(this);
btn.hide();
var randomgift = Math.floor((Math.random() * 10) + 1);
var distance = giftamount * gw * cycle + containercenter + (randomgift*gw) - giftcenter;
console.log(distance);
$( ".giftwrapper" ).css({left: "0"});
$('.giftwrapper').animate({left: "-="+distance},10000,function(){
alert('You Won Gift' + randomgift);
btn.show();
});
});
i get the wrong number of div, i tried a lot of combination but it doesn't work
You can try and substitute this for the distance
var distance = giftamount * cycle * gw + (randomgift*gw) - containercenter -24;
The idea is the following: with distance=- containercenter; you would move to be left-aligned with the center of the container.
To that you add a certain number of cycles giftamount * cycle * gw and finally a random number of gift elements ((randomgift*gw)).
I could not figure out where the constant -24 comes from. I hard-coded and it needs to be better defined but I guess it might depend on some margins/approximations/jQuery/CSS/??
Now you should see that the animation always stops at the same point within the gift element (in the middle). To add a random deviation you could ad a small deviation dev (that lets you stay within the gift element) like this:
var dev = Math.random()*(giftcenter+1);
var distance = giftamount * cycle * gw + (randomgift*gw) - containercenter -24 +dev;
Updated demo: https://codepen.io/anon/pen/RLNeBX
If you want to get the prize that is underneath the pointer (the vertical red bar), you actually do not have to compute the distance. Instead, you can make use of a really handy but somewhat less known DOM API method known as elementFromPoint(x, y), where you can obtain a reference to the topmost DOM node under the x,y coordinate of the page.
In order for this to work, x and y will have to correspond to the visual center of the pointer, which can we can simply calculate by using:
var $pointer = $('.rafflebox .pointer');
var pointerX = $pointer.offset().left + $pointer.width() * 0.5;
var pointerY = $pointer.offset().top + $pointer.height() * 0.5;
In jQuery's animation callback, you simply can retrieve the element (aka the prize) underneath this coordinate:
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var prize = document.elementFromPoint(pointerX, pointerY);
// Show it again
$pointer.show();
Now you have the correct reference to the DOM node, it is up to you to decide what kind of metadata you want to store in the "prize" DOM node. For example, you can embed a HTML5 data- attribute in your HAML:
%img{:src => "http://placehold.it/125x125?text=Prize+#{i}", :data => {:prize => "Prize #{i}"}}
...which simply stores the text Prize (n) (where n is the prize number) in the attribute data-prize, and we can access it later using:
var prize = document.elementFromPoint(pointerX, pointerY);
console.log($(prize).data('prize'));
When we replace part of your code with what I have suggested, you get this:
// Get visual center of pointer
var $pointer = $('.rafflebox .pointer');
var pointerX = $pointer.offset().left + $pointer.width() * 0.5;
var pointerY = $pointer.offset().top + $pointer.height() * 0.5;
$( ".giftwrapper" ).css({left: "0"});
$('.giftwrapper').animate({left: "-="+distance},10000,function(){
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var prize = document.elementFromPoint(pointerX, pointerY);
// Show it again
$pointer.show();
alert('You Won Gift ' + $(prize).data('prize'));
btn.show();
});
Here is your updated pen with a working example: https://codepen.io/terrymun/pen/dVPdMg
Updated example
There is a very small chance that the pointer will land in between prizes. To prevent this, you will want to use padding instead of margin on the .gift element:
.gift {
// Change margin to padding
padding: 0px 4px;
}
...and perform additional checks on the returned prize node:
// Hide pointer first, otherwise it will be returned as the topmost element
$pointer.hide();
// Get element from pointer's visual center
var $prize = $(document.elementFromPoint(pointerX, pointerY));
// If prize lands on the .gift element instead
if(!$prize.is('img'))
$prize = $prize.find('img')
// Show it again
$pointer.show();
alert('You Won Gift' + $prize.data('prize'));
btn.show();
The pen here is simply a fork of the original solution, but with exaggerated horizontal padding to increase the chance of the pointer landing in between iamges: https://codepen.io/terrymun/pen/rGaJmY

In PaperJS allow the user to edit a TextItem like regular text input field?

I am using PaperJS to make a canvas app that generates balloons with text inside each balloon. However I would like to allow the user to edit the text inside each balloon to whatever they want it to say.
Is it possible to allow a user to edit a PaperJS TextItem just like a HTML text input field?
The short answer is no, unless you implement parallel functionality from scratch. The solution I have used is to let the user draw a rectangle then overlay the rectangle on the canvas with a textbox or textarea at the same location using absolute positioning. It requires an additional level of abstraction but can work quite well.
It's non-trivial, but here's a basic framework that shows a bit about how it works. I may get around to making it available online at some point but it will take a bit so I'm not sure when. I'm also extracting this on-the-fly from a larger system so if you spot any errors let me know.
var rect;
var tool = new paper.Tool();
// create a paper rectangle. it's just a visual indicator of where the
// text will go.
tool.onMouseDown = function(e) {
rect = new paper.Path.Rectangle(
from: e.downPoint,
to: e.downPoint,
strokeColor: 'red',
);
}
tool.onMouseDrag = function(3) {
if (rect) {
rect.remove();
}
rect = new paper.path.Rectangle({
from: e.downPoint,
to: e.point,
strokeColor: 'red'
});
}
tool.onMouseUp = function(e) {
var bounds = rect.bounds;
var textarea = $("<textarea class='dynamic-textarea' " +
"style='position:absolute; left:" + bounds.x +
"px; top:" + bounds.y + "px; width: " + bounds.width +
"px; height: " + bounds.height +
"px; resize;' placeholder='Enter text'></textarea>");
// make the paper rectangle invisible for now. may want to show on
// mouseover or when selected.
rect.visible = false;
// add the text area to the DOM then remember it in the path
$("#parent-div").append(textarea);
rect.data.textarea = textarea;
// you may want to give the textarea focus, assign tab indexes, etc.
};

About image rotation once element with specific id is clicked

Logo and elements from ul once clicked rotates image. By default image is already rotated by certain degrees, then on each click image rotates to necessary value.
So far I was using the following:
$("#objRotates").css('opacity','.2');
var value = 0;
var prev_value = 0;
$( "li" ).click(function() {
var text=$(this).text();
if(text==="text1"){value=0;}
if(text==="text2"){value=33;}
if(text==="text3"){value=66;}
if(prev_value != value){
$("#objRotates").animate({opacity:'1'});
$("#objRotates").rotate({
animateTo:value,
easing: $.easing.easeInOutExpo,
center: ["25px", "150px"],
callback: function(){$("#objRotates").animate({opacity:'0.2'});}
});
}
prev_value = value;
});
Above code is the one that was used before, where images start position was 0 and its animation was triggered from link text.
Using jqueryRotate.js examples(here)
How do I change the code, so that images start position is certain degrees and animation starts if element with specific ID is clicked?
Give at least clue..Cause for now, looking at my old code, I am lost. Thanks in advance.
SIMPLIFIED FIDDLE
Ok, so I've created a couple of samples for you to check out. The first one is very basic and I've simplified the code a little to make it easier to understand. This one just uses completely static values and a static elementId for the event, which I'm pretty sure answers your question based on your response to my comment yesterday. http://jsfiddle.net/x9ja7/594/
$("#elementId").click(function () {
var startingAngle = 45;
var endingAngle = 90;
var elementToRotate = "img";
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
});
});
But I wanted to give another example as well that would be dynamic and repeatable for multiple elements. With the code above, you would have to copy/paste the same code over and over again if you want to perform this animation by clicking different elements. Here's an alternative. In this example, you set all of your parameters in the data attributes in the clickable element, then the function is completely repeatable, you only have to write it once. Less code = everyone happy! Here's the example: http://jsfiddle.net/x9ja7/595/
//#region Default starting angles
$("#image1").rotate({ angle: 90 });
$("#image2").rotate({ angle: 20 });
//#endregion
$(".rotateAction").click(function () {
//#region Optional parameter - used in the optional callback function
var $self = $(this);
//#endregion
var startingAngle = Number($(this).attr("data-startingangle"));
var endingAngle = Number($(this).attr("data-endingangle"));
var elementToRotate = $(this).attr("data-elementtorotate");
//#region If the current angle is the ending angle, reverse the animation - this can be removed if you want, I thought it may be cool to show some of the things you can do with this.
var currentAngle = $(elementToRotate).getRotateAngle();
if ( currentAngle[0] === endingAngle) {
startingAngle = Number($(this).attr("data-endingangle"));
endingAngle = Number($(this).attr("data-startingangle"));
}
//#endregion
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
//#region This is optional - uncommenting this code would make the animation single-use only
//, callback: function () { $self.off().removeClass("clickable"); }
//#endregion
});
});
Hope this helps. If you need any other assistance, please let me know.

Separating HTML elements into columns with proper spacing (JQuery and CSS)

I am trying to make a Windows 8 like interface for my webpage. I have created articles that act as tiles and have a random generator that makes the tile small or large. I am trying to make these look like they are in columns depending on the width of the screen. When I change the screen width the tiles do not seem to be properly spaced which is driving me nuts. I am new to css and jquery so I am still learning and always open to learning new ways to do things. I would really appreciate some help on this column and spacing issue.
NOTE: My tiles usually have pictures and after I changed the code just to show up as color tiles. Now they are not always showing but I will fix that issue.
For example: each column should have a width of one double box or two single box's. And depending on the screen width...if bigger the more columns will display and the smaller the less amount of columns it will display.
Here is my current code:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="http://code.jquery.com/jquery-2.1.0.min.js" type="text/javascript"></script>
<script src="Script/jquery.lorem.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function ()
{
var colors = ["#2672ec", "#00a300", "#97009f", "#094db5", "#da532c", "#af1a3f", "#613cbc", "#008ad2"];
var doubleBoxFlag = [true, false, false, false, false, false];
var pictures = ["Images/1.jpg", "Images/2.jpg", "Images/3.jpg", "Images/4.jpg", "Images/5.jpg", "Images/6.jpg", "Images/7.jpg", "Images/8.jpg", "Images/9.jpg", "Images/10.jpg", "Images/11.jpg"];
var defaultClass = '.box';
for (var i = 0; i < Math.floor((Math.random() * 64) + 34) ; i++)
{
var rand = Math.floor(Math.random() * pictures.length);
var boxRand = Math.floor(Math.random() * doubleBoxFlag.length);
var currentClass = defaultClass + i;
var currentClassJ = 'box' + i;
//For picture tiles:
//$("#Interface").append("<article class=" + currentClassJ + " " + "style='background-image: url(" + pictures[rand] + ")" + "'><span>" + i + "</span>");
//For Color Tiles:
$("#Interface").append("<article class=" + currentClassJ + " " + "style='background-color:" + colors[rand] + "'><span>" + i + "</span>");
if (doubleBoxFlag[boxRand]) {
$(currentClass).css("width", "374px");
$(currentClass).css("padding-right", "20px");
}
else
$(currentClass).css("width", "187px");
$(currentClass).css("height", "187px");
$("article").css("float", "left");
$("article").css("margin", "11px");
$("span").css("display", "block");
$("span").css("padding-top", "167px");
$("span").css("padding-left", "12px");
}
//if (screen.width <= 480)
// $("#Interface").css("width", "470px");
//if (screen.width >= 1000 && screen.width <= 1799)
// $("#Interface").css("width", "470px");
//if (screen.width >= 1800)
// $("#Interface").css("width", "470px");
// This line below should be adding the random word to each of the articles
$('span').lorem({ type: 'words', amount: '1', ptags: false });
});
</script>
</head>
<body background = "Images/bg.png">
<div id="Interface"></div>
</body>
</html>
Now that I understand your problem, I propose to you start using css media queries. Basicaly for three reasons:
It's one way to solve your problem (duh)
This scripty resising and calculations will run slower when it comes to the real world.
It's much more clear and painless.
Make a css file with all rules that you want at determined screen size, then do this again for as many screen sizes you want to match. Remeber you can use all css tricks available to one determined screen size to achieve the look & feel that you want, because rules aplied under a media query will not mess with your css in other screen sizes.
After all, organize all the stylesheets in a single files and wrap them inside a proper media query.
Give it a try, you'll love it.
And yes, it's supported in at least the three earlier versions of IE, I guess.

Categories

Resources