Skip to content

Commit

Permalink
Merge pull request #125 from Automattic/fix/114-deselect-color
Browse files Browse the repository at this point in the history
  • Loading branch information
ajlende authored Jul 28, 2020
2 parents b450654 + f7c0136 commit e3cb2f7
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 69 deletions.
83 changes: 54 additions & 29 deletions blocks/waves/src/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { useDispatch, useSelect } from '@wordpress/data';
import { useState, useEffect, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

const { run, parseColor, renderPreview } = window.a8cColorEffects;

const DEFAULT_COLORS = {
color1: '#000',
color2: '#555',
Expand Down Expand Up @@ -129,12 +131,15 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
DEFAULT_COLORS.color4,
};

const renderPreview = ( newAttributes = {} ) =>
window.a8cColorEffects.renderPreview( {
const updatePreview = ( newAttributes = {} ) =>
renderPreview( {
complexity: attributes.complexity,
mouseSpeed: 1,
fluidSpeed: 1,
...colors,
color1: parseColor( colors.color1 ),
color2: parseColor( colors.color2 ),
color3: parseColor( colors.color3 ),
color4: parseColor( colors.color4 ),
...newAttributes,
} );

Expand All @@ -149,7 +154,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {

// Save the initial preview in the attributes
if ( attributes.previewImage === undefined ) {
const previewImage = renderPreview();
const previewImage = updatePreview();
setAttributes( { previewImage } );
}
}, [] );
Expand All @@ -162,10 +167,39 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
backgroundImage: `url( "${ attributes.previewImage }" )`,
};

// To avoid recompiling shaders every frame uniform variables need to be
// mutable so a new reference doesn't have to be passed to run.
const dataset = useRef( {
complexity: attributes.complexity,
mouseSpeed: attributes.mouseSpeed,
fluidSpeed: attributes.fluidSpeed,
color1: parseColor( colors.color1 ),
color2: parseColor( colors.color2 ),
color3: parseColor( colors.color3 ),
color4: parseColor( colors.color4 ),
} );
useEffect( () => {
dataset.current.complexity = attributes.complexity;
dataset.current.mouseSpeed = attributes.mouseSpeed;
dataset.current.fluidSpeed = attributes.fluidSpeed;
dataset.current.color1 = parseColor( colors.color1 );
dataset.current.color2 = parseColor( colors.color2 );
dataset.current.color3 = parseColor( colors.color3 );
dataset.current.color4 = parseColor( colors.color4 );
}, [
attributes.complexity,
attributes.mouseSpeed,
attributes.fluidSpeed,
colors.color1,
colors.color2,
colors.color3,
colors.color4,
] );

const canvasRef = useRef();
useEffect( () => {
return window.a8cColorEffects.run( canvasRef.current );
}, [ canvasRef.current ] );
return run( canvasRef.current, dataset.current );
}, [ canvasRef.current, dataset.current ] );

return (
<>
Expand All @@ -175,7 +209,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
label={ __( 'Complexity', 'waves' ) }
value={ attributes.complexity }
onChange={ ( complexity ) => {
const previewImage = renderPreview( {
const previewImage = updatePreview( {
complexity,
} );
setAttributes( { complexity, previewImage } );
Expand Down Expand Up @@ -209,39 +243,39 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
{
label: __( 'Color 1', 'waves' ),
value: colors.color1,
onChange: ( color1 ) => {
const previewImage = renderPreview( {
color1,
onChange: ( color1 = colors.color1 ) => {
const previewImage = updatePreview( {
color1: parseColor( color1 ),
} );
setAttributes( { color1, previewImage } );
},
},
{
label: __( 'Color 2', 'waves' ),
value: colors.color2,
onChange: ( color2 ) => {
const previewImage = renderPreview( {
color2,
onChange: ( color2 = colors.color2 ) => {
const previewImage = updatePreview( {
color2: parseColor( color2 ),
} );
setAttributes( { color2, previewImage } );
},
},
{
label: __( 'Color 3', 'waves' ),
value: colors.color3,
onChange: ( color3 ) => {
const previewImage = renderPreview( {
color3,
onChange: ( color3 = colors.color3 ) => {
const previewImage = updatePreview( {
color3: parseColor( color3 ),
} );
setAttributes( { color3, previewImage } );
},
},
{
label: __( 'Color 4', 'waves' ),
value: colors.color4,
onChange: ( color4 ) => {
const previewImage = renderPreview( {
color4,
onChange: ( color4 = colors.color4 ) => {
const previewImage = updatePreview( {
color4: parseColor( color4 ),
} );
setAttributes( { color4, previewImage } );
},
Expand Down Expand Up @@ -289,16 +323,7 @@ function Edit( { attributes, className, isSelected, setAttributes } ) {
showHandle={ isSelected }
>
<div className={ className } style={ style }>
<canvas
ref={ canvasRef }
data-complexity={ attributes.complexity }
data-mouse-speed={ attributes.mouseSpeed }
data-fluid-speed={ attributes.fluidSpeed }
data-color1={ colors.color1 }
data-color2={ colors.color2 }
data-color3={ colors.color3 }
data-color4={ colors.color4 }
/>
<canvas ref={ canvasRef } />
<div className={ `${ className }__inner-container` }>
<InnerBlocks
template={ [
Expand Down
133 changes: 93 additions & 40 deletions blocks/waves/waves.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,30 @@
// Export for the editor so it can be run when a block is added.
window.a8cColorEffects = a8cColorEffects;
} else {
const { parseColor, run } = a8cColorEffects;
// Run the effect for all blocks on initial page load.
wp.domReady( () => {
document
.querySelectorAll( '.wp-block-a8c-waves canvas' )
.forEach( a8cColorEffects.run );
.forEach( ( canvas ) => {
const dataset = {
color1: parseColor( canvas.dataset.color1 ),
color2: parseColor( canvas.dataset.color2 ),
color3: parseColor( canvas.dataset.color3 ),
color4: parseColor( canvas.dataset.color4 ),
complexity: Number.parseInt(
canvas.dataset.complexity,
10
),
mouseSpeed: Number.parseFloat(
canvas.dataset.mouseSpeed
),
fluidSpeed: Number.parseFloat(
canvas.dataset.fluidSpeed
),
};
run( canvas, dataset );
} );
} );
}
} )( ( twgl ) => {
Expand Down Expand Up @@ -115,7 +134,7 @@
function inverse( [ x1, x2 ], [ y1, y2 ] ) {
const a = ( x1 * x2 * ( -y1 + y2 ) ) / ( x1 - x2 );
const b = ( x1 * y1 - x2 * y2 ) / ( x1 - x2 );
return function( x ) {
return function ( x ) {
return a / x + b;
};
}
Expand Down Expand Up @@ -157,30 +176,6 @@
textureInfo: twgl.createFramebufferInfo( gl, null, 512, 512 ),
} );

/**
* Convert a hex color string to a WebGL color vector.
*
* @param {string} color Hex color string (#FFFFFF or #FFF)
* @return {number[]} RGB array for WebGL
*/
function parseColor( color ) {
let r = '0';
let g = '0';
let b = '0';

if ( color.length === 7 ) {
r = '0x' + color[ 1 ] + color[ 2 ];
g = '0x' + color[ 3 ] + color[ 4 ];
b = '0x' + color[ 5 ] + color[ 6 ];
} else if ( color.length === 4 ) {
r = '0x' + color[ 1 ] + color[ 1 ];
g = '0x' + color[ 2 ] + color[ 2 ];
b = '0x' + color[ 3 ] + color[ 3 ];
}

return [ r / 0xff, g / 0xff, b / 0xff ];
}

/**
* Draw an individual block.
*
Expand All @@ -193,23 +188,40 @@
renderLiquidEffect( gl, state, program );
}

/**
* The parsed dataset from the canvas.
*
* @typedef {Object} Dataset
* @property {number[]} color1 First color of the gradient.
* @property {number[]} color2 Second color of the gradient.
* @property {number[]} color3 Third color of the gradient.
* @property {number[]} color4 Fourth color of the gradient.
* @property {number} complexity Integer complexity of the animation.
* @property {number} mouseSpeed Float mouse speed of the animation.
* @property {number} fluidSpeed Float fluid speed of the animation.
*/

/**
* Draw the custom gradient to the framebuffer.
*
* @param {WebGLRenderingContext} gl WebGL rendering context
* @param {Object} state Data state for the rendering frame
* @param {Object} program Collection of program info and buffers
* @param {Object} state State for the rendering frame.
* @param {Dataset} state.dataset Dataset to use for rendering.
* @param {Object} program Collection of program info and buffers.
* @param {Object} program.programInfoGradient Gradient program info.
* @param {Object} program.screenBufferInfo Screen buffer info.
* @param {Object} program.textureInfo Texture info.
*/
function renderGradient(
gl,
{ dataset },
{ programInfoGradient, screenBufferInfo, textureInfo }
) {
const uniforms = {
color1: parseColor( dataset.color1 ),
color2: parseColor( dataset.color2 ),
color3: parseColor( dataset.color3 ),
color4: parseColor( dataset.color4 ),
color1: dataset.color1,
color2: dataset.color2,
color3: dataset.color3,
color4: dataset.color4,
};

twgl.bindFramebufferInfo( gl, textureInfo );
Expand All @@ -229,19 +241,23 @@
/**
* Draw the liquid effect to the canvas.
*
* @param {WebGLRenderingContext} gl WebGL rendering context
* @param {Object} state Data state for the rendering frame
* @param {Object} program Collection of program info and buffers
* @param {WebGLRenderingContext} gl WebGL rendering context.
* @param {Object} state Data state for the rendering frame.
* @param {Dataset} state.dataset Dataset to use for rendering.
* @param {number[]} state.mouse Mouse position [ x, y ].
* @param {number} state.time Current program time.
* @param {Object} program Collection of program info and buffers.
* @param {Object} program.programInfoEffectPass Effect pass program info.
* @param {Object} program.screenBufferInfo Screen buffer info.
* @param {Object} program.textureInfo Texture info.
*/
function renderLiquidEffect(
gl,
{ dataset, mouse, time },
{ programInfoEffectPass, screenBufferInfo, textureInfo }
) {
const resolution = [ gl.canvas.width, gl.canvas.height ];
const complexity = Number.parseInt( dataset.complexity, 10 );
const mouseSpeed = Number.parseFloat( dataset.mouseSpeed );
const fluidSpeed = Number.parseFloat( dataset.fluidSpeed );
const { complexity, mouseSpeed, fluidSpeed } = dataset;

const uniforms = {
// Required in the vertex shader to prevent stretching
Expand Down Expand Up @@ -278,6 +294,36 @@
}

return {
/**
* Convert a hex color string to a WebGL color vector.
*
* @param {string} color Hex color string (#FFFFFF or #FFF)
* @return {number[]} RGB array for WebGL
*/
parseColor( color ) {
let r = '0';
let g = '0';
let b = '0';

if ( color.length === 7 ) {
r = '0x' + color[ 1 ] + color[ 2 ];
g = '0x' + color[ 3 ] + color[ 4 ];
b = '0x' + color[ 5 ] + color[ 6 ];
} else if ( color.length === 4 ) {
r = '0x' + color[ 1 ] + color[ 1 ];
g = '0x' + color[ 2 ] + color[ 2 ];
b = '0x' + color[ 3 ] + color[ 3 ];
}

return [ r / 0xff, g / 0xff, b / 0xff ];
},

/**
* Render a 512x512 px frame of the animation to use as a preview.
*
* @param {Dataset} dataset Dataset to use for rendering.
* @return {string} Data URI of a rendered frame.
*/
renderPreview( dataset ) {
const canvas = document.createElement( 'canvas' );
canvas.width = canvas.height = '512';
Expand All @@ -296,7 +342,14 @@

return gl.canvas.toDataURL();
},
run( canvas ) {

/**
* Runs the animation.
*
* @param {HTMLCanvasElement} canvas Canvas to draw on.
* @param {Dataset} dataset Reference to a parsed dataset.
*/
run( canvas, dataset ) {
const shouldAnimate = ! window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
Expand All @@ -315,7 +368,7 @@
const program = init( gl );

const state = {
dataset: canvas.dataset,
dataset,
mouse: [ 0, 0 ],
time: window.performance.now(),
rafId: 0,
Expand Down

0 comments on commit e3cb2f7

Please sign in to comment.