title: Synchronize transform matrix of superview and individual views in different coordinate space
body: <p><strong>Given following view hierarchy:</strong></p>
  
  <pre><code>root (e.g. view of a view controller)
    |_superview: A view where we will draw a cross using core graphics
      |_container: Clips subview
        |_subview: A view where we will show a cross adding subviews, which has to align perfectly with the cross drawn in superview
          |_horizontal line of cross
          |_vertical line of cross
  </code></pre>
  
  <p><strong>Task:</strong></p>
  
  <p>The crosses of <code>superview</code> and <code>subview</code> have to be always aligned, given a global transform. More details in "requirements" section.</p>
  
  <p><strong>Context:</strong></p>
  
  <p>The view hierarchy above belongs to a chart. In order to provide maximal flexibility, it allows to present chart points &amp; related content in 3 different ways:</p>
  
  <ol>
  <li><p>Drawing in the chart's base view (<code>superview</code>) <code>draw</code> method.</p></li>
  <li><p>Adding subviews to <code>subview</code>. <code>subview</code> is transformed on zoom/pan and with this automatically its subviews.</p></li>
  <li><p>Adding subviews to a sibling of <code>subview</code>. Not presented in view hierarchy for simplicity and because it's not related with the problem. Only mentioning it here to give an overview. The difference between this method and 2., is that here the view is not transformed, so it's left to the implementation of the content to update "manually" the transform of all the children.</p></li>
  </ol>
  
  <p>Maximal flexibility! But with this comes the cost that it's a bit tricky to implement. Specifically point 2.</p>
  
  <p>Currently I got zoom/pan working by basically processing the transforms for <code>superview</code> core graphics drawing and <code>subview</code> separately, but this leads to redundancy and error-proneness, e.g. repeated code for boundary checks, etc.</p>
  
  <p>So now I'm trying to refactor it to use one global matrix to store all the transforms and derive everything from it. Applying the global matrix to the coordinates used by <code>superview</code> to draw is trivial, but deriving the matrix of <code>subview</code>, given requirements listed in next section, not so much.</p>
  
  <p>I mention "crosses" in the view hierarchy section because this is what I'm using in my playgrounds as a simplified representation of one chart point (with x/y guidelines) (you can scroll down for images and gists).</p>
  
  <p><strong>Requirements:</strong></p>
  
  <ol>
  <li>The content can be zoomed and panned.</li>
  <li>The crosses stay always perfectly aligned.</li>
  <li><code>subview</code>'s subviews, i.e. the cross line views can't be touched (e.g. to apply transforms to them) - all that can be modified is <code>subview</code>'s transform.</li>
  <li>The zooming and panning transforms are stored only in a global matrix <code>matrix</code>.</li>
  <li><code>matrix</code> is then used to calculate the coordinates of the cross drawn in <code>superview</code> (trivial), as well as the transform matrix of <code>subview</code> (not trivial - reason of this question). 
  
  <ul>
  <li>Since it doesn't seem to be possible to derive the matrix of <code>subview</code> uniquely from the global matrix, it's allowed to store additional data in variables, which are then used together with the global matrix to calculate <code>subview</code>'s matrix.</li>
  </ul></li>
  <li>The size/origin of <code>container</code> can change during zoom/pan. The reason of this is that the labels of the y-axis can have different lengths, and the chart is required to adapt the content size dynamically to the space occupied by the labels (during zooming and panning).</li>
  <li>Of course when the size of <code>container</code> changes, the ratio of domain - screen coordinates has to change accordingly, such that the complete original visible domain continues to be contained in <code>container</code>. E.g if I'm displaying an x-axis with a domain [0, 10] in a container frame with a width of 500pt, i.e. the ratio to convert a domain point to screen coordinates is <code>500/10=50</code>, and shrink the container width to 250, now my [0, 10] domain, which has to fit in this new width, has a ratio of 25.</li>
  <li>It has to work also for multiple crosses (at the same time) and arbitrary domain locations for each. This should happen automatically by solving 1-7 but mentioning it for completeness.</li>
  </ol>
  
  <p><strong>What I have done:</strong></p>
  
  <p>Here are step-by-step playgrounds I did to try to understand the problem better:</p>
  
  <p><strong>Step 1 (works):</strong> </p>
  
  <p>Build hierarchy as described at the beginning, displaying nothing but crosses that have to stay aligned during (programmatic) zoom &amp; pan. Meets requirements 1, 2, 3, 4 and 5:</p>
  
  <p><a href="https://i.stack.imgur.com/vgAzQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/vgAzQ.png" alt="enter image description here"></a>
  <a href="https://gist.github.com/i-schuetz/52eb0f3fb38e7274fd89a6db67bb08ed" rel="nofollow noreferrer">Gist with playground.</a></p>
  
  <p>Particularities here:</p>
  
  <ul>
  <li>I skipped <code>container</code> view, to keep it simple. <code>subview</code> is a direct subview of <code>superview</code>.</li>
  <li><code>subview</code> has the same size as <code>superview</code> (before zooming of course), also to keep it simple.</li>
  <li>I set the anchor point of <code>subview</code> to the origin (0, 0), which seems to be necessary to be in sync with the global matrix.</li>
  <li>The translation used for the anchor change has to be remembered, in order to apply it again together with the global matrix. Otherwise it gets overwritten. For this I use the variable <code>subviewAnchorTranslation</code>. This belongs to the additional data I had in mind in the bullet under requirement 5.</li>
  </ul>
  
  <p>Ok, as you see everything works here. Time to try the next step.</p>
  
  <p><strong>Step 2 (works):</strong> </p>
  
  <p>A copy of step 1 playground with modifications:</p>
  
  <ul>
  <li>Added <code>container</code> view, resembling now the view hierarchy described at the beginning.</li>
  <li>In order for <code>subview</code>, which is now a subview of <code>container</code> to continue being displayed at the same position, it has to be moved to top and left by <code>-container.origin</code>.</li>
  <li>Now the zoom and pan calls are interleaved randomly with calls to change the frame position/size of container.</li>
  </ul>
  
  <p>The crosses continue to be in sync. Requirements met: All from step 1 + requirement 6.
  <a href="https://i.stack.imgur.com/CXKGR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/CXKGR.png" alt="enter image description here"></a>
  <a href="https://gist.github.com/i-schuetz/c8da84ca5f2b4064f961a69f4407c2e6" rel="nofollow noreferrer">Gist with playground</a></p>
  
  <p><strong>Step 3 (doesn't work):</strong></p>
  
  <p>So far I have been working with a screen range that starts at 0 (left side of the visible playground result). Which means that <code>container</code> is not fulfilling it's function to contain the range, i.e. requirement 7. In order to meet this, <code>container</code>'s origin has to be included in the ratio calculation.</p>
  
  <p>Now also <code>subview</code> has to be scaled in order to fit in <code>container</code> / display the cross at the correct place. Which adds a second variable (first being <code>subviewAnchorTranslation</code>), which I called <code>contentScalingFactor</code>, containing this scaling, that has to be included in <code>subview</code>'s matrix calculation.</p>
  
  <p>Here I've done multiple experiments, all of them failed. In the current state, <code>subview</code> starts with the same frame as <code>container</code> and its frame is adjusted + scaled when the frame of <code>container</code> changes. Also, <code>subview</code> being now inside container, i.e. its origin being now <code>container</code>'s origin and not <code>superview</code>'s origin, I have to set update its anchor such that the origin is not at (0,0) but (-x,-y), being x and y the coordinates of <code>container</code>'s origin, such that <code>subview</code> continues being located in relation to <code>superview</code>'s origin. And it seems logical to update this anchor each time that <code>container</code> changes its origin, as this changes the relative position from <code>content</code>'s origin to <code>superview</code>'s origin.</p>
  
  <p>I uploaded code for this - in this case a full iOS project instead of only a playground (I thought initially that it was working and wanted to test using actual gestures). In the actual project I'm working on the transform works better, but I couldn't find the difference. Anyway it doesn't work well, at some point there are always small offsets and the points/crosses get out of sync.</p>
  
  <p><a href="https://i.stack.imgur.com/vRil0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/vRil0.png" alt="enter image description here"></a>
  <a href="https://github.com/i-schuetz/GlobalMatrix/blob/master/GlobalMatrix/ViewController.swift" rel="nofollow noreferrer">Github project</a></p>
  
  <p>Ok, how do I solve this such that all the conditions are met. The crosses have to stay in sync, with continuous zoom/pan and changing the frame of <code>container</code> in between.</p>