Reported metrics should take into account CSS transformations #100

Open
paulyoung opened this Issue Jul 17, 2014 · 3 comments

1 participant

@paulyoung

For example, in the following screenshot the green box has its top, bottom, left, and right properties set to that of the red box, however it's not positioned that way since the rotation isn't accounted for.

screen shot 2014-07-16 at 22 27 48

@paulyoung

I changed my implementation so don't actually need this right now, but wanted to document what I have for future reference.

Using the code below I was able to set the size and position of the green rectangle to be that of the red rectangle when rotated.

screen shot 2014-07-17 at 02 41 19

From this I was also able to determine the size and position of a non-rotated rectangle that would fit inside of the red rectangle.

<body>
  <script>
    document.body.addEventListener('solved', function() {
      // Update reported metrics for z-rotation
      (function (vars) {
        var translateCoordinates = function(x, y, originX, originY, rotation) {
          var converted = rotation * (Math.PI / 180);

          return {
            x: originX + (x - originX) * Math.cos(converted) + (y - originY) * Math.sin(converted),
            y: originY - (x - originX) * Math.sin(converted) + (y - originY) * Math.cos(converted)
          };
        };

        var suggestIfNeeded = function(id, property, value) {
          var key, roundedVarValue, roundedValue;
          key = '$' + id + '[' + property + ']';
          roundedVarValue =  (Math.round(parseFloat(vars[key]) * 100) / 100);
          roundedValue =  (Math.round(parseFloat(value) * 100) / 100);

          if (roundedVarValue !== roundedValue) {
            var suggest = window.GSS.engines.root.commander.suggest;
            suggest('suggest', key, ['number', value]);
          }
        };

        for (key in vars) {
          var propertyName, property;
          propertyName = 'rotate-z';
          property = '[' + propertyName + ']';

          if (key.slice(property.length * -1) === property) {
            var id, element;
            id = key.replace('$', '').replace(property, '');
            element = document.getElementById(id);

            var x, y, width, height, rotateZ;
            x = vars["$"+id+"[x]"];
            y = vars["$"+id+"[y]"];
            width = vars["$"+id+"[width]"];
            height = vars["$"+id+"[height]"];
            rotateZ = vars["$"+id+"[rotate-z]"];

            var right, bottom;
            right = x + width;
            bottom = y + height;

            var centerX, centerY;
            centerX = x + (width / 2);
            centerY = y + (height / 2);

            // Assumes rotatation around center point
            var topLeft, topRight, bottomRight, bottomLeft;
            topLeft = translateCoordinates(x, y, centerX, centerY, rotateZ);
            topRight = translateCoordinates(right, y, centerX, centerY, rotateZ);
            bottomRight = translateCoordinates(right, bottom, centerX, centerY, rotateZ);
            bottomLeft = translateCoordinates(x, bottom, centerX, centerY, rotateZ);

            var xCoordinates, yCoordinates;
            xCoordinates = [topLeft.x, topRight.x, bottomRight.x, bottomLeft.x];
            yCoordinates = [topLeft.y, topRight.y, bottomRight.y, bottomLeft.y];

            var minX, maxX, minY, maxY;
            minX = Math.min.apply(this, xCoordinates);
            maxX = Math.max.apply(this, xCoordinates);
            minY = Math.min.apply(this, yCoordinates);
            maxY = Math.max.apply(this, yCoordinates);

            var rotatedTopLeft, rotatedTopRight, rotatedBottomRight, rotatedBottomLeft;
            rotatedTopLeft = { x: minX, y: minY };
            rotatedTopRight = { x: maxX, y: minY };
            rotatedBottomRight = { x: maxX, y: maxY };
            rotatedBottomLeft = { x: minX, y: maxY };

            // x, y, width, height
            var rotatedX, rotatedY, rotatedWidth, rotatedHeight;
            rotatedX = rotatedTopLeft.x;
            rotatedY = rotatedTopLeft.y
            rotatedWidth = rotatedTopRight.x - rotatedTopLeft.x;
            rotatedHeight = rotatedBottomLeft.y - rotatedTopLeft.y;

            suggestIfNeeded(id, 'rotated-left', rotatedX);
            suggestIfNeeded(id, 'rotated-top', rotatedY);
            suggestIfNeeded(id, 'rotated-width', rotatedWidth);
            suggestIfNeeded(id, 'rotated-height', rotatedHeight);

            // Coordinates
            var rotatedLeftX, rotatedLeftY, rotatedTopX, rotatedTopY,
            rotatedRightX, rotatedRightY, rotatedBottomX, rotatedBottomY;

            var sortedXCoordinates, sortedYCoordinates;
            sortedXCoordinates = xCoordinates.sort();
            sortedYCoordinates = yCoordinates.sort();

            rotatedLeftX = minX;
            rotatedLeftY = sortedYCoordinates[1];

            rotatedTopX = sortedXCoordinates[2];
            rotatedTopY = minY;

            rotatedRightX = maxX;
            rotatedRightY = sortedYCoordinates[2];

            rotatedBottomX = sortedXCoordinates[1];
            rotatedBottomY = maxY;

            suggestIfNeeded(id, 'rotated-left-x', rotatedLeftX);
            suggestIfNeeded(id, 'rotated-left-y', rotatedLeftY);
            suggestIfNeeded(id, 'rotated-top-x', rotatedTopX);
            suggestIfNeeded(id, 'rotated-top-y', rotatedTopY);
            suggestIfNeeded(id, 'rotated-right-x', rotatedRightX);
            suggestIfNeeded(id, 'rotated-right-y', rotatedRightY);
            suggestIfNeeded(id, 'rotated-bottom-x', rotatedBottomX);
            suggestIfNeeded(id, 'rotated-bottom-y', rotatedBottomY);
          }
        }
      })(window.GSS.vars);
    });
  </script>
