CALayer with NSScrollView, zooming panning and clicking


I have a CALayer hosting view, which I would like to be able to zoom, scroll around and click in. If I embed it in a scrollview, the scrolling works fine, but zooming causes the contents to fly away everywhere. If I don't embed it in a scrollview, I can get the zooming working nicely using CATransform3DMakeScale, but then I have problems with panning, and being able to select objects.

What would be the recommended way to approach this - before I try and work it out with the wrong option.

(If you have any source that does a similar thing, I would be very grateful to see it.)


I got inspired here at Apple sample codes

Also look at the Optimizing Drawing and Scrolling on OS X WWDC 2013 video

The CALayer embedded in ScrollView flown because the ScrollView wasn't the Core Animation layer (ScrollView.wantsLayer = true). Interface Builder

Here example in Swift:

class AppDelegate: NSObject, NSApplicationDelegate {
    var win: NSWindow!

    func applicationDidFinishLaunching(aNotification: NSNotification) {

        win = NSWindow(contentRect: NSRect(x: 200, y: 200, width: 500, height: 500),
            styleMask: NSTitledWindowMask,
            backing: NSBackingStoreType.Buffered,
            defer: false)


        let scrollView = NSScrollView()
        scrollView.allowsMagnification = true
        scrollView.hasHorizontalScroller = true
        scrollView.hasVerticalScroller = true
        scrollView.wantsLayer = true

        scrollView.contentView = CenteredClipView()
        scrollView.documentView = MyView()
        scrollView.backgroundColor = NSColor.controlColor()

        win.contentView = scrollView

class MyView: NSView {
    var drawn = false

    override func updateLayer() {

        if !drawn {
            drawn = true

            frame = (superview! as NSView).frame

            var shape = CAShapeLayer()
            let p = CGPathCreateMutable()
            CGPathAddEllipseInRect(p, nil, frame)
            CGPathMoveToPoint(p, nil, bounds.maxX, 0)
            CGPathAddLineToPoint(p, nil, 0, bounds.maxY)
            shape.path = p
            shape.lineWidth = 5
            shape.fillColor = NSColor.whiteColor().CGColor
            shape.strokeColor = NSColor.selectedControlColor().CGColor
            shape.lineDashPattern = [5, 5]

            let ant = CABasicAnimation(keyPath: "lineDashPhase")
            ant.fromValue = 0
            ant.toValue = 1000000
            ant.duration = 10000
            ant.repeatCount = 10000
            shape.addAnimation(ant, forKey: "lineDashPhase")


class CenteredClipView: NSClipView {
    override func constrainBoundsRect(proposedBounds: NSRect) -> NSRect {
        var rect = super.constrainBoundsRect(proposedBounds)

        if let containerView = documentView? as? NSView {
            if rect.size.width > containerView.frame.size.width {
                rect.origin.x = (containerView.frame.width - rect.width ) / 2

            if rect.size.height > containerView.frame.size.height {
                rect.origin.y = (containerView.frame.height - rect.height ) / 2

        return rect

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at


Login to comment


Saving edited image after zooming, rotating and panning

How to stop ScrollView from scrolling when panning/zooming on a MapBox view?

SciChart - zooming and panning from code in MVVM

Zooming and panning an image in a QScrollArea

Zooming and Panning in JS/JQuery like we can do it using SVG

Best practice for zooming and panning HTML5 canvas with > 10k objects

D3: Zooming/Panning Line Graph in SVG is not working in Canvas

D3 Canvas graph zooming and panning slow redraw in Webview

d3 how to tie text to top right corner of view port while zooming and panning

How to check if my Cytoscape.js graph is out of view (even partially) after panning and/or zooming?

Constraining zooming and panning in a D3 map viewport

R Shiny: googleway package - turn off auto zooming and panning during update

How do I intercept mapview panning and zooming (Swift 4)

amCharts 4 - How to Disable Scrollbar to Prevent Zooming and Panning

How can I detect panning and zooming by the user with d3 zoomBehavior?

d3js zooming in one direction, panning in both directions

Zooming with mouse wheel breaks panning (scrolling) of real time data in ZedGraph

Is there a Google Map event listener for panning or zooming map?

D3.js zooming and panning - lock on y axis

Having trouble panning and zooming on my d3 map

zooming and panning with buttons in android emulator

Flot zooming and panning with logarithmic axis

d3 v2 Prevent Zooming and Panning Chart Outside Viewport

Apply panning and zooming on inline SVG

Zooming and panning TextureView

Background image not zooming and panning with SVG

How to Implement linked zooming, panning in bokeh plots when embedded as Components

How to do panning/zooming operation in directx/c++

Shared matplotlib axes for images with different sizes (Linked zooming and panning)