{"id":16906554,"url":"https://github.com/rsms/uilayer","last_synced_at":"2025-03-17T07:30:34.434Z","repository":{"id":1753907,"uuid":"2580900","full_name":"rsms/uilayer","owner":"rsms","description":"CALayer-style API for building rich, high-performance UI graphics in WebKit","archived":false,"fork":false,"pushed_at":"2021-08-21T19:45:24.000Z","size":331,"stargazers_count":194,"open_issues_count":3,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-15T21:17:06.690Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://rsms.me/uilayer/","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rsms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-10-15T08:03:58.000Z","updated_at":"2024-12-04T15:20:05.000Z","dependencies_parsed_at":"2022-07-20T06:47:09.181Z","dependency_job_id":null,"html_url":"https://github.com/rsms/uilayer","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Fuilayer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Fuilayer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Fuilayer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Fuilayer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rsms","download_url":"https://codeload.github.com/rsms/uilayer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243847878,"owners_count":20357459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T18:43:14.439Z","updated_at":"2025-03-17T07:30:34.087Z","avatar_url":"https://github.com/rsms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UILayer\n\nUILayer provides a JavaScript API on top of WebKit **for working with the concept of layers**. Instead of manipulating DOM elements using a myriad of mixed concepts, you go though a single, well defined API.\n\n\n## Demo and example\n\n- [Psychotic layers randomly moving around](examples/animate-combo.html)\n- [Flip some pages in the Flip Book](examples/flip-book.html)\n- [Interactive 3D perspective](examples/perspective.html)\n- [More examples...](examples/)\n\n\u003e Note: UILayer only works in WebKit-based environments, such as web views on Apple iOS, OS X and Android or in web browsers like Google Chrome and Safari.\n\nHere's a simple example: A layer inside another layer which moves 50px to the right when touched, rotating the inner layer like a wheel:\n\n\u003cdiv\u003e\n\u003cpre class=\"plain-text\"\u003e\u003ccode\u003elayer1 = \u003ca href=\"#api\"\u003eUILayer\u003c/a\u003e({ x:10, y:10, width:300, height:300, \u003ca href=\"#animation\"\u003eanimated\u003c/a\u003e:true });\nlayer2 = \u003ca href=\"#api\"\u003eUILayer\u003c/a\u003e({ x:50, y:50, width:200, height:200, \u003ca href=\"#animation\"\u003eanimated\u003c/a\u003e:true });\nlayer1.\u003ca href=\"#layer-hierarchy\"\u003eaddSublayer\u003c/a\u003e(layer2);\nlayer1.\u003ca href=\"#style-attributes\"\u003ebackgroundColor\u003c/a\u003e = 'salmon'\nlayer1.\u003ca href=\"#handling-events\"\u003eon('touchstart'\u003c/a\u003e, function () {\n  layer1.\u003ca href=\"#geometry\"\u003eframe\u003c/a\u003e.x += 50\n  layer2.\u003ca href=\"#geometry\"\u003erotation.z\u003c/a\u003e += 20\n});\ndocument.body.appendChild(layer1.\u003ca href=\"#dom\"\u003eelement\u003c/a\u003e)\u003c/code\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\n[Try it (written in Move) →](examples/example1.html)\u003cbr\u003e\n[Try it (written in JavaScript) →](examples/example1-javascript.html)\n\n## Usage\n\nIf you use [Move](https://github.com/rsms/move/), either use the precompiled [uilayer.js](https://raw.github.com/rsms/uilayer/master/uilayer.js) or use the Move source files in the \"src\" directory directly.\n\nIf you don't use Move, use [uilayer-standalone.js](https://raw.github.com/rsms/uilayer/master/uilayer-standalone.js) JavaScript library.\n\n    \u003cscript src=\"https://raw.github.com/rsms/uilayer/master/uilayer-standalone.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n    var UILayer = Move.require('UILayer');\n    ...\n    \u003c/script\u003e\n\nYou can also build a JavaScript library from the source files (requires [move](https://github.com/rsms/move/) \u003e=0.4.4):\n\n    move compile -d src -o uilayer.js\n\n\n# API\n\n### UILayer(x, y, z, width, height, scale, frame, element, animated, style, sublayers, ..) → layer\n\nCreate a new UILayer with optional initial properties.\n\n\n## Geometry\n\n### layer.frame ⇄ UIFrame {x:number, y:number, z:number, width:number, height:number}\n\nThe position and size of the layer in the coordinate space of its parent layer.\n\nThe returned `UIFrame` object is a mutable proxy which when modified affects the layer. That is you can do `layer.frame.x = 10` to move the layer to x position 10, rather than `frame = layer.frame; frame.x = 10; layer.frame = frame`.\n\nProviding a width and/or height of 0 (zero) makes the layer span the width and/or height of it's parent.\n\n\n### layer.anchor ⇄ object | string\n\nLayer anchor defined in superlayer coordinates controls which edges of the superlayer the layer is attached to, or originates from. Defaults to `{top:0, left:0}`.\n\nThis property always returns an object (never a string) which might contain any or none of the following values:\n\n    { top:number|string, right::number|string,\n      bottom:number|string, left:number|string}\n\nIf a value is undefined, that edge is not part of the layers anchor.\n\nExample of having a layer originating from the bottom right corner of its superview:\n\n    layer.anchor = 'bottom right'\n    print layer.anchor  # -\u003e { bottom: 0, right: 0 }\n\nExample of having a layer originating from the bottom right corner of its superview with an offset of 20 pixels:\n\n    layer.anchor = {bottom:20, right:20}\n    print layer.anchor  # -\u003e { bottom: 20, right: 0 }\n\nExample of making a layer span the entire width of its superlayer, automatically being resized as the superlayer's frame size changes (note that we do not specify a frame size):\n\n    layer = UILayer {anchor:'top right bottom left'}\n\nExample of creating a layer that spans the width of its superlayer, attached to the bottom:\n\n    layer = UILayer {anchor:'left bottom right', height:100}\n\nExample: [examples/anchor.html](examples/anchor.html)\n\n\n### layer.moveBy(x, y:0, z:0)\n\nModify position of the layer.\n\n### layer.rotation ⇄ Rotation {x:number, y:number, z:number}\n\nRotation of the layer. Defaults to `{x:0, y:0, z:0}`. The returned object is a proxy, meaning it's possible to manipulate the values directly (e.g. `layer.rotation.x = 45`). Angles are expressed in degrees (0-360).\n\nWhen setting this value (rather than manipulating the returned proxy object), you only need to pass the values which you would like to modify. There's also a single [\"change:rotation\"](#change-rotation-oldvalues-x-y-z-) event emitted, rather than one even per axis, as implied by manipulating the proxy object.\n\nExample of rotating a layer around its Z-axis (spinning like a wheel):\n\n    layer.rotation.z = 45\n\nExample of setting several axis, causing a single change event to be emitted:\n\n    layer.rotation = {x:20, z:45}\n\nExample: [examples/rotation.html](examples/rotation.html)\n\n\n### layer.scale ⇄ number (0-inf]\n\nScale of the layer. Defaults to 1.0 (100%).\n\n\n### layer.scaleBy(x, y:0, z:0)\n\nModify scale of the layer.\n\n\n### layer.transformOrigin ⇄ [x, y, z]\n\nDefines the transformation origin of the layer's bounds rectangle. Affects how transformations like scale and rotation behaves. Animatable.\n\nDescribed in the unit coordinate space. Defaults to (0.5, 0.5, 0), the center of the bounds rectangle.\n\nExample: [examples/transformOrigin.html](examples/transformOrigin.html)\n\n\n### layer.zPosition ⇄ number\n\nLayers with a larger zPosition will be placed in front of those with a smaller one. Defaults to 0.\n\n\n## Style attributes\n\n### UILayer.debug ⇄ bool\n\nIf set to true, new layers will be assigned a random semi-opaque background color, aiding in development. Defaults to false.\n\nExample: [examples/debug.html](examples/debug.html)\n\n### layer.doubleSided ⇄ bool\n\nDetermines whether the receiver is displayed when facing away from the viewer. Defaults to false.\n\n### layer.cornerRadius ⇄ number\n\nSpecifies a radius used to draw the rounded corners of the receiver’s background. Defaults to 0.\n\nNote: cornerRadius does not affect hit testing.\n\n### layer.backgroundColor ⇄ string\n\nThe background color of the layer. Defaults to \"transparent\" (no background color).\n\nAccepts any [CSS 3 color value](http://www.w3.org/TR/css3-color/) as a string, including:\n\n- [`\"#000000-#ffffff\"` or `\"#000-#fff\"`](http://www.w3.org/TR/css3-color/#numerical)\n- [`\"rgb(0-255, 0-255, 0-255)\"`](http://www.w3.org/TR/css3-color/#rgb-color)\n- [`\"rgba(0-255, 0-255, 0-255, 0-1)\"`](http://www.w3.org/TR/css3-color/#rgba-color)\n- [`\"hsl(0-359, 0-100%, 0-100%)\"`](http://www.w3.org/TR/css3-color/#hsl-color)\n- [`\"hsl(0-359, 0-100%, 0-100%, 0-1)\"`](http://www.w3.org/TR/css3-color/#hsla-color)\n- [`\"red\"`, `\"salmon\"`, `\"transparent\"`, ...](http://www.w3.org/TR/css3-color/#svg-color)\n\nAlso accepts (but will canonicalize) arrays of relative RGBA values:\n\n- R, G, B, A -- `[0-1, 0-1, 0-1, 0-1]`\n- R, G, B -- `[0-1, 0-1, 0-1]`\n- RGB, A -- `[0-1, 0-1]`\n- RGB -- `[0-1]`\n\n### layer.color ⇄ string\n\nForeground (text) color of the layer. Defaults to the inherited value (from the environment, i.e. default browser style or host website style).\n\nAccepts any [CSS 3 color value](http://www.w3.org/TR/css3-color/) as a string. See description of [`layer.backgroundColor`](#layer.backgroundcolor-string) for more information.\n\n### layer.opacity ⇄ number [0-1]\n\nOpacity of the layer. Defaults to 1 (fully opaque).\n\n\n### layer.hidden ⇄ bool\n\nHide or show the layer. Defaults to false.\n\nA hidden view disappears from its window and does not receive input events. It remains in its superview’s list of sublayers, however, and participates in autoresizing as usual. Hiding a view with sublayers has the effect of hiding those sublayers and any view descendants they might have. This effect is implicit and does not alter the hidden state of the receiver’s descendants.\n\nIf you want to know if a layer is in a DOM tree (no matter if it's visible), see [`layer.document`](#layer.document-htmldocument).\n\n### layer.computedStyle → Style\n\nReturns a style object defining the layers computed style (equivalent to `window.computedStyle` for an element).\n\n### layer.style ⇄ Style\n\nThe explicit (CSS) style of the layer.\n\n\n### layer.masksToBounds ⇄ bool\n\nDetermines whether sublayers are confined to the bounds of the receiver. Defaults to false.\n\nSetting this value to true causes sublayers to be clipped to the bounds of the receiver. If set to false, sublayers whose frames extend beyond the visible bounds of the receiver are not clipped.\n\nExample: [examples/masksToBounds.html](examples/masksToBounds.html)\n\n\n### layer.perspective ⇄ number\n\nUsed to give an illusion of depth; it determines how layers change size based on their z-offset from the z=0 plane. You can think of it as though you're looking at the page from a distance p away. Layers on the z=0 plane appear in their normal size. Something at a z offset of p/2 (halfway between the viewer and the z=0 plane) will look twice as big, and something at a z offset of -p will look half as big. Thus, large values give a little foreshortening effect, and small values lots of foreshortening. Values between 500 and 1000 give a reasonable-looking result for most content.\n\nDefaults to \"none\" (i.e. \"no perspective\" or \"orthographic projection\").\n\nThe default origin for the perspective effect is the center of the layer, but you can control this with [`perspectiveOrigin`](#layer.hidden-bool).\n\nExample: [examples/perspective.html](examples/perspective.html)\n\n\n### layer.perspectiveOrigin ⇄ [x, y, z]\n\nPerspective origin. Defaults to `[0.5, 0.5, 0]`.\n\n\n### layer.preserve3d ⇄ bool\n\nWhen set to false (the default value), transformed sublayers are flattened into the plane of their superlayer (think of the 3D transform as simply a painting effect). However, when setting this to true, the layer to which it is assigned does not flatten its sublayers into it; instead, those sublayers live in a shared 3D space with the superlayer.\n\n\n## Animation\n\n### layer.animated ⇄ bool | string\n\nAnimate property changes. Defaults to false.\n\nThe value `true` indicates all properties should be animated. A string value signifies only a subset of properties should be animated. For instance:\n\n- \"all\" -- animate all properties. Equivalent to `true`\n- \"geometry\" -- animate changes to geometry\n- \"opacity\" -- animate changes to opacity\n\nYou can define a list of CSS properties to be animated by separating them with a comma. E.g. a value of `\"width, height, opacity\"` would cause frame size and opacity to be animated, but not scale, position, etc.\n\nExample:\n\n    layer = UILayer {x:0, y:0, width:100, height:100}\n    layer.animated = true\n    layer.on 'touchstart', ^{ layer.frame.x += 100 }\n    # Layer moves 100 px to the right during 500ms when touched\n\n\n### layer.animationDuration ⇄ number (0-inf]\n\nDuration in milliseconds of animations implied by changing properties. Only effective if `layer.animated` is set to true.\n\nExample:\n\n    layer = UILayer {x:0, y:0, width:100, height:100}\n    layer.animated = true\n    layer.animationDuration = 200\n    layer.on 'touchstart', ^{ layer.frame.x += 100 }\n    # Layer moves 100 px to the right during 200ms when touched\n\n\n### layer.animationTimingFunction ⇄ string\n\nAvailable timing functions:\n\n- `\"linear\"` – The linear function just returns as its output the input that it received.\n- `\"ease\"` – The default function, ease, is equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0).\n- `\"ease-in\"` – The ease-in function is equivalent to cubic-bezier(0.42, 0, 1.0, 1.0).\n- `\"ease-out\"` – The ease-out function is equivalent to cubic-bezier(0, 0, 0.58, 1.0).\n- `\"ease-in-out\"` – The ease-in-out function is equivalent to cubic-bezier(0.42, 0, 0.58, 1.0)\n- `\"cubic-bezier(x1, y1, x2, y2)\"` – Specifies a cubic-bezier curve whose P0 and P3 points are (0,0) and (1,1) respectively. The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2).\n\nExample:\n\n    layer = UILayer {x:0, y:0, width:100, height:100}\n    layer.animated = true\n    layer.animationTimingFunction = 'ease-out'\n    layer.frame.x = 100\n    # Layer moves 100 px to the right during 500ms,\n    # slowing down in the end\n\n\n\n\n## Custom drawing\n\n### layer.drawContent ⇄ ^{...}\n\nProvide a function to perform custom drawing of the layer's content. This function will be invoked every time the frame size changes or the layer is added to the DOM.\n\n\u003e Note: A layer that implements custom drawing can not have sublayers.\n\nExample of drawing a triangle:\n\n    layer = UILayer {width:300, height:300, drawContent:^{\n      g = @graphicsContext2D\n      g.strokeStyle = 'red'\n      g.moveTo 50,50\n      g.lineTo 250,50\n      g.lineTo 150,250\n      g.lineTo 50,50\n      g.stroke()\n    }}\n\nExample: [examples/drawContent.html](examples/drawContent.html)\n\n\n### layer.graphicsContext2D → CanvasRenderingContext2D\n\nThe 2D drawing context for a layer with a `drawContent` implementation.\n\nSee [HTML Canvas 2D Context](http://www.w3.org/TR/2dcontext/) for reference.\n\n### layer.graphicsContext3D → CanvasRenderingContext3D\n\nThe 3D (WebGL) drawing context for a layer with a `drawContent` implementation.\n\nSee [WebGL Specification](http://www.khronos.org/registry/webgl/specs/latest/) for reference.\n\n\n## Layer hierarchy\n\n### layer.superlayer → layer\n\nParent layer.\n\n\n### layer.sublayers → [layer, ..]\n\nA list of all sublayers (other layers that are owned by, or live within, the layer).\n\n\n### layer.firstSublayer → layer\n\nFirst sublayer (equivalent to `layer.sublayers[0]` but better performing in cases where a layer have many sublayers).\n\n\n### layer.addSublayer(layer:sublayer) → sublayer\n\nAdd a layer as a sublayer to the receiving layer. Returns the same sublayer that was passed as input.\n\n\n### layer.removeSublayer(layer:sublayer, index:number) → sublayer\n\nRemove a sublayer by reference or index. Returns the sublayer removed or undefined if no matching sublayer was found.\n\n\n### layer.removeAllSublayers() → [layer, ..]\n\nRemove all sublayers. Returns the layers that was removed.\n\n\n### layer.removeFromSuperlayer()\n\nRemoves the layer from the superlayer.\n\n\n### layer.isSublayerOf(layer:superlayer) → bool\n\nTest if a layer is a sublayer of another layer.\n\n\n## Hit testing\n\n### UILayer.hitTest(x, y) → layer\n\nReturns the farthest descendant of the layer hierarchy that contains a specified point.\n\nExample: [examples/hitTest.html](examples/hitTest.html)\n\n### layer.excludedFromHitTesting ⇄ bool\n\nControls whether the layer is included in hit testing. Defaults to true. Setting this to false causes the layer to stop accepting user input -- such as touches and clicks -- and also being ignored by `UILayer.hitTest`.\n\n\n## DOM\n\n### layer.element → HTMLElement\n\nThe DOM node which is used to represent the layer in the document. Can be assigned during creation, but not later.\n\n\n### layer.ownerDocument → HTMLDocument\n\nThe DOM document which this layer is owned by (created by). Note that a layer always have a ownerDocument, even if it's not in a DOM tree.\n\n\n### layer.document → HTMLDocument\n\nThe DOM document which this layer is currently presented in, if any. You can use this to test if the layer is part of the DOM tree or not.\n\nIf you just want to know if a layer is visible or not, see [`layer.hidden`](#layer.hidden-bool).\n\n\n## Handling events\n\n### layer.on(type:string, handler:^(event)) → handler\n\nRegister *handler* to be triggered each time *event* is emitted on the receiving layer. *type* can be any string, including [DOM Level 3 events](http://www.w3.org/TR/DOM-Level-3-Events/) and custom, arbitrary events.\n\n### layer.removeEventListener(type:string, handler:^(event)) → bool\n\nRemove an event handler.\n\n### layer.emit(type, bubbles:true, cancelable:true, ...) → bool\n### layer.emit(type, {bubbles:true, cancelable:true, ...}) → bool\n\nEmit (or: trigger/raise/send) an event on the receiving layer.\n\n*type* can be any string, including [DOM Level 3 events](http://www.w3.org/TR/DOM-Level-3-Events/) and custom, arbitrary events. All arguments or options (in positional call-style) except \"type\" will be added to the event object that is then sent to all listening event handlers.\n\nExample:\n\n    layer.on 'my-custom-event', ^(ev) {\n      print 'my-custom-event triggered with foo:', ev.foo\n    }\n    layer.emit 'my-custom-event', { foo:'Hello' }\n\n\n\n## Performance and edge-cases\n\n\n### layer.is3DBacked → bool\n\nIndicates whether the layer is backed by high-performance 3D rendering or not.\n\n\n## Identifying the layer at runtime\n\n### layer.tag ⇄ string\n\nAssign a document-wide unique tag to this layer. This will effectively set `id=\"tag\"` on the underlying element.\n\nExample: [examples/tag.html](examples/tag.html)\n\n### UILayer.layerWithTag(tag:string) → layer\n\nFind a layer anywhere in the document which has the specified tag.\n\n\n\n## Events\n\nA layer can emit any DOM Level 3 Events as well as arbitrary, user-defined events. Listed below are the UILayer-specific events.\n\n### uilayer:added-to-superlayer {superlayer:UILayer}\n\nThe receiving layer was added as a sublayer to another layer (superlayer).\n\n### uilayer:removed-from-superlayer {superlayer:UILayer}\n\nThe receiving layer was removed from a layer (superlayer).\n\n### uilayer:added-sublayer {sublayer:UILayer}\n\nA sublayer was added to the receiving layer.\n\n### uilayer:removed-sublayer {sublayer:UILayer}\n\nA sublayer was removed from the receiving layer.\n\n### change:frame {oldValues:{x:, y:, z:, width:, height:}}\n\nEmitted when `layer.rotation` changed. The oldValues object contains the old values of changes properties.\n\n### change:rotation {oldValues:{x:, y:, z:}}\n\nEmitted when `layer.rotation` changed. The oldValues object contains the old values of changes properties.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsms%2Fuilayer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frsms%2Fuilayer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsms%2Fuilayer/lists"}