Misalignment of svg elements on resizing/scaling


#1

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)
};

#2

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);

#3

That can only help case 3/3