"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.addWaterWave = void 0;
var tslib_1 = require("tslib");
var g2_1 = require("@antv-source/g2");
var util_1 = require("@antv/util");
var matrix_1 = require("../../../utils/matrix");
var DURATION = 5000;
/**
 * 一个线性映射的函数
 * @param min
 * @param max
 * @param factor
 */
function lerp(min, max, factor) {
    return min + (max - min) * factor;
}
/**
 * 波浪的 attrs
 * @param cfg
 */
function getFillAttrs(cfg) {
    var attrs = tslib_1.__assign({ opacity: 1 }, cfg.style);
    if (cfg.color && !attrs.fill) {
        attrs.fill = cfg.color;
    }
    return attrs;
}
/**
 * shape 的 attrs
 * @param cfg
 */
function getLineAttrs(cfg) {
    var defaultAttrs = {
        fill: '#fff',
        fillOpacity: 0,
        lineWidth: 4,
    };
    var attrs = (0, util_1.mix)({}, defaultAttrs, cfg.style);
    if (cfg.color && !attrs.stroke) {
        attrs.stroke = cfg.color;
    }
    if ((0, util_1.isNumber)(cfg.opacity)) {
        attrs.opacity = attrs.strokeOpacity = cfg.opacity;
    }
    return attrs;
}
/**
 * 用贝塞尔曲线模拟正弦波
 * Using Bezier curves to fit sine wave.
 * There is 4 control points for each curve of wave,
 * which is at 1/4 wave length of the sine wave.
 *
 * The control points for a wave from (a) to (d) are a-b-c-d:
 *          c *----* d
 *     b *
 *       |
 * ... a * ..................
 *
 * whose positions are a: (0, 0), b: (0.5, 0.5), c: (1, 1), d: (PI / 2, 1)
 *
 * @param x          x position of the left-most point (a)
 * @param stage      0-3, stating which part of the wave it is
 * @param waveLength wave length of the sine wave
 * @param amplitude  wave amplitude
 * @return 正弦片段曲线
 */
function getWaterWavePositions(x, stage, waveLength, amplitude) {
    if (stage === 0) {
        return [
            [x + ((1 / 2) * waveLength) / Math.PI / 2, amplitude / 2],
            [x + ((1 / 2) * waveLength) / Math.PI, amplitude],
            [x + waveLength / 4, amplitude],
        ];
    }
    if (stage === 1) {
        return [
            [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 2), amplitude],
            [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 1), amplitude / 2],
            [x + waveLength / 4, 0],
        ];
    }
    if (stage === 2) {
        return [
            [x + ((1 / 2) * waveLength) / Math.PI / 2, -amplitude / 2],
            [x + ((1 / 2) * waveLength) / Math.PI, -amplitude],
            [x + waveLength / 4, -amplitude],
        ];
    }
    return [
        [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 2), -amplitude],
        [x + (((1 / 2) * waveLength) / Math.PI / 2) * (Math.PI - 1), -amplitude / 2],
        [x + waveLength / 4, 0],
    ];
}
/**
 * 获取水波路径
 * @param radius          半径
 * @param waterLevel      水位
 * @param waveLength      波长
 * @param phase           相位
 * @param amplitude       震幅
 * @param cx              圆心x
 * @param cy              圆心y
 * @return path            路径
 * @reference http://gitlab.alipay-inc.com/datavis/g6/blob/1.2.0/src/graph/utils/path.js#L135
 */
