Last active
July 19, 2018 20:16
-
-
Save appsforartists/e5d2a4b7826bf5962fad142bcd255465 to your computer and use it in GitHub Desktop.
Snippets showing how to use -webkit-canvas to make a paint worklet work in Safari
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @license | |
* Copyright 2016 - 2017 Google LLC. All Rights Reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
* use this file except in compliance with the License. You may obtain a copy | |
* of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
* License for the specific language governing permissions and limitations | |
* under the License. | |
*/ | |
import { | |
CSSProperty, | |
myPainter, | |
inputProperties, | |
} from './myPainter.mjs'; | |
// We have an element whose background is either the Paint Worklet or | |
// -webkit-canvas. | |
setPainter = (element: HTMLElement) => { | |
if (element) { | |
this.element = element; | |
element.style.setProperty('background-image', 'paint(my-worklet-name)'); | |
if (typeof paintWorklet === 'undefined' && document.getCSSCanvasContext) { | |
// TODO: update the dimensions on resize | |
this.dimensions = { | |
width: element.clientWidth, | |
height: element.clientHeight, | |
}; | |
this.webkitCanvas = document.getCSSCanvasContext( | |
'2d', | |
'my-worklet-name', | |
devicePixelRatio * this.dimensions.width, | |
devicePixelRatio * this.dimensions.height, | |
); | |
this.webkitCanvas.scale(devicePixelRatio, devicePixelRatio); | |
element.style.setProperty('background', '-webkit-canvas(my-worklet-name)'); | |
// ensure the canvas dimensions match the element dimensions: | |
element.style.setProperty('background-size', 'contain'); | |
this.repaint(); | |
} | |
} | |
} | |
repaint() { | |
if (this.webkitCanvas) { | |
// Our painter has the same API as a Paint Worklet. We just pass it our | |
// -webkit-canvas instead of the one we'd get from the worklet. | |
myPainter( | |
this.webkitCanvas, | |
this.dimensions, | |
styleMapFromElement(inputProperties, this.element) | |
); | |
} | |
} | |
// We put our painted element inside a container, where we set custom | |
// properties. In a React component, this happens inside | |
// `componentWillReceiveProps`. | |
// | |
// Note: | |
// -webkit-canvas doesn't automatically repaint when the properties change, | |
// so you have to manually repaint whenever you want an update: | |
componentWillReceiveProps({ someProperty = 16 }: Props) { | |
this.containerElement.style.setProperty(CSSProperty.SOME_PROPERTY, someProperty + 'px'); | |
this.repaint(); | |
} | |
declare interface CSSStyleValue { | |
cssText: string, | |
} | |
/** | |
* This is just a quick snippet to provide the painter with the same API that it | |
* would get from the worklet. | |
* | |
* Note: it allocates a new Map and Array every call, as well as reading a bunch | |
* of style properties - it probably isn't as performant as it should be. | |
*/ | |
export function styleMapFromElement(inputProperties: Array<string>, element: HTMLElement): Map<string, CSSStyleValue> { | |
const style = getComputedStyle(element); | |
return new Map( | |
Array.from( | |
inputProperties, | |
key => [ | |
key, | |
style.getPropertyValue(key) | |
] | |
) as Array<[string, CSSStyleValue]> | |
); | |
} | |
export default styleMapFromElement; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @license | |
* Copyright 2016 - 2017 Google LLC. All Rights Reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
* use this file except in compliance with the License. You may obtain a copy | |
* of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
* License for the specific language governing permissions and limitations | |
* under the License. | |
*/ | |
// List all the custom properties that you want as inputs to your painter | |
// here. | |
export const CSSProperty = { | |
SOME_PROPERTY: '--some-property', | |
}; | |
export const inputProperties = Object.values(CSSProperty); | |
// Notice that this API has the same shape as a paint worklet. myWorklet | |
// passes its arguments straight through. MyComponent calls this function | |
// to repaint the -webkit-canvas when it goes stale. | |
export function myPainter(context, dimensions, styleMap) { | |
// ... paint stuff | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @license | |
* Copyright 2016 - 2017 Google LLC. All Rights Reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
* use this file except in compliance with the License. You may obtain a copy | |
* of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
* License for the specific language governing permissions and limitations | |
* under the License. | |
*/ | |
import { | |
myPainter, | |
inputProperties, | |
} from './myPainter.mjs'; | |
// This is a very simple shim that passes its argument as-is to our paint | |
// function | |
registerPaint( | |
'my-worklet-name', | |
class { | |
static get inputProperties() { | |
return inputProperties; | |
} | |
paint(context, dimensions, styleMap) { | |
myPainter(context, dimensions, styleMap); | |
} | |
} | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment