SVG饼图/互动圈

问题描述 投票:0回答:1

我正在创建一个具有不同分段的 svg 圆圈,其工作方式类似于用于显示/隐藏内容的选项卡。它基本上是一个饼图。我无法在视觉上区分我正在创建的片段。我需要它从圆的中心到外侧进行描边。我觉得我需要弄清楚 stroke-dasharray 属性?希望得到一些帮助来了解如何配置。

我的其他想法是使用边距来抵消segmentPath函数,但客户不喜欢它的外观。最后有一个想法,即为每个线段添加一个单独的线元素 - 从圆的边缘到中心。任何帮助都会很棒。

/**
 * Polar to Cartesian.
 * 
 * Håken Lid's SVG circle segments.
 * 
 * @see https://observablehq.com/@haakenlid/svg-circle
 * @see https://blog.logrocket.com/interactive-svg-circle-of-fifths/#arcs-circles
 */
function polarToCartesian(x, y, r, degrees) {
    const radians = degrees * Math.PI / 180.0;
    return [x + (r * Math.cos(radians)), y + (r * Math.sin(radians))]
}

/**
 * Segment Path.
 * 
 * Håken Lid's SVG circle segments.
 * 
 * @see https://observablehq.com/@haakenlid/svg-circle
 * @see https://blog.logrocket.com/interactive-svg-circle-of-fifths/#arcs-circles
 */
function segmentPath(x, y, r0, r1, d0, d1) {
    const arc = Math.abs(d0 - d1) > 180 ? 1 : 0
    const point = (radius, degree) =>
        polarToCartesian(x, y, radius, degree)
            .map(n => n.toPrecision(5))
            .join(',')
    return [
        `M${point(r0, d0)}`,
        `A${r0},${r0},0,${arc},1,${point(r0, d1)}`,
        `L${point(r1, d1)}`,
        `A${r1},${r1},0,${arc},0,${point(r1, d0)}`,
        'Z',
    ].join('')
}

/**
 * Segment Function.
 * 
 * Modified version of Håken Lid's SVG circle segments.
 * 
 * @see https://observablehq.com/@haakenlid/svg-circle
 * @see https://blog.logrocket.com/interactive-svg-circle-of-fifths/#arcs-circles
 */
function segment(i, segments, size, radius, width, className, fillColor) {
    const center = size/2
    const degrees = 360 / segments
    const start = degrees * i
    const end = (degrees * (i + 1) + 1)
    const path = segmentPath(center, center, radius, radius-width, start, end); 
    const el = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
    el.setAttribute(
        'd',
        path
    );
    el.classList.add( 'path-segment', className );
    el.style.fill = fillColor;

    return el;
}

/**
 * Render.
 * 
 * Function that will render the svg circle.
 */
function render() {
    // Circle Div.
    const circleDiv = document.getElementById( 'interactive-circle-svg' );

    if ( null !== circleDiv ) {

        // Setup environment.
        const svgSize = 580
        const segments = 6
        const segmentWidth = 60
        const outerFill = '#FB8D00'
        const middleFill = '#E68E36'
        const innerFill = '#F9B46F'

        // Set cirlce div attributes.
        circleDiv.style.height = svgSize + 'px';
        circleDiv.style.width = svgSize + 'px';
        circleDiv.style.transform = `rotate(${ 360/2 }deg)`
        circleDiv.style.transformOrigin = '50% 50%'

        // SVG NS.
        const svgns = 'http://www.w3.org/2000/svg';

        // Create the <svg>.
        const svg = document.createElementNS( svgns, 'svg' )
        svg.setAttribute( 'viewbox', `0 0 ${svgSize} ${svgSize}` );
        svg.setAttribute( 'overflow', 'visible' );
        svg.setAttribute( 'stroke', '#000' );
        svg.setAttribute( 'stroke-width', 3 );

        // Attach the children nodes.
        for ( let i = 0; i < segments; i++ ) {
            // Create the first <g>.
            let n = i + 1,
                radius1 = svgSize/2,
                radius2 = svgSize/2-segmentWidth+1,
                radius3 = svgSize/2-(segmentWidth*2)+2,
                g1 = document.createElementNS( svgns, 'g' );
            g1.classList.add( 'segment', `segment-${n}` );
            g1.setAttribute( 'data-segment-number', n );
            
            // Attach segments to the <g>.
            g1.appendChild( segment( i, segments, svgSize, radius1, segmentWidth, 'outer', outerFill ) );
            g1.appendChild( segment( i, segments, svgSize, radius2, segmentWidth, 'middle', middleFill ) );
            g1.appendChild( segment( i, segments, svgSize, radius3, segmentWidth, 'inner', innerFill ) );


            // Attach the <g> to the <svg>
            svg.appendChild( g1 );

            // Create event handlers with the g1.
            g1.addEventListener( 'click', function(e){
                const segNumber = this.getAttribute( 'data-segment-number' );

                // Hide bodies.
                const bodies = document.getElementsByClassName( 'segment-body' )
                for ( let i = 0; i < bodies.length; i++ ) {
                    if ( ! bodies[i].classList.contains( 'hide' ) ) {
                        bodies[i].classList.add( 'hide' );
                    }
                }

                // Show correct body.
                const body = document.getElementById( 'segment-body-' +  segNumber);
                body.classList.remove( 'hide' );
            });
        }

        // Attach to div.
        circleDiv.append( svg );
    }   
}

// Attach render to onload.
window.onload = render;
<div id="interactive-circle-svg"></div>

javascript svg
1个回答
0
投票

根据提供的代码,实现所需的功能,将线元素添加到从圆心到圆边缘的每个线段,这段代码,

g1.appendChild( segment( i, segments, svgSize, radius3, segmentWidth, 'inner', innerFill ) );

应替换为此代码,

g1.appendChild( segment( i, segments, svgSize, radius3, radius3, 'inner', innerFill ) );

可以检查一下是否有效。

© www.soinside.com 2019 - 2024. All rights reserved.