function getWaterWavePath(radius, waterLevel, waveLength, phase, amplitude, cx, cy) {
    var curves = Math.ceil(((2 * radius) / waveLength) * 4) * 4;
    var path = [];
    var _phase = phase;
    // map phase to [-Math.PI * 2, 0]
    while (_phase < -Math.PI * 2) {
        _phase += Math.PI * 2;
    }
    while (_phase > 0) {
        _phase -= Math.PI * 2;
    }
    _phase = (_phase / Math.PI / 2) * waveLength;
    var left = cx - radius + _phase - radius * 2;
    /**
     * top-left corner as start point
     *
     * draws this point
     *  |
     * \|/
     *  ~~~~~~~~
     *  |      |
     *  +------+
     */
    path.push(['M', left, waterLevel]);
    /**
     * top wave
     *
     * ~~~~~~~~ <- draws this sine wave
     * |      |
     * +------+
     */
    var waveRight = 0;
    for (var c = 0; c < curves; ++c) {
        var stage = c % 4;
        var pos = getWaterWavePositions((c * waveLength) / 4, stage, waveLength, amplitude);
        path.push([
            'C',
            pos[0][0] + left,
            -pos[0][1] + waterLevel,
            pos[1][0] + left,
            -pos[1][1] + waterLevel,
            pos[2][0] + left,
            -pos[2][1] + waterLevel,
        ]);
        if (c === curves - 1) {
            waveRight = pos[2][0];
        }
    }
    /**
     * top-right corner
     *
     *                       ~~~~~~~~
     * 3. draws this line -> |      | <- 1. draws this line
     *                       +------+
     *                          ^
     *                          |
     *                  2. draws this line
     */
    path.push(['L', waveRight + left, cy + radius]);
    path.push(['L', left, cy + radius]);
    path.push(['Z']);
    // path.push(['L', left, waterLevel]);
    return path;
}
/**
 * 添加水波
 * @param x           中心x
 * @param y           中心y
 * @param level       水位等级 0～1
 * @param waveCount   水波数
 * @param waveAttrs      色值
 * @param group       图组
 * @param clip        用于剪切的图形
 * @param radius      绘制图形的高度
 * @param waveLength  波的长度
 */
function addWaterWave(x, y, level, waveCount, waveAttrs, group, clip, radius, waveLength, animation) {
    // 盒子属性 颜色 宽高
    var fill = waveAttrs.fill, opacity = waveAttrs.opacity;
    var bbox = clip.getBBox();
    var width = bbox.maxX - bbox.minX;
    var height = bbox.maxY - bbox.minY;
    // 循环 waveCount 个数
    for (var idx = 0; idx < waveCount; idx++) {
        var factor = waveCount <= 1 ? 1 : idx / (waveCount - 1);
        // 画波
        var wave = group.addShape('path', {
            name: "waterwave-path",
            attrs: {
                // 波形路径配置
                path: getWaterWavePath(radius, bbox.minY + height * level, waveLength, 0, width / 32, // 波幅高度
                x, y),
                fill: fill,
                opacity: lerp(0.2, 0.9, factor) * opacity,
            },
        });
        try {
            // 默认 underfind 开启动画
            if (animation === false)
                return;
            var matrix = (0, matrix_1.transform)([['t', waveLength, 0]]);
            wave.stopAnimate();
            wave.animate({ matrix: matrix }, {
                duration: lerp(0.5 * DURATION, DURATION, factor),
                repeat: true,
            });
        }
        catch (e) {
            // TODO off-screen canvas 中动画会找不到 canvas
            console.warn('off-screen group animate error!');
        }
    }
}
exports.addWaterWave = addWaterWave;
/**
 *
 * @param x 中心 x
 * @param y 中心 y
 * @param width 外接矩形的宽
 * @param height 外接矩形的高
 */
function pin(x, y, width, height) {
    var w = (width * 2) / 3;
    var h = Math.max(w, height);
    var r = w / 2;
    // attrs of the upper circle
    var cx = x;
    var cy = r + y - h / 2;
    var theta = Math.asin(r / ((h - r) * 0.85));
    var dy = Math.sin(theta) * r;
    var dx = Math.cos(theta) * r;
    // the start point of the path
    var x0 = cx - dx;
    var y0 = cy + dy;
    // control point
    var cpX = x;
    var cpY = cy + r / Math.sin(theta);
    return "\n      M ".concat(x0, " ").concat(y0, "\n      A ").concat(r, " ").concat(r, " 0 1 1 ").concat(x0 + dx * 2, " ").concat(y0, "\n      Q ").concat(cpX, " ").concat(cpY, " ").concat(x, " ").concat(y + h / 2, "\n      Q ").concat(cpX, " ").concat(cpY, " ").concat(x0, " ").concat(y0, "\n      Z \n    ");
}
/**
 *
 * @param x 中心 x
 * @param y 中心 y
 * @param width 外接矩形的宽
 * @param height 外接矩形的高
 */
function circle(x, y, width, height) {
    var rx = width / 2;
    var ry = height / 2;
    return "\n      M ".concat(x, " ").concat(y - ry, " \n      a ").concat(rx, " ").concat(ry, " 0 1 0 0 ").concat(ry * 2, "\n      a ").concat(rx, " ").concat(ry, " 0 1 0 0 ").concat(-ry * 2, "\n      Z\n    ");
}
/**
 *
 * @param x 中心 x
 * @param y 中心 y
 * @param width 外接矩形的宽
 * @param height 外接矩形的高
 */
