Rotate Your Images in Style with Fancybox

Currently, I am working on a project that involves allowing users to rotate images 90 degrees counter clockwise within an interface. To achieve this functionality, I have implemented the rotation of images on the webpage using jQuery and -webkit-transform. However, I am facing a challenge in updating the preview of the image within the Fancybox slideshow.

In my attempts to rotate the image, I have tried the following approach:

 $(".fancybox").fancybox({           
      afterShow: function(){
        fancyboxRotation();
      }
    });

function fancyboxRotation(){
    $('.fancybox-wrap').css('webkitTransform', rotate(-90deg));
    $('.fancybox-wrap').css('mozTransform', rotate(-90deg));
}

Unfortunately, this method resulted in not only rotating the image but also affecting the controls (and shifting the close button to the top left instead of the top right):

If I solely apply the rotation to the image, the white border around it appears with incorrect orientation:

I am seeking advice from those who have experience in applying transformations to images within a Fancybox environment. Any insights would be highly appreciated.

Answer №1

For my custom implementation of fancybox 3, I have incorporated the usage of font awesome icons. You have the flexibility to replace them with glyphicons or any other icons of your choice.

//customizing fancybox menu to include an option to rotate image
    $(document).on('onInit.fb', function (e, instance) {
        if ($('.fancybox-toolbar').find('#rotate_button').length === 0) {
            $('.fancybox-toolbar').prepend('<button id="rotate_button" class="fancybox-button" title="Rotate Image"><i class="fa fa-repeat"></i></button>');
        }
        var click = 1;
        $('.fancybox-toolbar').on('click', '#rotate_button', function () {
                var n = 90 * ++click;
                $('.fancybox-image-wrap img').css('webkitTransform', 'rotate(-' + n + 'deg)');
                $('.fancybox-image-wrap img').css('mozTransform', 'rotate(-' + n + 'deg)');
            });
    });

Answer №2

To add a fun twist to your fancy box content, try rotating the outermost div. In my example, I'm using fancybox-skin (fancybox version 2).


afterShow: function(){
    var rotation = 1;
    $('.fancybox-wrap').append('<div id="rotate_button"></div>')
        .on('click', '#rotate_button', function(){
            var degrees = 90 * ++rotation;
            $('.fancybox-skin').css('webkitTransform', 'rotate(-' + degrees + 'deg)');
            $('.fancybox-skin').css('mozTransform', 'rotate(-' + degrees + 'deg)');
        });
};

Answer №3

After collaborating with @Ashik, I was able to successfully implement the solution without sacrificing the title display by rotating .fancybox-inner and tweaking some CSS to maintain the white border. Additionally, I initialized the fancybox within the $(document).ready() function, requiring a slight adjustment in binding the button.

Since this is quite an extensive answer, please let me know if anything important has been omitted. It's worth noting that IE compatibility is not a concern for this solution, fortunately!

To retain the position of regular arrow and close buttons at the top, it was necessary to add the fancy box button helper CSS and JS files:

<link href="/Content/css/jquery.fancybox.css" rel="stylesheet"/>
<link href="/Content/css/jquery.fancybox-buttons.css" rel="stylesheet"/>

<script src="/Content/Scripts/fancybox/jquery.fancybox.js"></script>
<script src="/Content/Scripts/fancybox/jquery.fancybox.pack.js"></script>
<script src="/Content/Scripts/fancybox/jquery.fancybox-buttons.js"></script>

