Git Product home page Git Product logo

Comments (28)

Swatto avatar Swatto commented on June 12, 2024

Not only shape: the support of rectangle and ellipse could make react-canvas very usefull.

from react-canvas.

zoomclub avatar zoomclub commented on June 12, 2024

Good integration between opentype.js and react-canvas would be great!

http://nodebox.github.io/opentype.js/

Being able to use the latest Canvas2D features would be fantastic!

https://hacks.mozilla.org/2015/01/canvas-2d-new-docs-path2d-hit-regions/

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

I am currently experimenting this in a performant way (shape and rect + circle) with react-canvas, it is very experimental and most likely will be pushed mid-week as a POC on my fork.

Though using a shape is already possible using a different canvas to render the stuff and then cache and use it as an image via data uri's but its not gonna cut i there is a decent high number of objects requiring dynamic re-draws.

Use - cases :

  1. Placeholders transitioning into values.
  2. ICON's and shapes built using rasterization of an svg path will be both performant and device independant.
  3. Animations with complex shapes like circle transitions etc
  4. Material Design style animations like a breeze.

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

Instead of adding more primitive I think that a simpler and more efficient solution would be to let us access to a draw function, here we can see that react canvas use customDrawFunction for image and text, letting us use our custom drawFunction would make it easy to implement all sort of primitive and avoid creating tons of element for complex drawing that does not need to take advantage of the event handler.

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

I have create a basic version here https://github.com/fdecampredon/react-canvas/tree/draw-api I'll experiment a bit more with that when I'll have time to do so.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

+1 @fdecampredon

I am using similar technique in my experiment but bundling more primitives as for path and commons. This can be common code and then primitives can be bundled :-)

exposing the draw theoretically allows paths for 3rd party canvas libs to tap in ( say for charts )

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

@mjohnston would you be interested by this approach for a PR if I work a bit more on that one ?

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

+1 from me.

from react-canvas.

mjohnston avatar mjohnston commented on June 12, 2024

@fdecampredon I really like the idea of making the drawing engine more extensible. Would love to see a PR! Direction you're heading looks like a good one.

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

Nice, ok so just a few questions.

The drawBaseRenderLayer function

Firstly I think the fact that the DrawingUtils has a default draw function drawBaseRenderLayer for all elements is problematic when it comes to custom layer.
For example, in my Circle example I would like to use some styles like backgroundColor or borderColor to draw the circle instead of having them used in the default draw mechanism.

For that matter I think about 3 solutions :

  1. Do nothing. People should use different style names for custom drawing.
  2. Injecting a boolean property on the layer 'doNotUseDefaultDraw' and preventing DrawingUtils from calling drawBaseRenderLayer when the layer has this property set to true.
  3. Making each component injects their draw function on the layer and only use this draw function in DrawingUtils. For example Layer would inject drawBaseRenderLayer on the underlying renderLayer, Image would inject drawImageRenderLayer and we would move the call to drawBaseRenderLayer in drawImageRenderLayer etc..

I guess that you understood I personally prefer solution 3), but I would like to have your opinion here because it would need some little refactoring.

Custom layer spec

In my example createCustomLayer is just a wrapper on top of createComponent that injects the draw function. That's perhaps a bit too simplistic, there are 3 other things the user might want to override :

  • The user might want to mark the component as 'cacheable'.
  • The user might want to mark the component as 'containingImage'.
  • The user might want to mark the component as 'containingFontFace'.

Perhaps something like :

createCustomLayer('Circle', {
  cacheable: false, // false default
  containsFont: false, // false default
  containingImage: false, // false default,
  draw: function (...) {
  }
});

Also I have some problems with the draw function signature itself.
In my example, I chose (ctx, props, x, y, width, height) => void.
I didn't want to expose the renderLayer itself to the component but I don't know if it's a good idea. Especially in the solution 3) case, that function should have the same signature than other draw functions, but that involves letting the user inject custom props to the renderLayer.

Finally here is a full example of what I have in mind:

var ReactCanvas = require('react-canvas');

var Circle = ReactCanvas.createCanvasComponent({
  displayName: 'Circle',
  cacheable: false, // false default
  containsFont: false, // false default
  containingImage: false, // false default,

  applyProps(prevProps, props, layer) {
    //inject dummy style if needed
  },

  draw(ctx, layer) {
    var {x, y, width, height} = layer.frame;
    var centerX = x + width / 2;
    var centerY = y + height / 2;

    var fillColor = layer.backgroundColor || '#FFF';
    var strokeColor = layer.borderColor || '#FFF';
    var strokeWidth = layer.borderWidth || 0;

    var radius = Math.min(width / 2, height / 2) - Math.ceil(strokeWidth / 2);

    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = fillColor;
    ctx.fill();
    ctx.lineWidth = strokeWidth;
    ctx.strokeStyle = strokeColor;
    ctx.stroke();
  }
});

We could also expose a base class since it's the React 0.13 way :

var ReactCanvas = require('react-canvas');

class Circle extends ReactCanvas.Component {

  constructor(props) {
    super(props);
    this.cacheable = false;
    ...
  }

  applyProps(prevProps, props, layer) {
    //inject dummy style if needed
  }

  draw(ctx, layer) {
    var {x, y, width, height} = layer.frame;
    var centerX = x + width / 2;
    var centerY = y + height / 2;

    var fillColor = layer.backgroundColor || '#FFF';
    var strokeColor = layer.borderColor || '#FFF';
    var strokeWidth = layer.borderWidth || 0;

    var radius = Math.min(width / 2, height / 2) - Math.ceil(strokeWidth / 2);

    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = fillColor;
    ctx.fill();
    ctx.lineWidth = strokeWidth;
    ctx.strokeStyle = strokeColor;
    ctx.stroke();
  }
}

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

@fdecampredon

:Updated:

How I have done it so far was to have 2 seperate classes exposed to the 3rd party.

  1. CanvasLayer, Lower level API which is accepted by the renderer and draws nothing ! the user can draw anything.
  2. BaseCanvasLayer, A higher level API which does the task of base canvas layer like drawing borders and so on.
import {CanvasLayer, BaseCanvasLayer} from 'react-canvas';

class Circle extends CanvasLayer{
    constructor(){  /* do some cool stuff */ }
    draw(ctx, layer){
        /* use the lower level api awesomeness */
    }
}

// maybe i should rename the exposed classes
class FrostBlurStyleLayer extends BaseCanvasLayer{
     constructor(){ /* do aweosmeness */
     draw(ctx, layer){
        /* do aweosmeness, this layer actually performs frost blur by taking image data */
     }
}

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

@darkyen have you seen the PR #46 that I sent ? I changed a bit my way of doing things and tryed to mimic the way things work actually, in that PR I have 2 new top level method :