</body>
@paulyoung

Similar calculations for skewY:

<body>
   <script>
    document.body.addEventListener('solved', function() {
      // Provide metrics for vertical skewing
      (function (vars) {
        var suggestIfNeeded = function(id, property, value) {
          var key, roundedVarValue, roundedValue;
          key = '$' + id + '[' + property + ']';
          roundedVarValue =  (Math.round(parseFloat(vars[key]) * 100) / 100);
          roundedValue =  (Math.round(parseFloat(value) * 100) / 100);

          if (roundedVarValue !== roundedValue) {
            var suggest = window.GSS.engines.root.commander.suggest;
            suggest('suggest', key, ['number', value]);
          }
        };

        for (key in vars) {
          var propertyName, property;
          propertyName = 'skew-y';
          property = '[' + propertyName + ']';

          if (key.slice(property.length * -1) === property) {
            var id, element;
            id = key.replace('$', '').replace(property, '');
            element = document.getElementById(id);

            var y, width, height, skewY;
            y = vars["$"+id+"[y]"];
            width = vars["$"+id+"[width]"];
            height = vars["$"+id+"[height]"];
            skewY = vars["$"+id+"[skew-y]"];

            var degrees, delta;
            degrees = Math.abs(skewY) * (Math.PI / 180);
            delta = Math.tan(degrees) * width;

            // Assumes origin is center point
            var skewedTop, skewedHeight, skewedBottom;
            skewedTop = y - (delta / 2);
            skewedHeight = height + delta;
            skewedBottom = skewedTop + skewedHeight;

            suggestIfNeeded(id, 'skewed-top', skewedTop);
            suggestIfNeeded(id, 'skewed-height', skewedHeight);
            suggestIfNeeded(id, 'skewed-bottom', skewedBottom);
          }
        }
      })(window.GSS.vars);
    });
  </script>
</body>
@paulyoung

getBoundingClientRect seems like it would handle this nicely for any combination of transformations if supported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment