Giter Site home page Giter Site logo

joakin / elm-canvas Goto Github PK

View Code? Open in Web Editor NEW
161.0 4.0 29.0 2.09 MB

A canvas drawing library for Elm

Home Page: https://package.elm-lang.org/packages/joakin/elm-canvas/latest/

License: BSD 3-Clause "New" or "Revised" License

JavaScript 5.93% HTML 13.23% CSS 0.50% Elm 79.01% Makefile 1.33%
elm canvas web-components custom-elements elm-lang generative-art

elm-canvas's Introduction

joakin/elm-canvas

This module exposes a nice drawing API that works on top of the the DOM canvas.

Live examples (example sources)

Usage

To use it, read the docs on the Canvas module, and remember to include the elm-canvas custom element script in your page before you initialize your Elm application.

Then, you can add your HTML element like this:

module Main exposing (main)

import Canvas exposing (..)
import Canvas.Settings exposing (..)
import Color -- elm install avh4/elm-color
import Html exposing (Html)
import Html.Attributes exposing (style)

view : Html msg
view =
    let
        width = 500
        height = 300
    in
        Canvas.toHtml (width, height)
            [ style "border" "1px solid black" ]
            [ shapes [ fill Color.white ] [ rect (0, 0) width height ]
            , renderSquare
            ]

renderSquare =
  shapes [ fill (Color.rgba 0 0 0 1) ]
      [ rect (0, 0) 100 50 ]

main = view

Examples

You can see many examples in the examples/ folder, and experience them live.

Additionally, some of the p5js.org examples were adapted to Elm using this package. They can be found in the Elm discourse thread.

elm-canvas's People

Contributors

brainrake avatar catrield avatar dkodaj avatar joakin avatar joshuahall avatar kubaracek avatar mpizenberg avatar orasund avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

elm-canvas's Issues

Support for "groups" or similar batching of settings to multiple `Renderable`

(Per discussion on Slack.)

Currently there are no functions along the lines of group : List Setting -> List Renderable -> Renderable. As such, if one has e.g. a standard transformation, there is no way to apply it to all (or some) of one's Renderables, rather than having to apply it to each individually.

While the canvas API does not natively support groups, it is a common feature in many other interfaces to it, as well as e.g. elm-playground.

Fullscreen, resizable canvas – not visible on page load

I'm trying to draw a canvas that spans the entire width and height of the window and resizes dynamically when the window size changes. However, the canvas isn't getting painted on the initial page load, but only on subsequent updates. I've tried multiple implementations but the same problem keeps recurring.

Here's an Ellie showing the issue. Notice how the screen is blank until after a keypress event fires the update, and then the canvas appears.

As a work-around, I can change the screen record into a Maybe, however that just shifts the problem from occurring on initial screen load to on resize.

And just for the sake of good record-keeping here's the code from the Ellie linked above:

module Main exposing (..)

import Browser
import Browser.Dom exposing (Viewport, getViewport)
import Browser.Events exposing (onKeyDown, onResize)
import Canvas exposing (..)
import Canvas.Settings exposing (..)
import Canvas.Settings.Advanced exposing (..)
import Color
import Html exposing (Html, div)
import Html.Attributes exposing (style)
import Json.Decode as Decode
import Task


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , subscriptions = subscriptions
        , update = update
        }


-- MODEL


type alias Model =
    { screen : { width : Int, height : Int }
    }


init : () -> ( Model, Cmd Msg )
init _ =
    ( { screen = { width = 800, height = 600 }
      }
    , Task.perform (\{ viewport } -> ScreenSize (round viewport.width) (round viewport.height)) getViewport
    )


-- UPDATE


type Msg
    = TurnLeft
    | TurnRight
    | MoveForward
    | Other
    | ScreenSize Int Int


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        TurnLeft ->
            ( model, Cmd.none )

        TurnRight ->
            ( model, Cmd.none )

        MoveForward ->
            ( model, Cmd.none )

        ScreenSize w h ->
            ( { model | screen = { width = w, height = h } }
            , Cmd.none
            )

        Other ->
            ( model, Cmd.none )


-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ onKeyDown keyDecoder
        , onResize ScreenSize
        ]


