function getLayoutRect(
    positionInfo, containerRect, margin
) {
    margin = normalizeCssArray$1(margin || 0);

    var containerWidth = containerRect.width;
    var containerHeight = containerRect.height;

    var left = parsePercent$1(positionInfo.left, containerWidth);
    var top = parsePercent$1(positionInfo.top, containerHeight);
    var right = parsePercent$1(positionInfo.right, containerWidth);
    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);
    var width = parsePercent$1(positionInfo.width, containerWidth);
    var height = parsePercent$1(positionInfo.height, containerHeight);

    var verticalMargin = margin[2] + margin[0];
    var horizontalMargin = margin[1] + margin[3];
    var aspect = positionInfo.aspect;

    // If width is not specified, calculate width from left and right
    if (isNaN(width)) {
        width = containerWidth - right - horizontalMargin - left;
    }
    if (isNaN(height)) {
        height = containerHeight - bottom - verticalMargin - top;
    }

    if (aspect != null) {
        // If width and height are not given
        // 1. Graph should not exceeds the container
        // 2. Aspect must be keeped
        // 3. Graph should take the space as more as possible
        // FIXME
        // Margin is not considered, because there is no case that both
        // using margin and aspect so far.
        if (isNaN(width) && isNaN(height)) {
            if (aspect > containerWidth / containerHeight) {
                width = containerWidth * 0.8;
            }
            else {
                height = containerHeight * 0.8;
            }
        }

        // Calculate width or height with given aspect
        if (isNaN(width)) {
            width = aspect * height;
        }
        if (isNaN(height)) {
            height = width / aspect;
        }
    }

    // If left is not specified, calculate left from right and width
    if (isNaN(left)) {
        left = containerWidth - right - width - horizontalMargin;
    }
    if (isNaN(top)) {
        top = containerHeight - bottom - height - verticalMargin;
    }

    // Align left and top
    switch (positionInfo.left || positionInfo.right) {
        case 'center':
            left = containerWidth / 2 - width / 2 - margin[3];
            break;
        case 'right':
            left = containerWidth - width - horizontalMargin;
            break;
    }
    switch (positionInfo.top || positionInfo.bottom) {
        case 'middle':
        case 'center':
            top = containerHeight / 2 - height / 2 - margin[0];
            break;
        case 'bottom':
            top = containerHeight - height - verticalMargin;
            break;
    }
    // If something is wrong and left, top, width, height are calculated as NaN
    left = left || 0;
    top = top || 0;
    if (isNaN(width)) {
        // Width may be NaN if only one value is given except width
        width = containerWidth - horizontalMargin - left - (right || 0);
    }
    if (isNaN(height)) {
        // Height may be NaN if only one value is given except height
        height = containerHeight - verticalMargin - top - (bottom || 0);
    }

    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);
    rect.margin = margin;
    return rect;
}
Position a zr element in viewport
 Group position is specified by either
 {left, top}, {right, bottom}
 If all properties exists, right and bottom will be igonred.

Logic:
    1. Scale (against origin point in parent coord)
    2. Rotate (against origin point in parent coord)
    3. Traslate (with el.position by this method)
So this method only fixes the last step 'Traslate', which does not affect
scaling and rotating.

If be called repeatly with the same input el, the same result will be gotten.

@param {module:zrender/Element} el Should have `getBoundingRect` method.
@param {Object} positionInfo
@param {number|string} [positionInfo.left]
@param {number|string} [positionInfo.top]
@param {number|string} [positionInfo.right]
@param {number|string} [positionInfo.bottom]
@param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'
@param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'
@param {Object} containerRect
@param {string|number} margin
@param {Object} [opt]
@param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.
@param {Array.<number>} [opt.boundingMode='all']
       Specify how to calculate boundingRect when locating.
       'all': Position the boundingRect that is transformed and uioned
              both itself and its descendants.
              This mode simplies confine the elements in the bounding
              of their container (e.g., using 'right: 0').
       'raw': Position the boundingRect that is not transformed and only itself.
              This mode is useful when you want a element can overflow its
              container. (Consider a rotated circle needs to be located in a corner.)
              In this mode positionInfo.width/height can only be number.