CoolFace
Apppublic

sourav-das/stem-separator

sourceHugging Facemitupdated 6mo agoView on Hugging Face
3likes
renderer-utils.js253 linesDownload Raw Back to dist
1export const DEFAULT_HEIGHT = 128;2export const MAX_CANVAS_WIDTH = 8000;3export const MAX_NODES = 10;4export function clampToUnit(value) {5    if (value < 0)6        return 0;7    if (value > 1)8        return 1;9    return value;10}11export function calculateBarRenderConfig({ width, height, length, options, pixelRatio, }) {12    const halfHeight = height / 2;13    const barWidth = options.barWidth ? options.barWidth * pixelRatio : 1;14    const barGap = options.barGap ? options.barGap * pixelRatio : options.barWidth ? barWidth / 2 : 0;15    const barRadius = options.barRadius || 0;16    const barMinHeight = options.barMinHeight ? options.barMinHeight * pixelRatio : 0;17    const spacing = barWidth + barGap || 1;18    const barIndexScale = length > 0 ? width / spacing / length : 0;19    return {20        halfHeight,21        barWidth,22        barGap,23        barRadius,24        barMinHeight,25        barIndexScale,26        barSpacing: spacing,27    };28}29export function calculateBarHeights({ maxTop, maxBottom, halfHeight, vScale, barMinHeight = 0, barAlign, }) {30    let topHeight = Math.round(maxTop * halfHeight * vScale);31    const bottomHeight = Math.round(maxBottom * halfHeight * vScale);32    let totalHeight = topHeight + bottomHeight || 1;33    if (totalHeight < barMinHeight) {34        totalHeight = barMinHeight;35        if (!barAlign) {36            topHeight = totalHeight / 2;37        }38    }39    return { topHeight, totalHeight };40}41export function resolveBarYPosition({ barAlign, halfHeight, topHeight, totalHeight, canvasHeight, }) {42    if (barAlign === 'top')43        return 0;44    if (barAlign === 'bottom')45        return canvasHeight - totalHeight;46    return halfHeight - topHeight;47}48export function calculateBarSegments({ channelData, barIndexScale, barSpacing, barWidth, halfHeight, vScale, canvasHeight, barAlign, barMinHeight, }) {49    const topChannel = channelData[0] || [];50    const bottomChannel = channelData[1] || topChannel;51    const length = topChannel.length;52    const segments = [];53    let prevX = 0;54    let maxTop = 0;55    let maxBottom = 0;56    for (let i = 0; i <= length; i++) {57        const x = Math.round(i * barIndexScale);58        if (x > prevX) {59            const { topHeight, totalHeight } = calculateBarHeights({60                maxTop,61                maxBottom,62                halfHeight,63                vScale,64                barMinHeight,65                barAlign,66            });67            const y = resolveBarYPosition({68                barAlign,69                halfHeight,70                topHeight,71                totalHeight,72                canvasHeight,73            });74            segments.push({75                x: prevX * barSpacing,76                y,77                width: barWidth,78                height: totalHeight,79            });80            prevX = x;81            maxTop = 0;82            maxBottom = 0;83        }84        const magnitudeTop = Math.abs(topChannel[i] || 0);85        const magnitudeBottom = Math.abs(bottomChannel[i] || 0);86        if (magnitudeTop > maxTop)87            maxTop = magnitudeTop;88        if (magnitudeBottom > maxBottom)89            maxBottom = magnitudeBottom;90    }91    return segments;92}93export function getRelativePointerPosition(rect, clientX, clientY) {94    const x = clientX - rect.left;95    const y = clientY - rect.top;96    const relativeX = x / rect.width;97    const relativeY = y / rect.height;98    return [relativeX, relativeY];99}100export function resolveChannelHeight({ optionsHeight, optionsSplitChannels, parentHeight, numberOfChannels, defaultHeight = DEFAULT_HEIGHT, }) {101    if (optionsHeight == null)102        return defaultHeight;103    const numericHeight = Number(optionsHeight);104    if (!isNaN(numericHeight))105        return numericHeight;106    if (optionsHeight === 'auto') {107        const height = parentHeight || defaultHeight;108        if (optionsSplitChannels === null || optionsSplitChannels === void 0 ? void 0 : optionsSplitChannels.every((channel) => !channel.overlay)) {109            return height / numberOfChannels;110        }111        return height;112    }113    return defaultHeight;114}115export function getPixelRatio(devicePixelRatio) {116    return Math.max(1, devicePixelRatio || 1);117}118export function shouldRenderBars(options) {119    return Boolean(options.barWidth || options.barGap || options.barAlign);120}121export function resolveColorValue(color, devicePixelRatio, canvasHeight) {122    if (!Array.isArray(color))123        return color || '';124    if (color.length === 0)125        return '#999';126    if (color.length < 2)127        return color[0] || '';128    const canvasElement = document.createElement('canvas');129    const ctx = canvasElement.getContext('2d');130    const gradientHeight = canvasHeight !== null && canvasHeight !== void 0 ? canvasHeight : canvasElement.height * devicePixelRatio;131    const gradient = ctx.createLinearGradient(0, 0, 0, gradientHeight || devicePixelRatio);132    const colorStopPercentage = 1 / (color.length - 1);133    color.forEach((value, index) => {134        gradient.addColorStop(index * colorStopPercentage, value);135    });136    return gradient;137}138export function calculateWaveformLayout({ duration, minPxPerSec = 0, parentWidth, fillParent, pixelRatio, }) {139    const scrollWidth = Math.ceil(duration * minPxPerSec);140    const isScrollable = scrollWidth > parentWidth;141    const useParentWidth = Boolean(fillParent && !isScrollable);142    const width = (useParentWidth ? parentWidth : scrollWidth) * pixelRatio;143    return {144        scrollWidth,145        isScrollable,146        useParentWidth,147        width,148    };149}150export function clampWidthToBarGrid(width, options) {151    if (!shouldRenderBars(options))152        return width;153    const barWidth = options.barWidth || 0.5;154    const barGap = options.barGap || barWidth / 2;155    const totalBarWidth = barWidth + barGap;156    if (totalBarWidth === 0)157        return width;158    return Math.floor(width / totalBarWidth) * totalBarWidth;159}160export function calculateSingleCanvasWidth({ clientWidth, totalWidth, options, }) {161    const baseWidth = Math.min(MAX_CANVAS_WIDTH, clientWidth, totalWidth);162    return clampWidthToBarGrid(baseWidth, options);163}164export function sliceChannelData({ channelData, offset, clampedWidth, totalWidth, }) {165    return channelData.map((channel) => {166        const start = Math.floor((offset / totalWidth) * channel.length);167        const end = Math.floor(((offset + clampedWidth) / totalWidth) * channel.length);168        return channel.slice(start, end);169    });170}171export function shouldClearCanvases(currentNodeCount) {172    return currentNodeCount > MAX_NODES;173}174export function getLazyRenderRange({ scrollLeft, totalWidth, numCanvases, }) {175    if (totalWidth === 0)176        return [0];177    const viewPosition = scrollLeft / totalWidth;178    const startCanvas = Math.floor(viewPosition * numCanvases);179    return [startCanvas - 1, startCanvas, startCanvas + 1];180}181export function calculateVerticalScale({ channelData, barHeight, normalize, maxPeak, }) {182    var _a;183    const baseScale = barHeight || 1;184    if (!normalize)185        return baseScale;186    const firstChannel = channelData[0];187    if (!firstChannel || firstChannel.length === 0)188        return baseScale;189    // Use fixed max peak if provided, otherwise calculate from data190    let max = maxPeak !== null && maxPeak !== void 0 ? maxPeak : 0;191    if (!maxPeak) {192        for (let i = 0; i < firstChannel.length; i++) {193            const value = (_a = firstChannel[i]) !== null && _a !== void 0 ? _a : 0;194            const magnitude = Math.abs(value);195            if (magnitude > max)196                max = magnitude;197        }198    }199    if (!max)200        return baseScale;201    return baseScale / max;202}203export function calculateLinePaths({ channelData, width, height, vScale, }) {204    const halfHeight = height / 2;205    const primaryChannel = channelData[0] || [];206    const secondaryChannel = channelData[1] || primaryChannel;207    const channels = [primaryChannel, secondaryChannel];208    return channels.map((channel, index) => {209        const length = channel.length;210        const hScale = length ? width / length : 0;211        const baseY = halfHeight;212        const direction = index === 0 ? -1 : 1;213        const path = [{ x: 0, y: baseY }];214        let prevX = 0;215        let max = 0;216        for (let i = 0; i <= length; i++) {217            const x = Math.round(i * hScale);218            if (x > prevX) {219                const heightDelta = Math.round(max * halfHeight * vScale) || 1;220                const y = baseY + heightDelta * direction;221                path.push({ x: prevX, y });222                prevX = x;223                max = 0;224            }225            const value = Math.abs(channel[i] || 0);226            if (value > max)227                max = value;228        }229        path.push({ x: prevX, y: baseY });230        return path;231    });232}233/**234 * @deprecated Use calculateScrollPercentages from './reactive/scroll-stream.js' instead.235 * This function is maintained for backward compatibility but will be removed in a future version.236 */237export function calculateScrollPercentages({ scrollLeft, clientWidth, scrollWidth, }) {238    if (scrollWidth === 0) {239        return { startX: 0, endX: 1 };240    }241    const startX = scrollLeft / scrollWidth;242    const endX = (scrollLeft + clientWidth) / scrollWidth;243    return {244        startX: Math.max(0, Math.min(1, startX)),245        endX: Math.max(0, Math.min(1, endX)),246    };247}248export function roundToHalfAwayFromZero(value) {249    const scaled = value * 2;250    const rounded = scaled < 0 ? Math.floor(scaled) : Math.ceil(scaled);251    return rounded / 2;252}253