Misalignment of svg elements on resizing/scaling

Hi all,

I’ve noticed that adjacent SVG elements become slightly misaligned when they are resized or scaled. It seems like this is to do with floating point truncation or rounding but I can’t find where this is occurring.

Below is a simple example application that adds 3 copies of an SVG containing 4 adjacent squares to a window. The first copy resizes trivially, the second sets a transform and the 3rd sets a transform and puts the component in a Viewport. On resizing, you can see in each copy of the svg the black squares go in and out of alignment and the copy within the Viewport also comes away at the edges. I have attached a screenshot to show the application window after resizing – you can see that the black squares are misaligned and the 3rd copy has also come away at its left edge. Before resizing everything is perfectly aligned.

Can anyone propose a solution to this? Or even just shed any light on what exactly is going on here?

Thanks,

George

After resizing:

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"

static const char* gapTestSVG = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<svg version=\"1.1\" id=\"GapTest\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\""
"width=\"333px\" height=\"110px\" viewBox=\"0 0 333 110\" style=\"enable-background:new 0 0 333 110;\" xml:space=\"preserve\">"
"<rect x=\"20\" y=\"20\" style=\"fill:#1A1A1A;\" width=\"30\" height=\"30\"/>"
"<rect x=\"50\" y=\"50\" style=\"fill:#1A1A1A;\" width=\"30\" height=\"30\"/>"
"<rect x=\"20\" y=\"50\" style=\"fill:#1A1A1A;\" width=\"30\" height=\"30\"/>"
"<rect x=\"50\" y=\"20\" style=\"fill:#1A1A1A;\" width=\"30\" height=\"30\"/>"
"<rect x=\"10\" y=\"10\" style=\"fill:none;stroke:#FF0000;stroke-miterlimit:10;\" width=\"80\" height=\"80\"/>"
"</svg>";

class Holder : public Component
{
public:
    Holder()
    :   svg (Drawable::createFromImageData (gapTestSVG, String (gapTestSVG).getNumBytesAsUTF8()))
    {
        setBounds (svg->getDrawableBounds().withZeroOrigin().getSmallestIntegerContainer());
    }
    
    void paint (Graphics& g) override
    {
        g.fillAll (Colour (0xffffffff));
        svg->drawWithin (g, getLocalBounds().toFloat(), RectanglePlacement::centred, 1.0f);
    }
    
private:
    ScopedPointer<Drawable> svg;
};

//==============================================================================


class MainContentComponent   : public Component
{
public:
    MainContentComponent()
    {
        addAndMakeVisible (holderResized);
        addAndMakeVisible (holderTransformed);
        viewport.setViewedComponent (&holderTransformedScrollable, false);
        addAndMakeVisible (viewport);
        
        setSize (1200, 400);
    }
    
    void resized() override
    {
        auto areaReamining = getLocalBounds();
        
        holderResized.setBounds (areaReamining.removeFromLeft (areaReamining.getWidth() / 3));
        
        auto xform = RectanglePlacement (RectanglePlacement::centred)
        .getTransformToFit (holderTransformed.getBounds().toFloat(),
                            areaReamining.removeFromLeft (areaReamining.getWidth() / 2).toFloat());
        
        holderTransformed.setTransform (xform);
        
        auto xformScrollable = RectanglePlacement (RectanglePlacement::centred)
        .getTransformToFit (holderTransformedScrollable.getBounds().toFloat(),
                            areaReamining.toFloat());
        
        holderTransformedScrollable.setTransform (xformScrollable);
        
        viewport.setBounds (areaReamining);
    }
    
    void mouseDown (const MouseEvent& e) override
    {
        holderResized.repaint();
        holderTransformed.repaint();
    }
    
private:
    Holder holderResized;
    Holder holderTransformed;
    Holder holderTransformedScrollable;
    Viewport viewport;
    
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};
1 Like

You just need to set the bounds to viewport. Do not set the bounds to holderTransformedScrollable in MainContentComponent’s resized method.
basically remove these lines

         auto xformScrollable = RectanglePlacement (RectanglePlacement::centred).getTransformToFit(holderTransformedScrollable.getBounds().toFloat(),areaReamining.toFloat());
       
        holderTransformedScrollable.setTransform (xformScrollable);

That can only help case 3/3