Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
197 views
in Technique[技术] by (71.8m points)

CSS Transform with element resizing

I found this: width/height after transform

and several others, but nothing is not quite what I'm looking for. What I want is to scale something to 50% of it's size (with nice animated transition of course) and have the page layout re-adjust to the new (visual) size of the element. What seems to happen by default is that the element still retains it's original size in the layout structure, and is merely drawn with the associated transformations.

Basically I want the user to click on a block of text (or other content), and then scale that text to 50% (or whatever) of it's size and stick it in a panel below to indicate that it's been selected. I don't want 50% whitespace around the element after I move it.

I've tried re-setting the height/width, but that causes the element iself to undergo a new layout and then the scale is applied to the new layout and this still leaves me with 50% white space after all is finished. My mozilla specific (for simplicity) code looks like this:

<script type="text/javascript">
 function zap(e) {

  var height = e.parentNode.offsetHeight/2 + 'px';
  var width = e.parentNode.offsetWidth/2 + 'px';
  e.parentNode.style.MozTransform='scale(0.0)'; 
  e.parentNode.addEventListener(
    'transitionend', 
    function() { 
      var selectionsArea = document.getElementById("selected");
      selectionsArea.appendChild(e.parentNode);
      e.parentNode.style.MozTransform='scale(0.5,0.5)'; 
      e.parentNode.style.display = 'inline-block';
      e.parentNode.style.height = height;
      e.parentNode.style.width = width;
    },
    true) 
}
</script>

I'm really hoping I don't have to go into messing with negative margins or relative positioning to achieve this...

Edit: Since writing this I found a very similar question with neither comments or answers. It differs slightly as I don't care about it being an html5 specific solution, I suspect the solution either doesn't exist or lies in CSS/javascript regardless of the html level.

Scale/zoom a DOM element and the space it occupies using CSS3 transform scale()

Edit 2: (another non-working attempt)

I've also tried this, but the scale and the translate functions seem to interact in a manner that makes the final position impossible to predict... and scale before transform doesn't appear to be the same as transform then scale. Unfortunately it's not just a matter of adjusting the translate by the scale factor ...

function posX(e) {
    return e.offsetLeft + (e.offsetParent ? posX(e.offsetParent) : 0)
}

function posY(e) {
    return e.offsetTop + (e.offsetParent ? posY(e.offsetParent) : 0)
}

function placeThumbNail(e, container, x, y, scale) {
    var contX = posX(container);
    var contY = posY(container);
    var eX = posX(e);
    var eY = posY(e);
    var eW = e.offsetWidth;
    var eH = e.offsetHeight;

    var margin = 10;
    var dx = ((contX - eX) + margin + (x * eW * scale));
    var dy = ((contY - eY) + margin + (y * eH * scale));

    // assumes identical objects     
    var trans = 'translate(' + dx + 'px, ' + dy + 'px) ';
    var scale = 'scale(' + scale + ',' + scale + ') ';
    e.style.MozTransform =  trans + scale ; 
}

Even if it worked, the above would still require me to first move the element to the bottom of the page before running this code (to get rid of the whitespace), and furthermore I would need to recalculate the transform on re-size... so I wasn't too happy with this attempt to start with anyway.

Also note that if you use scale + trans vs trans + scale above the result is drastically different.

Edit 3: I figured out the placement issues... the transforms are applied in the order specified, and scale(0.5,0.5) essentially changes the size of a pixel to half what it was originally (probably hinting at how they implemented it internally). If I put translate is first, translating slightly less/more to account for the change in the position of the upper left corner caused by scale will do the trick, but managing the location of the objects and adjusting the transforms when the dom changes in a reasonable manner is still eluding me. This sort of feels wrong because I am drifting in the direction of writing my own layout manager in javascript just to get this effect.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem I noticed is that when element scales, browser change its pixels ratio, not pixels amount. Element is smaller but it doesn't change its actual pixel size in DOM. Because of that I don't think that CSS-only solution exist.

I put scalable element into container which keeps the same pixel ratio as rest of elements. Using Java Script I simply change container's size. Everything is still based on CSS3 transform: scale. Maybe JS code could be simplier, but now it's all about the idea (just a proof of concept);) Fiddle with two examples: http://jsfiddle.net/qA5Tb/9/

HTML:

<div class="overall-scalable">
    <div class="scalable" scalex='0.5' scaley='0.5'>
        Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium. Nunc et nisi ante. Integer in blandit nisi. Nulla facilisi. Vestibulum vulputate sapien eget mauris elementum sollicitudin. Nullam id lobortis dolor. Nulla vitae nibh vitae sem volutpat pretium.
    </div>
</div>

CSS:

.overall-scalable {width: 350px; height: 150px; overflow: hidden; -webkit-transition: all 1s;}
.scalable {color: #666; width: 350px; height: 150px; -webkit-transform-origin: top left; -webkit-transition: all 1s;}

JS:

$('button').click(function() {
    $('.scalable').each(function(){
        rescale($(this));
    })
});

function rescale(elem) {

    var height = parseInt(elem.css('height'));
    var width = parseInt(elem.css('width'));
    var scalex = parseFloat(elem.attr('scalex'));
    var scaley = parseFloat(elem.attr('scaley'));

    if (!elem.hasClass('rescaled')){
        var ratioX = scalex;
        var ratioY = scaley;
    }else{          
        var ratioX = 1;
        var ratioY = 1;
    }

    elem.toggleClass('rescaled');
    elem.css('-webkit-transform', 'scale('+ratioX +', '+ratioY+')');        
    elem.parent().css('width', parseInt(width*ratioX) + 'px');
    elem.parent().css('height', parseInt(height*ratioY) + 'px');
}?

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...