  • registerLayerType that allows yo register a custom render layer type associated to a custom draw function draw a function :
ReactCanvas.registerLayerType('circle', function (ctx, layer) {
  //draw a circle
});
  • createCanvasComponent that allow to create a new Layer-like by associating it to a render layer type and providing a function that will inject properties on the render layer:
var Circle = ReactCanvas.createCanvasComponent({
  layerType: 'circle',
  applyCustomProps(prevProps, props) {
   var layer = this.node;
   layer.myCustomStyleUsedInDraw = props.style.myCustomStyleUsedInDraw;
  }
});

This way we can separate draw api engine extensions from component using them (and so we could imagine having multiple component using the same layer type and associated draw function but injecting different property in the layer).

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

I intended to use the same code for declaring Text and Image components provided by the library. That way it will be the common way for drawing for everyone.

3rd party libraries for Charting and other stuff can just use the same pattern and just by extending a single class.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

My current prototype with Inheritance does something like this

class FrostyBlur extends LayoutLayer {
    draw(ctx){
         super.draw(ctx);
         /* and then get reference to the pixel array and blur */
    }
}

class Circle extends RenderLayer{
     draw(ctx){
         super.draw(ctx);
         /* draw the circle */
         /* super does other tasks here like scaling and opacity and etc */
     }
}

// and the Layoutlayer itself is implemented like  so

class LayoutLayer extends RenderLayer{
     draw(ctx){
        super.draw(ctx);
        /* do all css style border,radius etc rendering here */
     }
}

The drawRenderLayer function then becomes pretty simple.

from react-canvas.

mjohnston avatar mjohnston commented on June 12, 2024

I have mixed feelings about using es6 classes, though that appears to be where things are going. The question of how mixins work in this world is still an open one. Until things settle a bit more I would be in favor of the createClass style, similar to what @fdecampredon is doing with createCanvasComponent (though maybe it would make since to call this createCanvasClass? Or simply ReactCanvas.createClass?)

I imagine the existing canvas classes could be moved to this model (Image, Text, etc.) and drawRenderLayer could be made more simple. The image and font loading handlers currently exposed in DrawingUtils are really not needed. They're a remnant from the flipboard.com code base which uses flux for invalidating layers when images and fonts load. The way it's done now in react-canvas is that the Image and Text layers are responsible for calling invalidateLayout or invalidateBackingStore as appropriate.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

I can make my style work with es5 style. No issues with that in fact that
will be easier :-)
On Feb 19, 2015 11:40 PM, "Michael Johnston" [email protected]
wrote:

I have mixed feelings about using es6 classes, though that appears to be
where things are going. The question of how mixins work in this world is
still an open one. Until things settle a bit more I would be in favor of
the createClass style, similar to what @fdecampredon
https://github.com/fdecampredon is doing with createCanvasComponent
(though maybe it would make since to call this createCanvasClass? Or simply
ReactCanvas.createClass?)

I imagine the existing canvas classes could be moved to this model (Image,
Text, etc.) and drawRenderLayer could be made more simple. The image and
font loading handlers currently exposed in DrawingUtils are really not
needed. They're a remnant from the flipboard.com code base which uses
flux for invalidating layers when images and fonts load. The way it's done
now in react-canvas is that the Image and Text layers are responsible for
calling invalidateLayout or invalidateBackingStore as appropriate.


Reply to this email directly or view it on GitHub
#13 (comment)
.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

I have problem is with the dual method, I just happen to dislike it.
On Feb 19, 2015 11:45 PM, "Abhishek Hingnikar" [email protected] wrote:

I can make my style work with es5 style. No issues with that in fact that
will be easier :-)
On Feb 19, 2015 11:40 PM, "Michael Johnston" [email protected]
wrote:

I have mixed feelings about using es6 classes, though that appears to be
where things are going. The question of how mixins work in this world is
still an open one. Until things settle a bit more I would be in favor of
the createClass style, similar to what @fdecampredon
https://github.com/fdecampredon is doing with createCanvasComponent
(though maybe it would make since to call this createCanvasClass? Or simply
ReactCanvas.createClass?)

I imagine the existing canvas classes could be moved to this model
(Image, Text, etc.) and drawRenderLayer could be made more simple. The
image and font loading handlers currently exposed in DrawingUtils are
really not needed. They're a remnant from the flipboard.com code base
which uses flux for invalidating layers when images and fonts load. The way
it's done now in react-canvas is that the Image and Text layers are
responsible for calling invalidateLayout or invalidateBackingStore as
appropriate.


Reply to this email directly or view it on GitHub
#13 (comment)
.

from react-canvas.

mjohnston avatar mjohnston commented on June 12, 2024

You have a point there... I wonder if the same customization at the layer-level can be done by composition and configuration through props?

For instance, rather than injecting different layer properties from the Component, the Layer would conditionalize it's drawing code based on this.props.xxx.

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