keyDecoder : Decode.Decoder Msg
keyDecoder =
    Decode.map toDirection (Decode.field "key" Decode.string)


toDirection : String -> Msg
toDirection string =
    case string of
        "ArrowLeft" ->
            TurnLeft

        "ArrowRight" ->
            TurnRight

        "ArrowUp" ->
            MoveForward

        _ ->
            Other


-- VIEW


clearScreen : Float -> Float -> Renderable
clearScreen width height =
    shapes [ fill Color.black ] [ rect ( 0, 0 ) width height ]


view : Model -> Html Msg
view { screen } =
    div
        [ style "display" "flex"
        , style "justify-content" "center"
        , style "align-items" "center"
        ]
        [ Canvas.toHtml
            ( screen.width, screen.height )
            []
            [ clearScreen (toFloat screen.width) (toFloat screen.height)
              , shapes [ fill Color.red ] [ rect ( 30, 30 ) 200 200 ]
            ]
        ]

Unexpected scene

In your example Textures.elm line 147, If you delete rect ( 0, 0 ) w h, then everything becomes strange.
It seems that you have to add a "curtain" behind everything, is it normal?
What's the principle of it?

Use `Result` rather than `Maybe` for texture loading

Right when a texture fails to load for some reason, we can't tell why it failed because we just get a Nothing. Could you change this API to use a Result Http.Error Texture or even just a Result String Texture describing the failure?

Question about filter

Is it possible to apply a filter to Renderable object? (CanvasRenderingContext2D.filter)

Sampling Canvas Data (getImageData)

First off, awesome package! I'm having fun with it so far.

I was curious if you had any plans for an API to get/put raw image data? It seems like might be possible with Texture, but I'm not too sure.

Thanks!

Use elm-geometry types?

Hi @joakin! Thanks for all the great work you've done on this package.

Recently I've been playing with elm-canvas and elm-geometry. They work really nicely together. elm-geometry has a lot of useful functions that help you do things like find the center of a rectangle, or work with vectors. And of course, elm-canvas has a great API for drawing shapes.

My one problem is that it requires a lot of code to convert elm-geometry types to elm-canvas types.

For example, elm-canvas's, Canvas.circle gets called like this:

center = ( 100, 100 )
radius = 25
Canvas.circle center radius

But if I want to use elm-geometry types, I have to do this:

-- Define a helper function to convert elm-geometry types to something that elm-canvas understands.
circle : Quantity Int Pixels -> Point2d Pixels CanvasCoordinates -> Canvas.Shape
circle radius center =
    let
        -- Convert our Point2d [1] to a tuple like ( x, y ).
        centerTuple =
            Point2d.toTuple Pixels.inPixels center

        -- Now convert radius to a Float. It starts as an instance of the `Quantity Pixels`
        -- type [2], which is how elm-geometry does type-safe math and unit conversions.
        radiusInPixels =
            radius
                |> Pixels.toInt
                |> toFloat
    in
    Canvas.circle
        centerTuple
        radiusInPixels

[1]: Here are the Point2d docs.
[2]: And here are the Quantity docs.

Thanks again for all your hard work! I really like using this library, and I think that adding support for elm-geometry types would make it even more fun and enjoyable.

use elm-color instead of custom color library?

playing with this library, looks great so far.

question though. would it not make more sense for type matching to use the native elm color instead of custom CanvasColor?

I might be missing the reason for not, just mentioning it in case.

This would allow for using other libraries for color like elm-visualization and color scales.

Add making textures from DOM images

From slack, if you want to make textures directly in JS and pass them to Elm as flags/ports, it should be possible.

Making a texture from a DOM image

Should be easy to add and backwards compatible:

Canvas.Texture.fromDomImage : Json.Decode.Value -> Maybe Texture

Things to keep in mind:

  • Document well enough and maybe add a markdown file in the repo or an example Elm file to point to more info explaining how to load
  • Validate that the Value is actually a DOM image and that it has everything we need

Some notes for docs/example:

How to load images in JS to pass to Elm:

