Making badge from RoundedRectangle

I’m trying to make a badge that is a circle until the text gets long enough to make it stretch horizontally which then the sides are half circles. I’m trying to use RoundedRectangle where the radius is half of the height but it doesn’t work. I also tried making the radius the same as the height but still doesn’t work. Should this be possible using RoundedRectangle, and if so, what am I missing? I increased the numbers to show what’s happening.

Here is the link label template:

        make('Panel', 'Auto', {
                segmentIndex: 0,
                segmentOffset: new go.Point(45, 0)
            },
            new go.Binding('visible', 'labelVisible'),
            make('Shape', 'RoundedRectangle', {
                parameter1: 25,
                minSize: new go.Size(50, 50),
                strokeWidth: 0,
                fill: '#f00'
            }),
            make('TextBlock', {
                textAlign: 'center',
                font: me.baseLinkFont,
                stroke: '#fff',
                text: '100'
            })
        )

One more question on badges which we are also going to put on nodes which are Panel.Vertical. Is there any way to overlay a badge in the TopRight when the type is Vertical without shifting the other content down? If not is using Table the best type putting both in the same row and column?

25 is too small a value for Shape.parameter1 to cause your nodes to always have sides without a straight segment. Try using a much larger value. After all, if it’s too small/short, a huge value won’t mess up the corner curve.

Use a “Spot” Panel if you want to position objects to overlay (or be completely outside) of another (usually larger) object. See GoJS Nodes -- Northwoods Software for some examples.

I set it to 5000 and it didn’t seem make a difference. I also tried using maxSize and minSize without any luck. Here is my code.

        make('Panel', 'Auto', {
                segmentIndex: 0,
                segmentOffset: new go.Point(10, 0)
            },
            new go.Binding('visible', 'badgeVisible'),
            make('Shape', 'RoundedRectangle', {
                parameter1: 5000,
                minSize: new go.Size(18, 18),
                maxSize: new go.Size(NaN, 18),
                strokeWidth: 0,
                fill: '#ff3b30'
            }),
            make('TextBlock', {
                textAlign: 'center',
                font: me.baseBadgeFont,
                stroke: '#fff'
            },
            new go.Binding('text', 'badgeText')
            )
        )

Zoom in on the badge.

Ah, the reason is that the radius for each corner is limited to 1/3 of the total side length.

So you’ll need to define your own figure that doesn’t have that limit. The Intro page about Shapes, GoJS Shapes -- Northwoods Software, shows you how to define new figures, at the bottom of the page. Except that those examples only implement rounded corners on either the top or the bottom sides, not on all sides.

I have my shape defined and working but need to find out what the height is. A RoundedRectangle uses parameter1 to set the radius but I always want it to be height / 2. The height parameter to the shape function is always 100 so that doesn’t work. I want the badge to use it’s natural height and not force the user to manually supply it. Here is my current code:

    go.Shape.defineFigureGenerator('Badge', function(shape, w, h) {
        var p1 = h / 2,
            geo = new go.Geometry();

        // a single figure consisting of straight lines and quarter-circle arcs
        geo.add(new go.PathFigure(0, p1)
            .add(new go.PathSegment(go.PathSegment.Arc, 180, 90, p1, p1, p1, p1))
            .add(new go.PathSegment(go.PathSegment.Line, w - p1, 0))
            .add(new go.PathSegment(go.PathSegment.Arc, 270, 90, w - p1, p1, p1, p1))
            .add(new go.PathSegment(go.PathSegment.Arc, 0, 90, w - p1, h - p1, p1, p1))
            .add(new go.PathSegment(go.PathSegment.Line, p1, h))
            .add(new go.PathSegment(go.PathSegment.Arc, 90, 90, p1, h - p1, p1, p1).close()));

        // don't intersect with two top corners when used in an "Auto" Panel
        geo.spot1 = new go.Spot(0, 0, 0.3 * p1, 0.3 * p1);
        geo.spot2 = new go.Spot(1, 1, -0.3 * p1, 0);
        
        return geo;
    });

And here is what it produces. The shape is exactly what I want but size is too big.

Changing the shape to RoundedRectangle produces the natural size that I want.

How can I get this natural size and calculate the radius from it for my custom shape?

The area that the “contents” of the “Auto” Panel can occupy is determined by the Shape.spot1 and Shape.spot2 properties. Those get default values from the Geometry.spot1 and Geometry.spot2 properties, which your figure generator probably wants to set.

But notice that you are specifying a “margin” that is about one third (0.3) of half the height. I think you want to use a smaller offset for both spots. Although I suspect zero is too small.

Thanks for your help I got it working and it stretches perfectly.

Here is the code if anyone might want to use it or for examples.

    go.Shape.defineFigureGenerator('Badge', function(shape, w, h) {
        var radius = h / 2,
            geo = new go.Geometry();

        // a single figure consisting of straight lines and half-circle arcs
        geo.add(new go.PathFigure(0, radius)
            .add(new go.PathSegment(go.PathSegment.Arc, 90, 180, radius, radius, radius, radius))
            .add(new go.PathSegment(go.PathSegment.Line, w - radius, 0))
            .add(new go.PathSegment(go.PathSegment.Arc, 270, 180, w - radius, radius, radius, radius))
            .add(new go.PathSegment(go.PathSegment.Line, radius, h).close()));

        // don't intersect with two top corners when used in an "Auto" Panel
        geo.spot1 = new go.Spot(0, 0, 0.1 * radius, 0.1 * radius);
        geo.spot2 = new go.Spot(1, 1, -0.1 * radius, 0);

        return geo;
    });