@mjohnston @darkyen my original proposition was made to avoid a big refactoring if we are allowed to have a bigger refactoring while I most of the time try to avoid class an inheritance I think also that in this case it could make sense. I could make a proposal and a little prototype in that direction if you wish.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

Makes sense, PS here is are two doable new proposal using composition

// Extending how react does it we can do something like this as per reacts code

var AwesomeComponent = ReactCanvas.createClass({
     draw(ctx){
           ctx.rect(20,20,40,40);
           ctx.stroke();
     }
});
// and have a boolean or something ... or
// @fdecampredon's way  of ding it
elements, and to achieve the layout Layer we

Another solution using pure react

import React from 'react';
import {LayoutLayer, RenderLayer, Drawable} from 'react-canvas';

var AwesomeView = React.createClass({
    onAnimationFrame(ctx){
    /* call to draw */
      // do your awesome stuff !
    },
    render (){
          return (
               <RenderLayer>
                   <Drawable 
                       cachable={false}/>
               </RenderLayer>
          );
    }
});

In the second example we can keep using react style of doing things and simply just call the parents.onAnimationFrame method from the element. That way react can also re-use the top Components and just change the Drawable component dynamically. This is also pure react-style composition. and i can submit a pr for the latter by saturday evening (Finally its friday !) (I feel the latter is more slightly inspired by rackt/react-router how they use and routes to define and compose incredible ui's. Also as per performance is concerned once the state is built react's hyperfast way of binding this should take care of things for the most part but i will try to benchmark.

Perhaps it might be better to allow the person to pass the function name too :D

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

any suggestions ?

from react-canvas.

fdecampredon avatar fdecampredon commented on June 12, 2024

There is only one thing bothering me @darkyen actually the react component is just a wrapper on top of the render layer, and the render layer does not depends upon that component, that's has some advantage, the render layer itself is just a plain serializable json object without any logic.
That has some value for example with that approach the rendering engine pretty much independent of the react stuff, you can consule the render layer tree for other means than drawing (see the issue about accessibility) etc....
With your proposal everything changes, the react component the render layer and the drawing engine becomes highly coupled.

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

No. I would still only write thin wrappers over an independent layer. For
instance.

var Drawable = React.createClass({
      onAnimationFrame(ctx){
           /* draw the thing by calling stuff */
           this.props.onAnimationFrame(ctx);
      },
      render(){
            // additional hidden Dom goes here
            return <this.props.children />
      }
});

var ClassyInput = React.createClass({
      getInitialState(){

      },

      transferFocus(e){
             this.refs.realInput.getDOMNode().focus();

             return false;
      },
      onChange(){

          /* sync state and bubble up and queue for re render */
      },
      af(){
          /* update the value and render the input this occurs freely */
      },

      render(){
             return (
                 <Drawable onTouchTapCapture={this.transferFocus}>
                     <input ref="realInput" />
                 </Drawable>
             );
      }

});

How about this ? AFAIK this will support A11y as well since a11y will be handled by cousin Dom. While render layer will our perform and since that Dom can be set to visibility hidden or something (like the checkbox or custom Dom element haxx ) we should be able to achice best of both worlds and If tomorrow a react based proper a11y implementation occurs it will be easy to be implemented

from react-canvas.

darkyen avatar darkyen commented on June 12, 2024

Also in the above example it will be fully valid React View without the
Surface element but when the surface element is present it will mantain the
shallow Dom and call the renderers if .onAnimationFrame property on
children ... (Read the accessiblity view, it seems that what i said is what Flipboard is doing in production)

from react-canvas.

jpatel531 avatar jpatel531 commented on June 12, 2024

+1

from react-canvas.

natew avatar natew commented on June 12, 2024

Any updates on this?

from react-canvas.

zallek avatar zallek commented on June 12, 2024

👍 Would be great to see that.

from react-canvas.

matt-d-rat avatar matt-d-rat commented on June 12, 2024

Any updates on this?

from react-canvas.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.