function loadImage(src) {
  return new Promise((resolve, reject) => {
    let image = new Image();
    image.onload = () => resolve(image)
    image.onerror = (err) => reject(err)
    image.src = src
  })
}
let images = await Promise.all(imageUrls.map(loadImage))

Other values that could be valid:

image
An element to draw into the context. The specification permits any canvas image source (CanvasImageSource), specifically, a CSSImageValue, an HTMLImageElement, an SVGImageElement, an HTMLVideoElement, an HTMLCanvasElement, an ImageBitmap, or an OffscreenCanvas.

It may be easy to add support for these other values (SVG, Video, other canvas, at least). Could warrant an investigation.

CORS - Textures and Tained canvas

Problem

Images downloaded as textures seems not to use crossOrigin = "Anonymous" flag and they make my canvas tained.

Reproduce

I've created this Ellie (https://ellie-app.com/86XKmYD9Mxya1) that loads a texture, just popup the browser console and execute this

var tmpCtx=document.createElement("canvas").getContext("2d");
tmpCtx.drawImage(document.querySelectorAll("img[src='https://www.alsipnursery.com/wp-content/uploads/2019/04/1703190.jpg']")[0],0,0);
tmpCtx.getImageData(1,1,1,1);

You can see that on my project https://kubaracek.github.io/hanggliding-map/ that uses map tiles

var tmpCtx=document.createElement("canvas").getContext("2d");
tmpCtx.drawImage(document.querySelectorAll("img[src='https://tile.nextzen.org/tilezen/terrain/v1/256/terrarium/11/1087/715.png?api_key=Nl9_q6yZQA6NIJp6Zn9kYg']")[0],0,0);
tmpCtx.getImageData(1,1,1,1);

Interesting this is that on my project the image returns: access-control-allow-origin: *

I'm having a strange problem with the canvas rendering properly everywhere

Namely: If I serve the canvas through reactor or through a compiled Html file, it's always just a transparent rectangle no matter what I put into it. I've tested this on up to date Opera, Chrome, and Firefox on Windows 10.

OTOH when I try the same thing (exact same code) with Ellie it seems to work fine in those same browsers: https://ellie-app.com/38zhvnLGCKMa1 :o

Do you reproduce the same, and/or is this a known issue at present? Or is what I describe difficult for others to reproduce?

Runtime crash with `arc` function and negative radius

If Canvas.arc is passed a negative value for its radius, it crashes with

Uncaught DOMException: CanvasRenderingContext2D.arc: Negative radius

This should probably at least be documented clearly in a warning, since one is usually reasonably insulated from runtime crashes with Elm. (Obviously, the use of a custom element here does away with that "guarantee," but it's still not entirely expected.)

Document the canvas coordinate system

Unless you already know from JS experience, from the docs it is impossible to know what the coordinate system is and what positive Y/X or negative Y/X are.

High CPU load with many canvases

When I get ~100 canvases on page and change something on one of them, all canvases are redrawn.
If this change is something intensive as mousemove, the CPU load jumps and stays high until I stop changing the canvas.
Is it possible to not redraw canvases for which draw commands did not change? Will commands diffing in set cmds (values) be less CPU-intensive than redrawing?

Not working

I tested your code and examples, but nothing shows up.

Is this repo still maintained?

Support for HiDPI?

I find that rendering text on a hidpi screen (in my case, just Windows 10 Chrome with interface set to 175%) is very blurry. I have read here:

https://www.html5rocks.com/en/tutorials/canvas/hidpi

and here:

https://groups.google.com/forum/#!topic/elm-discuss/pq1KS8XgFiQ

that this could be addressed by a few lines of JS trickery.

Any chance of some kind of support for that here?

It looks like the trick that they use is a drop-in option that shouldn't disturb any existing code that uses canvas and should still look perfect on non-HiDPI screens. :o

DOM images textures break in Firefox

I have an app that gets a list of files and sends them as List D.Value to a port, on js side I do this:
File -> Image -> Canvas -> downscale -> Canvas -> Image -> send it back to elm through port.
I send Images back one by one as soon as any of them is ready. Then in elm I decode them with Canvas.Texture.fromDomImage and save in a list in model, then draw them in view with List.map.
Often that breaks elm app in Firefox. Sometimes works ok. With the same images. When it breaks - it is always the same error, I made screenshots.
Capture1
Capture2
I've updated Firefox to the latest version. This does not happen in Chrome or Safari.
I really like this package! I'd love to help anyway I can!
The app I am working on is here:
https://github.com/shepelevstas/elmphoto.git

closePath operation

When drawing a path, to fill it, it seems I have to add the first point at the end again. The closePath function does that in JS. I would like an equivalent in the elm-canvas package. Or did I miss something?

Missing support for images

I know it's a titan task for a pure language like elm to juggle with referencing image resources across DOM elements.
Please point out the lack of support and the reasons why in your README and the elm package docs.

And please consider to find a way for base64 dataUrls as a start.

Canvases get blank on deleting one of them from a List

Hello! First of all - Great package!!! Thanks you!!! =D

In my Model I have List {texture:Canvas.Texture, id:Int}
when I delete on of textures with { model | textures = List.filter (.id >> (/=) delete_id) model.textures } in update function - all canvases (drawn with List.map drawCanvas model.textures) that have greater id than the deleted one - become blank. They are redrawn as soon as I mouseover one of canvases.
Am I doing it wrong? Or is it a bug? Are there any workarounds?

Thank you!

arc function: glitches

I was attempting to replicate p5 examples, namely pie chart.

Found a glitch with clockwise=True. The center of the arc seems a little off the provided point.

using clockwise induces a glitch. Using anti-clockwise doesn't, but it's really confusing.

Margin bug: canvas and elm-canvas don't share the same height

Hi!

I banged my head on this one :)
I'm pretty sure the bug is in the library so here is my bug report.