function diamond(x, y, width, height) {
    var h = height / 2;
    var w = width / 2;
    return "\n      M ".concat(x, " ").concat(y - h, "\n      L ").concat(x + w, " ").concat(y, "\n      L ").concat(x, " ").concat(y + h, "\n      L ").concat(x - w, " ").concat(y, "\n      Z\n    ");
}
/**
 *
 * @param x 中心 x
 * @param y 中心 y
 * @param width 外接矩形的宽
 * @param height 外接矩形的高
 */
function triangle(x, y, width, height) {
    var h = height / 2;
    var w = width / 2;
    return "\n      M ".concat(x, " ").concat(y - h, "\n      L ").concat(x + w, " ").concat(y + h, "\n      L ").concat(x - w, " ").concat(y + h, "\n      Z\n    ");
}
/**
 *
 * @param x 中心 x
 * @param y 中心 y
 * @param width 外接矩形的宽
 * @param height 外接矩形的高
 */
function rect(x, y, width, height) {
    var GOLDEN_SECTION_RATIO = 0.618;
    var h = height / 2;
    var w = (width / 2) * GOLDEN_SECTION_RATIO;
    return "\n      M ".concat(x - w, " ").concat(y - h, "\n      L ").concat(x + w, " ").concat(y - h, "\n      L ").concat(x + w, " ").concat(y + h, "\n      L ").concat(x - w, " ").concat(y + h, "\n      Z\n    ");
}
var builtInShapeByName = {
    pin: pin,
    circle: circle,
    diamond: diamond,
    triangle: triangle,
    rect: rect,
};
(0, g2_1.registerShape)('interval', 'liquid-fill-gauge', {
    draw: function (cfg, container) {
        var cx = 0.5;
        var cy = 0.5;
        var customInfo = cfg.customInfo;
        var _a = customInfo, percent = _a.percent, radio = _a.radius, shape = _a.shape, shapeStyle = _a.shapeStyle, background = _a.background, animation = _a.animation;
        var outline = customInfo.outline;
        var wave = customInfo.wave;
        var border = outline.border, distance = outline.distance;
        var waveCount = wave.count, waveLength = wave.length;
        // 获取最小 minX
        var minX = (0, util_1.reduce)(cfg.points, function (r, p) {
            return Math.min(r, p.x);
        }, Infinity);
        var center = this.parsePoint({ x: cx, y: cy });
        var minXPoint = this.parsePoint({ x: minX, y: cy });
        var halfWidth = center.x - minXPoint.x;
        // 保证半径是 画布宽高最小值的 radius 值
        var radius = Math.min(halfWidth, minXPoint.y * radio);
        var waveAttrs = getFillAttrs(cfg);
        var outlineAttrs = getLineAttrs((0, util_1.mix)({}, cfg, outline));
        var innerRadius = radius - border / 2;
        var buildPath = typeof shape === 'function' ? shape : builtInShapeByName[shape] || builtInShapeByName['circle'];
        var shapePath = buildPath(center.x, center.y, innerRadius * 2, innerRadius * 2);
        // 1. 当 shapeStyle 不为空时，绘制形状样式作为背景
        if (shapeStyle) {
            container.addShape('path', {
                name: 'shape',
                attrs: tslib_1.__assign({ path: shapePath }, shapeStyle),
            });
        }
        // 比例大于 0 时才绘制水波
        if (percent > 0) {
            // 2. 绘制一个波
            var waves = container.addGroup({
                name: 'waves',
            });
            // 3. 波对应的 clip 裁剪形状
            var clipPath = waves.setClip({
                type: 'path',
                attrs: {
                    path: shapePath,
                },
            });
            // 4. 绘制波形
            addWaterWave(center.x, center.y, 1 - cfg.points[1].y, waveCount, waveAttrs, waves, clipPath, radius * 2, waveLength, animation);
        }
        // 5. 绘制一个 distance 宽的 border
        container.addShape('path', {
            name: 'distance',
            attrs: {
                path: shapePath,
                fill: 'transparent',
                lineWidth: border + distance * 2,
                stroke: background === 'transparent' ? '#fff' : background,
            },
        });
        // 6. 绘制一个 border 宽的 border
        container.addShape('path', {
            name: 'wrap',
            attrs: (0, util_1.mix)(outlineAttrs, {
                path: shapePath,
                fill: 'transparent',
                lineWidth: border,
            }),
        });
        return container;
    },
});
//# sourceMappingURL=liquid.js.map