javascript高效图形编程中的旋转木马变化公式/原理
高洛峰
高洛峰 2017-04-10 12:48:56
0
1
707

最近在看javascript高效图形编程这本书。

其中的旋转木马那一章中P82页上的这句代码:

ang += angle;

sinVal = Math.sin(ang);
scale = ((sinVal + 1) * sizeRange) + options.minScale;

x = ((Math.cos(ang) * options.radiusX) * scale) + options.width / 2;
y = ((sinVal * options.radiusY) * scale) + options.height / 2;

这些代码是如何实现那种旋转木马的旋转效果的呢?完全看不懂其公式来源啊。望高手指点。 还有就是为了实现某种视觉效果的那些变换公式是怎么得出来的?

是不是需要去看看计算机图形学啊?

附(旋转木马完整代码):

<!DOCTYPE html->
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Carousel</title> 
    <style type="text/css">
        img { border:none;}
    </style>
    <!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script> -->
    <script src="jquery-1.8.2.min.js"></script>
    <script type="text/javascript">



// Start of jQuery carousel plugin.           
(function($) {

// Function to execute a callback when an image has been loaded,
// either from the network, or from the browser cache.

var loadImage = function ($image, src, callback) {
    console.log($image)

    // Bind the load event BEFORE setting the src.
    $image.bind("load", function (evt) {
        // If no valid width, image hasn't actually loaded.
        if ($image.width() === 0) {
            alert('zero');
            return;
        }
        // Image has loaded, so unbind event and call callback.
        $image.unbind("load");
        callback($image);

    }).each(function () {
        // For Gecko based browsers, check the complete property,
        // and trigger the event manually if image loaded.
        if ($image[0].complete) {
            $image.trigger("load");
        }
    });
    // For Webkit browsers, the following line ensures load event fires if
    // image src is the same as last image src. This is done by setting
    // the src to an empty string initially.
    if ($.browser.webkit) {
        $image.attr('src', '');               
    }
    $image.attr('src', src );
};



// Create a single carousel item.           
var createItem = function ($image, angle, options) {
    var loaded = false, // Flag to indicate image has loaded.
        orgWidth,       // Original, unscaled width of image.
        orgHeight,      // Original, unscaled height of image.
        $originp,     // Image is attached to this p.  

        // A range used in the scale calculation to ensure 
        // the front-most item has a scale of 1,
        // and the furthest most item has a scale as defined
        // in options.minScale.
        sizeRange = (1 - options.minScale) * 0.5,

        // An object to store the public update function.
        that;

    // Make image invisible and
    // set its positioning to absolute.
    $image.css({
        opacity: 0,
        position: 'absolute'
    });
    // Create a p element ($originp). The image
    // will be attached to it.
    $originp = $image.wrap('<p style="position:absolute;">').parent();
    console.log($originp)

    that = {
        update: function (ang) {
            var sinVal, scale, x, y;

            // Rotate the item.
            ang += angle;

            // Calculate scale.
            sinVal = Math.sin(ang);
            scale = ((sinVal + 1) * sizeRange) + options.minScale;

            // Calculate position and zIndex of origin p.
            // x = ((Math.cos(ang) * options.radiusX) * scale);
            // y = ((sinVal * options.radiusY) * scale);
            x = ((Math.cos(ang) * options.radiusX) * scale) + options.width / 2;
            y = ((sinVal * options.radiusY) * scale) + options.height / 2;
            $originp.css({
                left: (x >> 0) + 'px',
                top: (y >> 0) + 'px',
                zIndex: (scale * 100) >> 0
            });
            // If image has loaded, update its dimensions according to
            // the calculated scale.
            // Position it relative to the origin p, so the 
            // origin p is in the center.
            if (loaded) {
                $image.css({
                    width: (orgWidth * scale) + 'px',
                    height: (orgHeight * scale) + 'px',
                    top: ((-orgHeight * scale) / 2) + 'px',
                    left: ((-orgWidth * scale) / 2) + 'px'
                });
            }
        }
    };

    // Load the image and set the callback function.
    loadImage($image, $image.attr('src'), function ($image) {
        loaded = true;
        // Save the image width and height for the scaling calculations.
        orgWidth = $image.width();
        orgHeight = $image.height();
        // Make the item fade-in.
        $image.animate({
            opacity: 1
        }, 1000);

    });
    return that;
};

// Create a carousel.
var createCarousel = function ($wrap, options) {
    var items = [],
        rot = 0,
        pause = false,
        unpauseTimeout = 0,
        // Now calculate the amount to rotate per frameRate tick.
        rotAmount = (Math.PI * 2) * (options.frameRate/options.rotRate),
        $images = $('img'),
                // 下面这么写就改变了上下文,从document --> .carousel
        // $images = $('img', $wrap),
        // Calculate the angular spacing between items.
        spacing = (Math.PI / $images.length) * 2,
        // This is the angle of the 1st item at
        // the front of the carousel.
        angle = Math.PI / 2,
        i;
                console.log('Images: ', $images);
    // Create a function which is called when the mouse moves over
    // or out of an item.
    $wrap.bind('mouseover mouseout', function (evt) {
        // Has the event been triggered on an image? Return if not.
        if (!$(evt.target).is('img')) {
            return;
        }

        // If mouseover, then pause the carousel.
        if (evt.type === 'mouseover') {
            // Stop the unpause timeout if it's running.
            clearTimeout(unpauseTimeout);
            // Indicate carousel is paused.
            pause = true;
        } else {
            // If mouseout, restart carousel, but after a small
            // delay to avoid jerking movements as the mouse moves
            // between items.
            unpauseTimeout = setTimeout(function () {
                pause = false;
            }, 200);
        }

    });

    // This loop runs through the list of images and creates
    // a carousel item for each one.
    for (i = 0; i < $images.length; i++) {
        var image = $images[i];
        var item = createItem($(image), angle, options);
        items.push(item);
        angle += spacing;
    }

    // The setInterval will rotated move all items in the carousel
    // every 30Ms, unless the carousel is paused.
    setInterval(function () {
        if (!pause) {
            rot += rotAmount;
        }
        for (i = 0; i < items.length; i++) {
            items[i].update(rot);
        }
    }, options.frameRate);
};



// This is the jQuery plugin part. It iterates through
// the list of DOM elements that wrap groups of images.
// These groups of images are turned into carousels.
$.fn.Carousel = function(options) {
    this.each( function() {
        // User options are merged with default options.
        options = $.extend({}, $.fn.Carousel.defaults, options);
        // Each wrapping element is given relative positioning
        // (so the absolute positioning of the carousel items works),
        // and the width and height are set as specified in the options.
        $(this).css({
            position:'relative',
            width: options.width+'px',
            height: options.height +'px'
        });
        createCarousel($(this),options);
    });
}; 

// These are the default options.
$.fn.Carousel.defaults = {
    radiusX:230,   // Horizontal radius.
    radiusY:80,    // Vertical radius.
    width:512,     // Width of wrapping element.
    height:300,    // Height of wrapping element.
    frameRate: 30,  // Frame rate in milliseconds. 
    rotRate: 5000, // Time it takes for carousel to make one complete rotation.
    minScale:0.60 // This is the smallest scale applied to the furthest item.
};

})(jQuery);
// End of jQuery carousel plugin.   

    $(function(){
        // Create a carousel on all wrapping elements
        // with a class of .carousel.
        $('.carousel').Carousel({
            width:512, height:300,  // Set wrapping element size.
            radiusX:220,radiusY:70, // Set carousel radii.
            minScale:0.6           // Set min scale of rear-most item.

        });

        // Bind a click event to one of the pictures
        // to show events are preserved after images become
        // carousel items.
        $('#pic2').bind('click', function() {
            alert('Pic 2 clicked!');
        });
    });
    </script>

</head>
<body>








</body>
</html>

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回复(1)
PHPzhong

scale是近大远小的过程,按照角度以正弦呈周期变化。

x和y是椭圆参数方程的:

x=acosθ,y=bsinθ

考虑一下,以某个角度看一个圆形的东西,那不就是个椭圆吗。。

而后面的一系数是为了保证缩放之后保持居中……

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板