The bug cannot be observed by opening the documented examples, such as this one: https://chimeces.com/elm-canvas/ellie.html

But the bug can be observed by opening the documented starter template example, here: https://ellie-app.com/62Dy7vxsBHZa1

The code of both examples is mostly the same, but if you look carefully at the ellie template, canvas and elm-canvas don't share the same height:

image

This causes problems with edge detection (I wanted to animate a bouncing ball).

After much head scratching, I noticed that removing <!DOCTYPE html> from my HTML document made the problem disappear! And this is consistent with the two examples mentioned above: the one displaying the problem does have a <!DOCTYPE html> decleration, the one that is not displaying the problem does not have a <!DOCTYPE html> declaration.


See the effect of removing/adding the <!DOCTYPE html> declaration below:

https://github.com/benjamin-thomas/nature-of-code/tree/efc9abd26beacd27e10e0f00fdb9ed52883aba8a/_basic_setup/elm/elm-canvas

ok
not_ok


I found writing custom CSS rules quite tricky with this library, so in the end I followed the starter template's suggestion.

Maybe all that's required is suggesting better CSS defaults?

Text Color Support

fillText seems to be missing from the newer versions of elm-canvas and there doesn't appear to be another documented method for setting text color.

arc function: anti clockwise doesn't work with startAngle < endAngle

I should expect that we could maintain the angles and just reverse the orientation of the arcs.

But trying to make a pie chart, I've found that only using startAngle > endAngle with clockwise = False works.

Using counter clockwise, this one do not work as expected. This other one, do work but it's rather confusing that startAngle must be greater than endAngle. Besides it's putting every arc next to the other in a clockwise manner. I except for the first one to be red in the top right quadrant, green on the top-left one and blue in the lower one.

It's like the angles always are clockwise and fall in the same way no matter if clockwise it's true or false, but only it fills well if the direction of the fill it's in accordance with clock direction (startAngle > endAngle for clockwise, the other way around for anti-clockwise) very confusing.

4.0.1 version - style background issues

Refactoring the p5 examples to work with last version (4.0.1); found that the background color shrinks to a small height on the canvas.

Compare color-hue from docs[1] (canvas version 3.0.5) with color-hue refactored (canvas version 4.0.1)

the same happens with reactor.

[1] that doesn't compile on ellie, it seems that it ignores the version number and just uses the latest; but works just fine in a normal desktop setup. It compiles and the background color displays correctly.

Improve arc docs

The function is pretty confusing to use, at least some docs should help with it.

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.