specious / cloud9carousel

:cyclone: 3D-perspective carousel for jQuery / Zepto
http://j.mp/cloud9demo
233 stars 88 forks source link

Front image scale "bonus" #6

Closed rolling29 closed 8 years ago

rolling29 commented 8 years ago

Hi, I'm not really sure how this works, it's my first time trying to contribute to a project here. I made a few changes that allow a neat feature and I really like the work you've made available so I wanted to help. So, here's my little 3 lines change to the rotateItem function:

    this.rotateItem = function( itemIndex, rotation ) {
      var item = this.items[itemIndex];
      var sin = Math.sin(rotation);
      var farScale = this.farScale;
      var scale = farScale + ((1-farScale) * ((sin+1) * 0.5));
      // TR 15OCT2015 - I want the front image to be scalable larger than the surrounding images, so...
      var frontscalebonus = 0.4;  // 0.4 gives 40%
      var frontzoom = (Math.pow(sin+1,64)/18446744073709600000) * frontscalebonus; 
      var scaleonly = (scale + frontzoom) / (1+frontscalebonus);
      // Allow "scale" to continue setting the rotation position, but make the image scale depend on the
      // new "scaleonly".  This new var applies a modified sin function to the existing sin function, the
      // goal is to reduce the previous maximum scale to a smaller amount and allow the front image to use 
      // the difference as it's expansion factor.  It keeps the rotation positions pretty well intact. My
      // exponential factor makes the small part of the sin curve rapidly peak near Pi/2 and flat elsewhere.
      // That little bit of curve is enough to animate the front image scaling as it slides in and out.
      item.moveTo(
        this.xOrigin + (scale * ((Math.cos(rotation) * this.xRadius) - (item.fullWidth * 0.5))),
        this.yOrigin + (scale * sin * this.yRadius),
      // swap scale for scaleonly below, but not above
        scaleonly
      );
    }

I tried to explain it in my comments, but the basic idea is you set a decimal percentage for the frontscalebonus variable, then it scales the front image about that much bigger than the images on either side. So my example has 0.4, the front image will be 100% for a nice clear image, and to the left and right the images are about 60%, and everything on the way back is scaled down to the farScale value as normal. I use 20% for farScale, and I like to set the yRadius a bit smaller for a little overlap. The scale variable stays the same so rotation positions don't get messed up, and scaleonly stays between 0-1 so it doesn't go crazy. It just makes that little curved bump at Pi/2 so the front image is how much bigger you want it.

specious commented 8 years ago

@rolling29, that's really cool.

I think that the proper way to do enable this kind of modification would be to officially allow a custom function to override the default for calculating the item render parameters each frame. A pull request would be appreciated.

Since this is JavaScript, what you can do is replace the item render function with your own. For example, after you initialize the carousel:

$('#carousel').data('carousel').renderItem = function( itemIndex, rotation ) {
  var item = this.items[itemIndex];
  var sin = Math.sin(rotation);
  var farScale = this.farScale;
  var scale = farScale + ((1-farScale) * ((sin+1) * 0.5));
  // TR 15OCT2015 - I want the front image to be scalable larger than the surrounding images, so...
  var frontscalebonus = 0.4;  // 0.4 gives 40%
  var frontzoom = (Math.pow(sin+1,64)/18446744073709600000) * frontscalebonus; 
  var scaleonly = (scale + frontzoom) / (1+frontscalebonus);

  // ...  

  item.moveTo(
    this.xOrigin + (scale * ((Math.cos(rotation) * this.xRadius) - (item.fullWidth * 0.5))),
    this.yOrigin + (scale * sin * this.yRadius),
  // swap scale for scaleonly below, but not above
    scaleonly
  );
}

Please note that I renamed rotateItem() to renderItem(), as I decided that it makes more sense semantically. See: https://github.com/specious/cloud9carousel/commit/419df18af1fe73fb828e212103f120b64cdf6fd9