The fancy box initialization is performed within $(document).ready(), as mentioned earlier, set up as follows (note the removal and addition of arrows and close buttons using the button helper's tpl property):

$(document).ready(function() {

    $(".fancybox").fancybox({
        loop   : true,
        helpers: {
            buttons: {
                position: 'top',
                tpl     : '<div id="fancybox-buttons"><ul><li><a class="btnPrev" title="Previous" href="javascript:;"></a></li><li><a id="fancybox-rotate-button" title="Rotate" data-rotation="0" onclick="FancyBoxRotateButton()"></a></li><li><a class="btnNext" title="Next" href="javascript:;"></a></li><li><a class="btnClose" title="Close" href="javascript:jQuery.fancybox.close();"></a></li></ul></div>'
            }
        },
        closeBtn: false, // you will use the tpl buttons now
        arrows  : false  // you will use the tpl buttons now
    });

Below is the custom rotation button's onclick function:

window.FancyBoxRotateButton = function() {
    var fancyboxInner        = $('.fancybox-inner');
    var fancyBoxRotateButton = $('#fancybox-rotate-button');
    var currentRotation      = parseInt(fancyBoxRotateButton.data("rotation"));
    var rotation             = 'rotate(-' + (90 * ++currentRotation) + 'deg)';

    fancyboxInner.css({
        '-moz-transform'   : rotation,
        '-webkit-transform': rotation,
        '-o-transform'     : rotation,
        'transform'        : rotation
    });

    fancyBoxRotateButton.data("rotation", currentRotation.toString());
}

To address the white border issue and adjust the size of the custom button ul, along with setting a custom picture for the rotation button, alterations were made by removing backgrounds from .fancybox-skin and applying them to .fancybox-inner:

#fancybox-buttons ul{
    width: 130px;
}

#fancybox-buttons #fancybox-rotate-button {
    background-image: url('/Content/images/fancybox_rotate.png')
}

.fancybox-skin {
    background: none !important;
}

.fancybox-opened .fancybox-skin {
    -webkit-box-shadow: none !important;
    -moz-box-shadow   : none !important;
    box-shadow        : none !important;
}


.fancybox-inner {
    border-radius     : 4px;
    border            : 2px solid white;
    padding           : 10px;
    background        : white none repeat scroll 0 0;
    -webkit-box-shadow: 0 10px 25px #000000;
    -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
    -moz-box-shadow   : 0 10px 25px #000000;
    -moz-box-shadow   : 0 10px 25px rgba(0, 0, 0, 0.5);
    box-shadow        : 0 10px 25px #000000;
    box-shadow        : 0 10px 25px rgba(0, 0, 0, 0.5);
}

I hope this detailed explanation proves helpful to someone!

Answer №4

To rotate your image, use the CSS property

-webkit-transform: rotate(-90deg);
specifically on the '.fancybox-inner' class element rather than the '.fancybox-wrap' to ensure that only the image rotates without affecting the rest of the container containing controls and descriptions.

Answer №5

In order to enhance the user experience, I implemented a solution where I removed the arrows and close button from the fancybox interface. Instead, I applied a smooth fade-in effect to display the fancybox slideshow after the rotation effect was completed on the entire fancybox-wrap element. The key steps involved setting the display property of the fancybox-wrap to none during the "beforeShow" event, followed by a fade-in action during the "afterShow" event. Below is the customized code snippet that illustrates this implementation:

    $(".fancybox").fancybox({
      helpers: {
        overlay: {
          locked: false
        }
      },
      arrows: false,
      closeBtn: false,
      beforeShow: function(){
        if($('.fancybox-image').length>0){
           $('.fancybox-wrap').css('display', 'none');
            var imageID = getFancyboxImageID();
            var rotation = getFancyboxRotation(imageID);
            if(rotation!=0){
              fancyboxRotate(rotation);  
            }
        }
      },
      afterShow: function(){
        if($('.fancybox-image').length>0){
          $('.fancybox-wrap').fadeIn();
        }
      }
    });

Answer №6

To preserve the close button and caption elements, I implemented a clever CSS3 transformation technique:

afterShow: function() {
    var click = 0, deg;
    $('.fancybox-inner')
        .append('<img id="rotate_button" src="https://cdn0.iconfinder.com/data/icons/super-mono-sticker/icons/button-rotate-cw_sticker.png" title="Rotate 90° CW">')
        .on('click', '#rotate_button', function() {
            click = (++click % 4 === 0) ? 0 : click;
            deg = 90 * click;
            $('.fancybox-wrap').css('transform', 'rotate(' + deg + 'deg)');
            $('#rotate_button').css('transform', 'rotate(-' + deg + 'deg)');
            sessionStorage.setItem('prev_rotated_image', $('.fancybox-image').prop('src'));
            sessionStorage.setItem($('.fancybox-image').prop('src'), deg);

            // Adjust close button position and rotate the label based on rotation
            switch (deg) {
                case 90:
                    $('.fancybox-close').css('transform', 'translate(-' + $('.fancybox-wrap').width() + 'px, 0px)');
                    $('.fancybox-title').find('span.child').css('transform', 'translate(' + ($('.fancybox-wrap').width() / 2 + $('.fancybox-title').height() / 2 + 8) + 'px, -' + ($('.fancybox-wrap').height() / 2) + 'px) rotate(-' + deg + 'deg)');
                    break;
                case 180:
                    $('.fancybox-close').css('transform', 'translate(-' + $('.fancybox-wrap').width() + 'px, ' + $('.fancybox-wrap').height() + 'px)');
                    $('.fancybox-title').find('span.child').css('transform', 'translate(0px, -'+ ($('.fancybox-wrap').height() + $('.fancybox-title').height() + 16) +'px) rotate(-' + deg + 'deg)');
                    break;
                case 270:
                    $('.fancybox-close').css('transform', 'translate(0px, ' + $('.fancybox-wrap').height() + 'px)');
                    $('.fancybox-title').find('span.child').css('transform', 'translate(-' + ($('.fancybox-wrap').width() / 2 + $('.fancybox-title').height() / 2 + 8) + 'px, -' + ($('.fancybox-wrap').height() / 2) + 'px) rotate(-' + deg + 'deg)');
                    break;
                case 0:
                case 360:
                default:
                    $('.fancybox-close').css('transform', 'translate(0px, 0px)');
                    $('.fancybox-title').find('span.child').css('transform', 'translate(0px, 0px) rotate(0deg)');
            }
        });
}

Answer №7

Shoutout to @Paul for the fantastic code snippet! I made some modifications to include class changes (current slide) and CSS properties that worked perfectly with my version of fancybox3. Hopefully, this can benefit someone else as well.

Just a heads up: you have the option to substitute the "Rotate" text with an icon.

// Function to add a custom item to fancybox menu for image rotation
$(document).on('onInit.fb', function (e, instance) {
    if ($('.fancybox-toolbar').find('#rotate_button').length === 0) {
        $('.fancybox-toolbar').prepend('<button id="rotate_button" class="fancybox-button" title="Rotate Image">Rotate</button>');
    }
    var click = 1;
    $('.fancybox-toolbar').on('click', '#rotate_button', function () {
            var n = 90 * ++click;
            $('.fancybox-slide--current img').css('webkitTransform', 'rotate(-' + n + 'deg)');
            $('.fancybox-slide--current img').css('mozTransform', 'rotate(-' + n + 'deg)');
            $('.fancybox-slide--current img').css('transform', 'rotate(-' + n + 'deg)');
        });
});

Answer №8

If you're facing a similar issue, check out this Github thread: https://github.com/fancyapps/fancybox/issues/1100

After testing user seltix5's code in fancybox v3 myself, I can confirm that it works perfectly.

All you have to do is add his/her code to your fancybox.js file. This code enhances the fancybox object with a rotate feature triggered after the "onInit.fb" event. It even includes rotating buttons on the top menu along with a smooth animation for rotation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Implement a T3 App Redirect in a TRPC middleware for unsigned users

Is there a way to implement a server-side redirect if a user who is signed in has not finished filling out their profile page? const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { if (!ctx.session || !ctx.session.user) { throw new TRPCE ...

Using JavaScript to dynamically populate form fields

I am currently working on developing a form that allows users to add additional fields themselves. They will have the ability to add up to 5 new "options", with each option containing up to 50 "variants". For example, an option could be "size" with varian ...

Activate the jQuery function multiple times

I am currently working on the menu structure for my website <div class="header"> <ul> <li id="menu__lnk_one"><a href="#">Home</a></li> <li><a href="#">Our Story</a></ ...

Ways to Retrieve Material-UI Date Picker Data

I am struggling to figure out how to set the value selected by the user in a material-ui datepicker to state. Any help would be greatly appreciated. Currently, this is what I have been trying: The datepicker component code looks like this: <DatePicke ...

Guide to activating a function by tapping anywhere on a webpage in iPhone Safari

I am attempting to implement a jQuery function that will change the text of a div in the iPhone browser when any area of the page is clicked. Here is my current setup: <div id="alternative_text">traduit</div> <script type="text/javascript ...

Adjusting font size in CSS for HTML websites

Having some trouble adjusting the font size on my HTML webpage using CSS - for some reason, the "font-size" property isn't cooperating: Below is the snippet of HTML code for my site: And here's a brief look at the accompanying CSS code: I&apos ...

Clear navigation bar on top of a backdrop picture

I am currently exploring the most effective method to place my hero/background image behind a transparent Bootstrap 4 navbar. Some have suggested applying the background image to the body of the page, but I specifically want the background image only on th ...

Is there a way to increment a counter with a click?

Seeking a method to create a counter that increments upon button click. Attempted code provided below, however the displayed value remains constant: $(document).ready(function () { $("#gonder").click(function() { var baslik = document.title; ...

The Jasmine tests seem to have a mind of their own,

Encountering a peculiar problem during the execution of my Jasmine tests in the Bamboo build. The tests are failing sporadically with the error message below: Failed: can't convert undefined to object on 18-Nov-2019 at 03:08:56 ./node_modules/@a ...

The table printing settings are not compatible with portrait and landscape orientations

I am facing an issue with printing a table on my webpage. When I try to print using Control+P or window.print();, the width of the table does not adjust properly for portrait or landscape orientation. The table ends up exceeding the paper width. How can I ...

Vue event emissions are not triggered or detected

This is the functionality of the Child Component: registerUser() { if (this.$refs.form.validate()) { this.$emit('showLoader', true); // Triggers this.$fireAuth .createUserWithEmailAndPassword(this.email, this.password) .the ...

Step-by-step guide to designing a custom eBay-inspired logo page using HTML and CSS

Recently, I stumbled upon a fascinating website design for eBay's new logo page. It got me thinking about how I could recreate something similar for my own website. The concept of having the logo visible through the gaps is quite intriguing. If you&a ...

Increase the nestling of bullet points with inner indentation <li>

Hey there, I'm currently facing an issue with the right-side indentation of the bullet points. I have included a code snippet and an image that should help clarify the situation: https://i.sstatic.net/vmOVc.png <h1 style="display: block;marg ...

Show or hide table columns easily without relying on jQuery

Within my HTML table that contains multiple columns, I aim to create a toggle feature for one specific column (in this case, the 4th column). Currently, I have accomplished this using jQuery: document.write('<a class="toggle" href="#!" data-alt="H ...

Saving and retrieving user input as a variable using Javascript and HTML local storage

This is the foundation of my HTML page. When the "remember text" paragraph is clicked, the data in the input text box is saved to local storage as a string. Clicking the "recall text" paragraph loads the stored data into the "recalled text" paragraph. I am ...

Exploring the process of updating initialState within react-redux

I am currently using react-redux to retrieve data from a MongoDB database and integrate it into my React App. Below is the structure I am working with: const initialState = { Level: [{ wId: Math.random(), Level1: [ { id: Math.rando ...

Are the buttons appearing within a pop-up display?

I am having an issue with my Javascript popup buttons. Whenever the popup appears, the buttons that come after the one clicked appear on top of the popup container, and the previous buttons appear behind it. How can I ensure that the popup container displa ...

The output produced by ASP.NET remains unaffected by JQuery or JavaScript interference

I am facing an issue with manipulating a dynamically generated directory tree in HTML format using JavaScript. I have a piece of code that generates the tree server-side in ASP.NET and then tries to add a '+' at the end of each list item using jQ ...

Using values across different Express routes in Node.jsIn Node.js development,

I'm a beginner with Express and working on a Node.js application. I'm facing an issue with using the same parameters in my code: app.get('/signin', function (req, res) { renderView(req, res, 'signin.jade'); }); app.get(&ap ...

Guide on implementing enums (or const) in VueJS

Seeking help on a seemingly simple task, I am trying to understand how to use "enums" in VueJS. In my file named LandingPage.js, I have the following code: const Form = { LOGIN: 0, SIGN_UP: 1, FORGOT_PASSWORD: 2, }; function main() { new Vue({ ...