I am writing my first custom function/addon for jQuery, it's been a lot of fun. basically it will load a bunch of images from an array and create a slider to enable you to pick one from the list and display it as the main image.
in my options I have added an onClick event, but I want to be able to pass variables to this event for the end user to set in the options, such as the image src, so when you click an image the optional onClick function fires and the end user could then return the src of the image clicked, he is my code for a better example, it may be a tad dirty as I haven't cleaned it and its full of code that needs polishing but it works.
(function($){
$.fn.imagePicker = function( options ) {
var defaults = {
width: 398,
height: 230,
imageArray: ["/img/news/emailpi.jpg", "/img/news/debit.jpg", "/img/news/aim-high.jpg", "/img/news/Koala.jpg", "/img/news/170217_get_connected.jpg",
"/img/news/10.jpg", "/img/news/1000864_street_variations__doors_2.jpg", "/img/news/1005134_ear_defenders.jpg", "/img/news/1080177_magnifying_glass.jpg", "/img/news/160.jpg",
"/img/news/161.jpg", "/img/news/162.jpg", "/img/news/163.jpg", "/img/news/2012.jpg", "/img/news/48.jpg",
"/img/news/8.jpg", "/img/news/12.jpg", "/img/news/ski.jpg", "/img/news/storm.jpg", "/img/news/tax-img.jpg",],
show: 10,
thumb: {
width:70,
height: 60,
borderWidth: 1,
borderColour: "#CCC",
borderStyle: "solid",
padding:3
},
mainImage: {
width: 150,
height:200,
borderColour:"#CCC",
borderStyle:"solid",
padding:3
},
leftScroll: 50,
rightScroll: 50,
interval: 5,
onClick: function(){},
onScrollLeft:function(){},
onScrollRight:function(){},
debug: false
};
var options = $.extend( true, defaults, options );
//Preload the images in the array
ip_preloader( options.imageArray )
$(this).css({width:options.width, height:options.height, overflow:'hidden'});
$(this).html( "<div class='ip-main-images' style='text-align:center'></div>\n\
<div class='ip-image-menu' style='position:relative; height:"+(options.thumb.height+5)+"px; width:"+( ((options.thumb.width + options.thumb.padding + ( options.thumb.borderWidth*2 ))*options.imageArray.length) )+"px; overflow:hidden;'>\n\
<div class='ip-menu-images-overlay' style='width:"+options.width+"px; position:absolute; top:0;'>\n\
<div class='ip-left-hotspot' style='background:url(/admin_v2/css/images/white_trans_10x10.png);position:absolute; left:0; top:0; width:"+options.leftScroll+"px; height:"+( options.thumb.height+( options.thumb.borderWidth*2 ) )+"px; z-index:99;'></div>\n\
<div class='ip-right-hotspot' style='background:url(/admin_v2/css/images/white_trans_10x10.png);position:absolute; right:0; top:0; width:"+options.rightScroll+"px; height:"+( options.thumb.height+( options.thumb.borderWidth*2 ) )+"px; z-index:99;'></div>\n\
</div>\n\
<div class='ip-menu-images' style='position:relative; top:0;'>\n\
</div>\n\
</div>\n\
<div class='ip-mouse-pos'></div>" );
var container = $(this);
var menu = $(this).find( ".ip-menu-images" );
var main = $(this).find( ".ip-main-images" );
main.html( "<img src='"+options.imageArray[0]+"' width='"+options.mainImage.height+"' height='"+options.mainImage.width+"' style='margin:0 auto; width:"+options.mainImage.width+"px' />" );
for( i=0; i<options.imageArray.length; i++ ){
menu.append( "<img src='"+options.imageArray[i]+"' style='float:left; margin-right:"+options.thumb.padding+"px; border:"+options.thumb.borderWidth+"px "+options.thumb.borderStyle+" "+options.thumb.borderColour+";' alt='' class='' width='"+options.thumb.width+"' height='"+options.thumb.height+"' />" );
}
$(".ip-image-menu img").live("click", function( ){
var src = $(this).attr("src");
$(".ip-main-images img").attr("src", src);
options.onClick( src );
});
var leftpos = 0;
$(".ip-left-hotspot").bind('mouseenter', function() {
this.iid = setInterval(function() {
if( leftpos != options.leftScroll ){
leftpos ++;
menu.css("left", leftpos);
options.onScrollLeft();
}
if(options.debug)$(".ip-mouse-pos").html( "LeftPos: "+menu.css("left") );
}, options.interval);
}).bind('mouseleave', function(){
this.iid && clearInterval(this.iid);
});
$(".ip-right-hotspot").bind('mouseenter', function() {
this.iids = setInterval(function() {
if( leftpos != "-"+menu.width()){
leftpos --;
menu.css("left", leftpos);
options.onScrollRight();
}
if(options.debug)$(".ip-mouse-pos").html( "LeftPos: "+menu.css("left") );
}, options.interval);
}).bind('mouseleave', function(){
this.iids && clearInterval(this.iids);
});
function ip_preloader( imagesArray )
{
// counter
var i = 0;
// create object
imageObj = new Image();
// start preloading
for(i=0; i<=3; i++)
{
imageObj.src=imagesArray[i];
}
}
; };
})(jQuery);
if you do a find for ("src") will jump you to the bit of code where I call options.onClick and I just want to pass the src to that event so the end user has access to it, should they want to populate a hidden form field with the image src etc. And also so I know how it works, as I am struggling to google for it without the correct terminology. (am not even sure if what I am trying to do is called "an event")
You could use the following:
if(typeof(options.onClick) == 'function'){
options.onClick(x, y, z);
}
You can just give the parameters you want to the function. JavaScript doesn't care how many arguments you give the function. You subscriber just neest to specify the parameters in his handler.
This example shows that it works.
var onclick;
onclick = function(a){
alert(a);
};
onclick('Hellow world', 'I am useless');
So this should work as well:
$('#myElement').imagePicker({
onclick: function(src){
alert(src);
}
});
Maybe you could make your example a bit smaller. This bulk of code is a little bit to much.
This is a loose example but you could allow the user to pass function into the constructor, in this example I am passing an object of callbacks but afaik it would amount to the same thing
var a = "xyz";
var Foo = function(args, callbacks) {
var a = "abc";
this.bar = callbacks.bar(a);
};
var foo = new Foo({}, { bar: function(a){ alert(a) } });
foo.bar(); // will alert "abc" NOT "xyz"
here is a demo
Related
I am exporting the data present inside the div to PDF when user click on the export button. I want to show each div content to show in individual pages inside the PDF.
The above scenario is working in the demo https://plnkr.co/edit/KvkVlYmmmJiZ71sghb1l?p=preview
The same when applied to below code, it is not working.
Demo here : https://plnkr.co/edit/P9nUSRY5TytkonM6dUHl?p=preview
js code:
$scope.export = function() {
var pdf = new jsPDF('landscape');
var source = $('#append-source');
$('.myDivClass').each(function(){
var html = "<div>"+$(this) + "</div><!--ADD_PAGE-->";//the code is broken with this line
// var html = $(this);
source.append(html);
});
console.log(source);
pdf.addHTML(
source, 0, 0, {
pagesplit: true
},
function(dispose){
pdf.save('test3.pdf');
}
);
}
It is not recommended to use jquery like this inside an angular app. To see why look here: Can we use both jQuery and Angular in our Web Application?
However what you want to do is possible if you put the following into your controller:
$scope.export = function() {
var pdf = new jsPDF('landscape');
var source = "";
var width1 = pdf.internal.pageSize.width;
$('.myDivClass').each(function(){
var textForPdfPage = $(this).children().eq(1).children()[0].textContent;
var html = "<div>"+ textForPdfPage + " </div><!--ADD_PAGE-->";
source+=html;
});
margins = {
top: 80,
bottom: 60,
left: 10,
width: '100%'
};
pdf.fromHTML(
source, // HTML string or DOM elem ref.
margins.left, // x coord
margins.top, { // y coord
'width': width1 // max width of content on PDF
},
function (dispose) {
pdf.save('test.pdf');
},
margins
);
}
Your main problem is that when you where trying to create your html string you only used $(this). $(this) gives you a jquery object. The string you want to put on the page is inside this object and is accessed using the jquery .children() method.
Here is a way of doing what you asked using addHTML() instead of fromHTML():
$scope.export = function() {
var pdf = new jsPDF('landscape');
var pdfName = 'test.pdf';
var options = {};
var $divs = $('.myDivClass') //jQuery object of all the myDivClass divs
var numRecursionsNeeded = $divs.length -1; //the number of times we need to call addHtml (once per div)
var currentRecursion=0;
//Found a trick for using addHtml more than once per pdf. Call addHtml in the callback function of addHtml recursively.
function recursiveAddHtmlAndSave(currentRecursion, totalRecursions){
//Once we have done all the divs save the pdf
if(currentRecursion==totalRecursions){
pdf.save(pdfName);
}else{
currentRecursion++;
pdf.addPage();
//$('.myDivClass')[currentRecursion] selects one of the divs out of the jquery collection as a html element
//addHtml requires an html element. Not a string like fromHtml.
pdf.addHTML($('.myDivClass')[currentRecursion], 15, 20, options, function(){
console.log(currentRecursion);
recursiveAddHtmlAndSave(currentRecursion, totalRecursions)
});
}
}
pdf.addHTML($('.myDivClass')[currentRecursion], 15, 20, options, function(){
recursiveAddHtmlAndSave(currentRecursion, numRecursionsNeeded);
});
}
I left the other answer so people can see both ways of doing it.
I've got the code below. I was using it to use 1 image and use the 'rel' and 'title' tags to populate words to go along with the actual image. This creating a banner like system that used text instead of all images. Now, what I want to do is use the 'rel' tag to populate an image; however, don't know how to modify this javascript code to do this.
<img title="This is a title that will appear as text above the image" rel="image1" alt="SEO Image 1" src="../images/backdrop2.png">
as you can see, rel is equal to image1...so what it needs to do is use this to make...
<img class="something" src="images/image1.png">
All its doing is using the word that is in 'rel' to fill in that 1 spot and it automatically fills in the rest in the code.
<script type="text/javascript">
jQuery(function( $ ){
var efx = "fade", // "slide" || "fade"
animationTime = 600,
pauseTime = 4000,
$gal = $("#images_holder"),
$mov = $("#moving_part"),
$sli = $mov.find("> div"),
$btn = $("#prev, #next"),
$dsc = $("#description"),
$wrd = $("#word"),
w = $gal.width(),
n = $sli.length,
c = 0, // Counter // Start index
itv; // Interval
// SETUP (fade or slide?)
$mov.width(w*n);
if(efx==="fade") $sli.css({position:"absolute", left:0}).fadeOut(0).eq(c).fadeIn(0);
function populateWord() {
$wrd.text( $sli.eq(c).find("img").attr("rel") );
}
function populateDescription() {
$dsc.text( $sli.eq(c).find("img").attr("title") );
}
function anim() {
c = c<0 ? n-1 : c%n; // loop-back if exceedds
populateDescription();
populateWord();
if (efx==="fade") {
$sli.fadeOut(animationTime).eq(c).stop().fadeIn(animationTime);
}else if(efx==="slide") {
$mov.stop().animate({left: -c*w});
}
}
function auto() {
itv = setInterval(function(){
++c;
anim();
}, pauseTime);
}
function pause() {
return clearInterval( itv );
}
$gal.hover(pause, auto);
$btn.on("click", function(){
c = this.id==="next" ? ++c : --c;
anim();
});
populateDescription();
populateWord();
auto();
});
</script>
function populateWord() {
var src = 'images/'+$sli.eq(c).find("img").attr("rel")+'.png';
$wrd.html('<img class="something" src="'+src+'">');
}
I just started using Raphael.js and I am stumped on adding an id to a path. I have read a lot of posts on how to do it, but I think the way my file is set up doesn't allow me to easily translate those solutions.
I have an init.js file and a path.js file
init.js
var r = Raphael('man', 500, 573),
attributes = {
fill: '#204ad3',
opacity: '0.0',
'stroke-linejoin': 'round'
},
arr = new Array();
for (var muscles in paths) {
var obj = r.path(paths[muscles].path);
obj.attr(attributes);
arr[obj.id] = muscles;
obj
.hover(function(){
this.animate({
fill: '#204ad3',
opacity: '0.3'
}, 300);
}, function(){
this.animate({
fill: attributes.fill,
opacity: attributes.opacity
}, 300);
})
.click(function(){
document.location.hash = arr[this.id];
var point = this.getBBox(0);
$('#man').next('.point').remove();
$('#man').after($('<div />').addClass('point'));
$('.point')
.html(paths[arr[this.id]].name)
.prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
.prepend($('<img />').attr('src', 'flags/'+arr[this.id]+'.png'))
.css({
left: point.x+(point.width/2)-80,
top: point.y+(point.height/2)-20
})
.fadeIn();
});
$('.point').find('.close').live('click', function(){
var t = $(this),
parent = t.parent('.point');
parent.fadeOut(function(){
parent.remove();
});
return false;
});
}
path.js file:
var paths = {
neck: {
name: 'Neck',
path: 'd="M412.294,73.035c0,0,7.661,28.869,9.406,31.78c1.746,2.911,4.657,2.911,9.896,2.911 s9.313-1.746,9.896-5.239c0.582-3.493,6.985-28.523,6.985-28.523s-2.963,2.599-6.232,5.984c-2.543,2.632-7.2,5.904-11.088,5.904 c-3.889,0-6.705-2.431-10.367-5.04C418.063,78.868,418.08,79.22,412.294,73.035z"',
},
pecks: {
name: 'Pecks',
path: 'd="M379.581,117.994c0,0,0.396-1.586,6.936-4.558c6.539-2.972,13.475-5.351,16.844-6.737 c3.369-1.387,4.559-1.784,4.559-1.784s13.674,2.973,15.061,3.17c1.387,0.198,4.36,1.982,8.72,1.982s9.511-1.387,11.097-2.18 s10.307-2.973,11.693-3.171s1.387-0.198,1.387-0.198s12.286,3.369,16.845,4.36c4.558,0.991,8.917,2.378,9.116,3.765 c0.197,1.387,1.584,4.954,1.584,6.341s-0.197,5.945-0.396,6.738c-0.198,0.792-3.171,15.457-4.757,21.997 c-1.585,6.54-1.188,8.918-7.331,11.494s-10.899,7.53-22.79,2.378s-13.277-5.549-17.241-5.152s-11.098,3.963-14.862,5.351 c-3.766,1.387-16.251,2.179-20.412-0.198c-4.162-2.378-10.9-9.314-12.881-16.844c-1.981-7.531-3.963-16.052-4.359-17.638 C377.995,125.525,377.798,121.165,379.581,117.994z"',
},
}
The generated SVG element does not have an id, nor do I know how to get one in there. Any advise/help would be much appreciated.
This will add the id attribute to the svg path elements:
var id = 0;
for (var muscles in paths) {
var obj = r.path(paths[muscles].path);
obj.node.id = "muscles_or_whatever_you_want_" + id;
id++
//....
to add an id to a SVG element ....
paper.path( path data ).node.id = 'pathIdString';. to test ... try alert( document.getElementById("pathIdString").id );. should return the id
It looks like what you are trying to do is to pop up a div with an image and a close link above the path that is clicked. The problem is that you are confusing the Raphael id of the path object with the index in your paths array. You probably want to eliminate arr entirely and pass the index to your handler through a closure:
.click(function(index) { return function() {
document.location.hash = index;
var point = this.getBBox(0);
$('#man').next('.point').remove();
$('#man').after($('<div />').addClass('point'));
$('.point')
.html(paths[index].name)
.prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
.prepend($('<img />').attr('src', 'flags/'+index+'.png'))
.css({
left: point.x+(point.width/2)-80,
top: point.y+(point.height/2)-20
})
.fadeIn();
}; }(muscles));
I've some images on a page which are loaded randomly and they are over 100kbs, is it possible to have it fully loaded then fade it in rather than progressively loading it?
My JS looks like this...
(function($){
$.randomImage = {
defaults: {
//you can change these defaults to your own preferences.
path: '_images/', //change this to the path of your images
myImages: ['hero_eagle.jpg', 'hero_giraffe.jpg', 'hero_owl.jpg', 'hero_rabbit.jpg']
}
}
$.fn.extend({
randomImage:function(config) {
var config = $.extend({}, $.randomImage.defaults, config);
return this.each(function() {
var imageNames = config.myImages;
//get size of array, randomize a number from this
// use this number as the array index
var imageNamesSize = imageNames.length;
var lotteryNumber = Math.floor(Math.random()*imageNamesSize);
var winnerImage = imageNames[lotteryNumber];
var fullPath = config.path + winnerImage;
//put this image into DOM at class of randomImage
// alt tag will be image filename.
$(this).attr( { src: fullPath });
});
}
});
})(jQuery);
Should be able to, just set the image to display:none in your stylesheet and modify the bit of the script that sets the src to this:
$(this).attr( { src: fullPath }).load(function() {
$(this).fadeIn()
});
Start with the images hidden using CSS. Then use:
$(document).ready(function() {
// Code goes here.
});
and have the fade-in execute there.
There's another SO question that discusses preloading images using jQuery right here: Preloading images with jQuery
Quoting from the top answer:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}
// Usage:
preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);
if you want all images to preload before fading in, and display a loading message to the user, you can use something like this:
var gotime = imgArray.length;
$(".maxCount").text(gotime);
var imgCounter = 0;
$.each(imgArray, function(){
$(new Image()).load(function(){
imgCounter++;
$(".presentCount").text(imgCounter);
if (--gotime < 1) {
$("#content").fadeIn();
}
}).attr('src', this);
});
Ok so i'm learning to write plugins and the jQuery site for plugin authoring is damn confusing. I'm really trying to figure out how to add methods to my plugin that will fire based on a browser event. So basically I have a plugin that builds out a swipeable slide show for a mobile device. When the device is rotated I need it to rebuild the slideshow for the new dimensions. Right now I have it so it builds it the first time but I can't (a) figure out to add methods for different functions and (b) bind events to those specific methods. here's my code.
(function( $ ){
$.fn.jCarousel = function( options ) {
var empty = {}
var defaults = {
height: $(window).height(),
width: $(window).width(),
count: 1,
amount: $('.swiper', this).length,
thisone:this,
};
var options = $.extend(empty, defaults, options);
return this.each(function() {
options.thisone = this;
amount = $('.swiper', this).length;
holdWidth = options.width * options.amount;
$('.swiper', this).height(options.height);
$(this).height(options.height);
$('.swiper', this).width(options.width);
$(this).width(holdWidth);
$('.swipe_slide',this).width(holdWidth);
//==================================================================================================================
//==================================================================================================================
$('.swiper', this).each(function(i) {
var nwidth = options.width*i;
$(this).css('left',nwidth);
});
//==================================================================================================================
//==================================================================================================================
//==================================================================================================================
//==================================================================================================================
$('.swipe_slide', this).swipe(function(evt, data) {
if(data.direction=='left'){
//alert('count: '+options.count+" amount: "+options.amount);
if(options.count != options.amount){
moveWidth = options.count * -options.width;
$('.swipe_slide',options.thisone).css( "left" ,moveWidth );
options.count++
}else{
return
}
}else{
if(options.count!=1){
moveWidth = moveWidth+ options.width;
$('.swipe_slide',options.thisone).css( "left" ,moveWidth );
options.count--
}
else{
return
}
}
});
//==================================================================================================================
//==================================================================================================================
});
};
})( jQuery );
$(window).bind('orientationchange', $.fn.jCarousel);
You'll have to refactor your plugin a bit so that the function stores the options that are passed into it, otherwise running the function again on orientation change will reset the options to the defaults.