Zoomable cartesian canvas   otázka

WPF

Dobrý den,

potřeboval bych vytvořit Canvas s nulovým bodem uprostřed. A aby se automaticky přizpůsoboval měřítkem obsahu.

Na první část funguje celkem dobře:

<Canvas RenderTransformOrigin="0.5,0.5" 
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" 
                Height="Auto" 
                Width="Auto" >
            <Rectangle Width="50" Height="50" Canvas.Left="-25" Canvas.Top="-25" Stroke="Black" StrokeThickness="5" />
            <Rectangle Width="100" Height="100" Canvas.Left="25" Canvas.Top="25" Stroke="Red" StrokeThickness="5" />
...
        </Canvas>

S druhou částí jsem zkoušel uzavřít canvas do viewboxu, ale to nefunguje.

Věděl by někdo jak na to ?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

je to způsobené tím, že velikost Canvasu nezávisí na velikosti elementů, které v něm jsou obsaženy. Velikost Canvasu závisí pouze na elementu, uvnitř kterého je umístěn. Pokud je canvas umístěn uvnitř ViewBoxu (nebo jiného elementu, který je schopen svým potomkům nabídnout "nekonečnou" plochu - např ScrollViewer), je velikost Canvasu 0;0 a jeho potomci jsou vykresleny mimo jeho plochu.

Teď ta složitější část, jak to vyřešit :) Nenapadá mě žádné jednoduché řešení na "jeden řádek".

1) Napsat si vlastní Canvas, který bude řešit celý váš probléme, tedy bod 0,0 bude vykreslovat uprostřed plochy a automaticky bude měnit měřítko jako Viewbox. Není to složité, ale je potřeba znát, jak funguje WPF a jak přetížit MeasureOverride a ArrangeOverride.

2) Při každé změně elementů uvnitř Canvasu spočítat, jak velký je potřeba Canvas, aby se do něj všechno vešlo a tuto velikost nastavit jako rozměry canvasu. Canvas pak umístit do Viewboxu. Canvas už pak nebude mít nulovou velikost a Viewbox bude umět vypočítat měřítko.

        private void CalculateCanvasSize()
        {
            double maxX = 0;
            double maxY = 0;

            foreach (FrameworkElement element in canvas.Children)
            {
                //zjistit hodnoty pro element
                var left = Canvas.GetLeft(element);
                var right = Canvas.GetRight(element);
                var top = Canvas.GetTop(element);
                var bottom = Canvas.GetBottom(element);

                //vypočítat hranice objektu
                if (double.IsNaN(left) == false)
                    right = left + element.ActualWidth;
                else if (double.IsNaN(right) == false)
                    throw new NotSupportedException();
                else { left = 0; right = element.ActualWidth; }

                if (double.IsNaN(top) == false)
                    bottom = top + element.ActualHeight;
                else if (double.IsNaN(bottom) == false)
                    throw new NotSupportedException();
                else { top = 0; bottom = element.ActualHeight; }

                //uložit největší vzdálenost od bodu 0;0
                maxX = Math.Max(maxX, Math.Max(Math.Abs(left), Math.Abs(right)));
                maxY = Math.Max(maxY, Math.Max(Math.Abs(top), Math.Abs(bottom)));
            }

            //nastavit canvas na dvojnásobek maximální vzdálenost (dvojnásobek, jde se na obě strany)
            canvas.Width = 2 * maxX;
            canvas.Height = 2 * maxY;

            //souřadnice objektů v canvasu jsou vzhledem k levémmu hornímu rohu => změnou velikosti canvasu se posune jeho levý horní roh => je třeba posunout objekty v canvasu
            canvas.RenderTransform = new TranslateTransform(maxX, maxY);
        }

Pro úplnost přikládám i XAML

    <Grid>
        <Viewbox>
            <Canvas Name="canvas" 
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
                <Rectangle Width="50" Height="50" Canvas.Left="-25" Canvas.Top="-25" Stroke="Black" StrokeThickness="5" />
                <Rectangle Width="100" Height="100" Canvas.Left="25" Canvas.Top="25" Stroke="Red" StrokeThickness="5" />
                <Rectangle Width="1000" Height="10" Stroke="Red" />
                <Rectangle Width="90" Height="10" Canvas.Left="10" Canvas.Top="50" Stroke="Blue" />
            </Canvas>
        </Viewbox>
    </Grid>
nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback