GithubHelp home page GithubHelp logo

elm / core Goto Github PK

View Code? Open in Web Editor NEW
2.8K 95.0 361.0 1.77 MB

Elm's core libraries

Home Page: http://package.elm-lang.org/packages/elm/core/latest

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

Elm 84.76% JavaScript 14.45% Shell 0.79%
elm core dictionary set array json

core's People

Contributors

avh4 avatar brian-carroll avatar dandandan avatar deadfoxygrandpa avatar eeue56 avatar evancz avatar harrysarson avatar hossameldeen avatar imeckler avatar jazmit avatar jcollard avatar jerith666 avatar jinjor avatar jonathanhefner avatar jonathanperret avatar jvoigtlaender avatar jwmerrill avatar laszlopandy avatar lorenzo avatar mariosangiorgio avatar maxsnew avatar mgold avatar noahzgordon avatar process-bot avatar rgrempel avatar rluiten avatar robinheghan avatar simonh1000 avatar thomasweiser avatar turbomack 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  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

core's Issues

Initial value in a channel ignored in foldp

The initial value in a Channel doesn't appear in a foldp over the channel converted to a Signal.

type Action = Init
            | ...

actions : Signal.Channel Action
actions = Signal.channel Init

update : Action -> Model -> Model
update action state =
  case Debug.log "action" <| action of      -- Debug.log never prints "action: Init"
    Init -> ...

model : Model -> Signal Action -> Signal Model
model initialState action =
  Signal.foldp update initialState action  -- Seems like the initialState here should be
                                           -- combined with the initial action, either
                                           -- to create the first value or to create the
                                           -- first two values in the signal

main = run emptyModel (Signal.subscribe actions)

Initializing a signal with a good initialState is not always easy because initialization may depend on a signal coming in from a port in which case you need to do something like this:

port userId : Signal Int

main = run emptyModel (Signal.zip (Signal.subscribe actions) userId)

...in this case creating an initial model based on the incoming userId seems near impossible unless some event can be triggered (perhaps by explicitly calling send on the userId port after the widget has been initialized in order to force an update).

This might assist with issues like this one as well: https://github.com/elm-lang/core/issues/91. I'm not taking the work on promises into account, I don't know if this may be handled already in the upcoming implementation.

Elaborating the arguments to Http.request for CORS support

With the ongoing work on Http, I'd like to bravely throw in a feature request for CORS support :)

The protocol for CORS is actually somewhat involved, particularly since it involves a preflight OPTIONS request which I believe needs to be resent after a timeout period. I think this is usually invisible to the user of most API's, it seems as though things can get tricky.

Using AngularJS's $httpProvider and Restangular, this looks like the following:

  $httpProvider.defaults.useXDomain = true
  Restangular.setDefaultHttpFields {withCredentials: true}
  Restangular.setDefaultHeaders {"Content-Type": "application/json"} # X-Requested-With header can't be used with CORS

While non-CORS restangular requests simply look like

  Restangular.setDefaultHeaders 
  { "Content-Type": "application/json",
  , "X-Requested-With": "XMLHttpRequest"
  }

I think swapping the argument to request in the new API might also be handy.

request : String -> String -> String -> List (String, String) -> Request String

Since request is an elaborated version of get/put/post/delete it seems as though the primary use case is going to be adjusting the headers...
For example, for a regular ajax request, get might look like

get = Http.request
    [ "Content-Type": "application/json",
    , "X-Requested-With": "XMLHttpRequest"
    ]
    "GET"

while a CORS ajax request looks somewhat different

corsGet = Http.request
    [ "Content-Type": "application/json",
    , -- ... ?
    ]
    "GET" -- "OPTIONS" ?

`Text.style` supersedes `Text.color`

First applying a style seems to make it impossible to then use Text.color.

http://share-elm.com/sprout/56506538e4b05f0d6cc4a102

import Graphics.Element (..)
import Graphics.Collage (..)
import Text (..)
import Text
import Color (..)

redText : String -> Text
redText str =
    Text.color red (fromString str)

redText' : String -> Text
redText' str =
    Text.color red (style defaultStyle (fromString str))

main : Element
main = flow down 
  [ leftAligned <| redText  "Hello, World!"
  , leftAligned <| redText' "Hello, World!"
  ]

Re-rendering can cause an input field to lose focus.

In this example, typing in the input field causes it to immediately lose focus.

The issue is apparently that whenever the number of elements in a flow changes, all the elements in the flow are re-rendered. Re-rendering an input causes it to lose focus.

Avoiding re-rendering input fields unnecessarily would mean this bug would manifest less often, but the robust solution is to make sure that re-rendering restores focus.

Some discussion and a work around for this particular case here:

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

Integer division doesn't work with left operands larger than LONG_MAX

The issue at elm-compiler#878 mentions it, but it's in the wrong repo, so I'm recreating it here.

LHS arguments greater than LONG_MAX(4294967295) return a negative number when using integer division (//).

main = asText (4294967295 // 2)
-- shows 2147483647
main = asText (4294967296 // 2)
-- shows -2147483648

This is because elm-core's src/Native/Basics.js div function is a/b|0, thus using JavaScript's OR operator, which most converts the LHS to a 32-bit integer and returns a 32-bit integer.

EDIT: I read the JS spec, it's not a bug with JS, just another one of its problems.

Textured shapes performance issue

Hi,
Textured shapes consume way too much CPU, see this issue:
elm/elm-lang.org#186

(below my original comment)

Hitting this as well with Elm 0.14 on Tacks. Here are Chrome CPU profiling screenshots:

  • with racing area as a filled rect:

54a4979a120000300001ae3e 2015-01-18 18-58-56

  • with racing area as a textured rect (image being 200*200 jpeg file):

54a4979a120000300001ae3e 2015-01-18 18-58-41

`Cannot read property 'length' of undefined` when concatenating largeish arrays

I've defined concat as

concat = A.foldl (\x acc -> log "step" <| x `A.append` acc) A.empty

Using this,

concat << A.repeat 4 <| A.repeat 4 ()

produces

step: Array.fromList [(),(),(),()]
step: Array.fromList [(),(),(),(),(),(),(),()]
step: Array.fromList [(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),()]
step: Array.fromList [(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),()]
Array.fromList [(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),()]
 : Array.Array ()

as expected.

concat << A.repeat 4 <| A.repeat 5 ()

produces

step: Array.fromList [(),(),(),(),()]
step: Array.fromList [(),(),(),(),(),(),(),(),(),()]
step: Array.fromList [(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),()]
TypeError: Cannot read property 'length' of undefined

The line producing the error is https://github.com/elm-lang/core/blob/master/src/Native/Array.js#L477

flow left / right cause error on re-render

Initially, the page loads fine. however, upon clicking the rerendering only the second number is rerendered correctly. The console gives the following error message: Uncaught TypeError: Cannot read property 'style' of undefined

module Bug where

import Text (asText)
import Graphics.Element (..)
import Signal (Signal, foldp, (<~))
import Mouse

display : (Int, Int) -> Element
display (f, s) = 
    -- No problem with flow down
    --flow down [ asText f, asText s ]

    -- However, it fails with flow right
    flow right [ asText f, asText s ]

-- Each time someone clicks, roll the dice.
handleClick : () -> (Int, Int) -> (Int, Int)
handleClick _ (f, s) = (f + 1, s + 1)

-- Basic wiring
main : Signal Element
main = display <~ (foldp handleClick (0, 0) Mouse.clicks)

Mouse.isDown is not just the left button

The comment in the source says

{-| The current state of the left mouse-button.
True when the button is down, and false otherwise. -}

But in reality it is ANY mouse button. This leads to misbehaviour as described in issue elm/elm-lang.org#184. jQuery's docs say:

The mousedown event is sent when any mouse button is clicked. To act only on specific
buttons, we can use the event object's which property. Not all browsers support this property
(Internet Explorer uses button instead), but jQuery normalizes the property so that it is safe
to use in any browser. The value of which will be 1 for the left button, 2 for the middle button,
or 3 for the right button.

Confounding behavior of Time signal

I just happened upon the following extremely confusing behavior. Consider the following program:

module Bad where

import Keyboard
import Time
import Text
import Signal

type Update
  = Key {x : Int, y : Int}
  | Tick Time.Time

updates =
  let time = Time.every 30 in
  Signal.mergeMany
  [ Signal.map Key (Signal.sampleOn time Keyboard.arrows)
  , Signal.map Tick time
  ]

update u s = case u of
  Key arr -> {s | x <- s.x + arr.x, y <- s.y + arr.y}
  Tick t  -> {s | time <- t}

main = 
  Signal.foldp update {x=0,y=0,time=0} updates
  |> Signal.map (Text.plainText << toString)

If you try running it, you'll notice that the time field never changes! Somehow those updates aren't making it to the merged signal. Replacing on of the instances of time with a "new" Time.every 30 makes things work as expected.

Separate scale into scaleX and scaleY, and related issues

It seems a bit arbitrary that Forms have separate fields for theta, x, y, and scale given that they could be wrapped in a group with an appropriate Transform2D (I assume this is an optimization to avoid additional levels of indirection). Canvas supports scaling different amounts in the X and Y directions. Should forms have separate scaleX and scaleY fields? Should they just have one field which is a Transform2D?

Tests for Collage module

I was pondering how to add tests for Collage, and came up with the idea of using node-canvas to render a data-url and comparing it to a known url.

This would add another test dependency to core, but would add some comfort in making changes to the Native modules.

Perhaps in future it could be combined with a tool to compare the expected DOM output using js-dom or similar and become a general purpose regression testing tool for Elm.

Is this desirable or should we avoid adding extra dependencies to Core?

Abstract shapes & render performance

The recent discussion on #118 by @jazmit got me thinking...

Shape currently means "polygon" in Elm (a list of points). I would like to propose that it would make sense to move towards an abstract representation to shapes that makes a distinction between BasicForm, Shape and Polygon.

The invariant that qualifies something to be a Shape would be the function...

type alias LevelOfDetail = Float
tesselate : LevelOfDetail -> Shape -> Polygon

...so that something like Text is excluded.

There are a couple of nice attractions:

  • Renderer abstraction: Every renderer is different. One concrete example is rendering a Circle to SVG: it will be much cleaner if the algebraic representation is preserved. One could even render shapes relatively cleanly to Html using stylesheets. There's also a chance render quality could be improved - for example, it might make sense for a renderer to implement specialized anti-aliasing for curves and circles.
  • Renderer performance: There could be large performance benefits to specializing rendering. There's a good chance that canvas.arc is orders of magnitude faster than a highly tessellated polygon. It's also quite likely that arc uses an adaptive tessellation that could take any number of interesting things into account to improve quality and performance. Another example would be a WebGL renderer, rendering circles and curves with shaders.
  • Memory use: would plummet :). Just 1000 circles * 50 points * 2 coords * 8 bytes = 800 000 bytes.
  • Algorithms: Any algorithm that works with polygons would continue to work with shapes since it can always be converted to a Polygon. The advantages are also many since it allows for more specialized CSG, ray tracers/view cones, physics etc.

Much of the above probably requires Shape constructors to be exposed, which I think might be a tad premature. Never-the-less, performance might be something worth looking into sooner. Myself and @TheunisKotze are about to do some testing to see what effect this has on us - we draw a helluvalot of circles. I'll report back!

Graphics.Element middle position can be off by one pixel due to rounding

Hello,

Just started playing around with Elm and am finding it very impressive! Keep up the great work.

I noticed that in certain cases attempting to position an element in the middle of another element results in a layout that is off by a single pixel. I believe this is because line 241 and 236 in the source javascript are using the bitwise or to round towards a single pixel instead of something like Math.round().

For a reproduction see this example which should draw a red rectangle with a single pixel border all the way around, but instead draws it with a 2px border at the top and left only.

import Graphics.Element (..)
import Color (red, blue)

main = spacer 99 19
  |> color red
  |> container 101 21 middle
  |> color blue

screen shot 2014-12-18 at 9 00 33 pm

On an unrelated note, I noticed P, Z, and N seem to refer to different methods of setting an axis origin for positioning. This terminology is unfamiliar to me and I would be interested to know what it refers to.

Images mixing

Not sure if this is a compiler or core library issue or programming error, I haven't identified the cause yet, but it seems like it shouldn't happen due to programming error. Also I have a hard time finding a good description, but when running the example code (a simple slide-like presentation) below, this is what I observe:

  • when going from the second slide (shell) to the third (book), the image dimensions get replaced with those of the third slide, but the image stays the same.
  • going forward, then back again, will correctly show the book
  • this happens only when an image is followed by a fittedImage, when both are regular or fitted image, they show up as expected

Also worth noting: This setup somehow breaks hot reloading in elm-reactor. When changing something, often I have to manually reload for everthing to work.

(using Elm platform 0.16)

module Bugs where

import List exposing ((::), foldr, length, drop, head)
import Signal exposing (Signal, constant, foldp, map2)
import Graphics.Element exposing (..)
import Keyboard
import Debug
import Text exposing (fromString)


slides = [
  constant <| centered <| fromString "use arrow keys to go forward/backward",
  constant <| fittedImage 100 500 "https://raw.githubusercontent.com/elm-lang/elm-lang.org/master/resources/imgs/shells.jpg",
  constant <| image 700 500 "https://raw.githubusercontent.com/elm-lang/elm-lang.org/master/resources/imgs/book.jpg",
  constant <| centered <| fromString "go back and it will be a book instead of shells"
  ]

lastSlide = length slides - 1

updateSlide {x,y} current = 
  let nextSlide = case x of
        -1 -> current - 1
        1 -> current + 1
        _ -> current
  in clamp 0 lastSlide nextSlide 

chooseSlide page = drop page >> head

safeSlide e = case e of
  Just elem -> elem
  Nothing -> centered <| fromString "โ€ฆ"

-- signals

currentSlide = foldp updateSlide 0 Keyboard.arrows

main = 
  let maybeSlides = applyMany (Signal.map chooseSlide currentSlide) slides
  in Signal.map safeSlide maybeSlides


-- debug
slideWatch = Signal.map (Debug.watch "slide") currentSlide


-- taken from elm-signal-extra

combine : List (Signal a) -> Signal (List a)
combine = foldr (map2 (::)) (constant [])

andMap : Signal (a -> b) -> Signal a -> Signal b
andMap = map2 (<|)

applyMany : Signal (List a -> b) -> List (Signal a) -> Signal b
applyMany fs l = andMap fs (combine l)

Crash when using an invalid regular expression

Issue for discussion thread https://groups.google.com/d/topic/elm-discuss/7Uwl5-usqjs/discussion

Basically, JavaScript's RegExp (which is what Elm's Regex sits on top of) can throw an exception when given an invalid string. Examples:

RegExp("a"); // OK
RegExp("\\"); // Exception!
RegExp("("); // Exception!
RegExp("(?"); // Exception!
RegExp("(?:"); // Exception!
RegExp("?"); // Exception!
RegExp("+"); // Exception!
RegExp("*"); // Exception!

The obvious fix is to make Elm's Regex.regex return a Result (or a Maybe), but that seems like a pain to work with. It's also an API-breaking change, which I have no problems with whatsoever, but others might.

The only other solution I can think of is to escape characters at the end of an input string until no exception is thrown. For example:

RegExp("(?:"); // Exception!
RegExp("(?\\:"); // Exception!
RegExp("(\\?\\:"); // Exception!
RegExp("\\(\\?\\:"); // OK

It's a bit hacky though, and may not follow the principle of least surprise. Thoughts?

Memoize module make functions

I've been investigating the loading for our elm widgets...

It appears to me that when several widgets are instantiated (embedded), repeated calls to make for a large module is very slow. In particular, Bootstrap.Html.make() takes a large amount of time:

timeline

One way of testing this quickly is as follows:

for (var i = 0; i < 100; ++i) {
    Elm.Bootstrap.Html.make({});
}

The above takes 12.68s on my laptop.

One quick solution might be to memoize the make function. The generated function currently looks like this...

Elm.Bootstrap.Html.make = function (_elm) { ... }

...I'm not 100% sure if it would be necessary to memoize the function based on the incoming _elm environment, but it seems like that shouldn't be necessary. One edge case is if someone is uses different versions of the same package for different embedded widgets.

Keyboard should have a signal of keypresses as well as than isDown states

The Mouse module has isDown and clicks. The Keyboard module only has isDown. I would like a function keypresses : KeyCode -> Signal (), analogous to Mouse.clicks.

I've implemented it like this, but there's probably a better way, and it would be nice if this functionality were in core:

keypresses : KeyCode -> Signal ()
keypresses c = isDown c |> keepIf identity False |> map (always ())

`Array.foldr` operates out of order for Arrays larger than 32 elements

A.foldr (::) [] <| A.fromList [1 .. 32]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]

A.foldr (::) [] <| A.fromList [1 .. 33]
[32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,33]

A.foldr A.push A.empty <| A.fromList [1 .. 32]
Array.fromList [32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1]

A.foldr A.push A.empty <| A.fromList [1 .. 33]
Array.fromList [33,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]

Elm.embed should accept a div with children.

Currently if you try to embed Elm on a div with children it fails with:
Error: Elm.node must be given an empty DIV. No children allowed!

However there is a valid use case when this should be allowed. I am porting a mobile web app from React, which needs to start up as quickly as possible. My React version did something like this:

<div id='react_container'>
    <div class="spinner">
        <div class="bounce1"></div>
        <div class="bounce2"></div>
        <div class="bounce3"></div>
    </div>
</div>
<script src="myapp.js"></script>
<script>
React.renderComponent(MyApp(), document.getElementById('react_container'));
</script>

The spinner div has some CSS animation applied to it, and starts animating immediately while the scripts are loading. Once React has booted up, the first render will replace the children (including spinner) with the real app (or with the same spinner div if the app is still waiting for data). This is a very useful way to lower the perceived loading time.

dropDown: parameter for selected option?

Graphics.Input.dropDown only takes a handler function and a list of options to render a drop-down list. However, this provides no way to set the drop-down's current selection. In particular, the selection can update a signal but a new signal cannot update the selection (and trigger a re-render). This is in contrast with other inputs: checkbox takes a Bool parameter for the current check state, and field takes a Content parameter for the current text and selection.

I'd like to see dropDown's signature being changed to something along the lines of:

dropDown : (a -> Signal.Message) -> List (String, a) -> a -> Element

where the third parameter is the selected option (which should also be present in the list of options). That way, one can for example map over the signal (obtained with Channel.subscribe) and provide the current value of the signal to use for the drop-down's selection. To use the same example as in the documentation:

type Sport = Football | Cricket | Snooker

sport : Signal.Channel (Maybe Sport)
sport = Signal.channel Nothing

sportDropDown : (Maybe Sport) -> Element
sportDropDown currentSport =
    dropDown (Signal.send sport)
      [ (""        , Nothing)
      , ("Football", Just Football)
      , ("Cricket" , Just Cricket)
      , ("Snooker" , Just Snooker)
      ] currentSport

main = map sportDropDown (Signal.subscribe sport)

Parser bug with record assignment

Take a look at https://github.com/rtfeldman/dreamwriter/blob/75651371541a88a1d85504e70c7e41afd914eaae/Dreamwriter/Model.elm

Notice that emptyState at the bottom awkwardly has an extra level of indentation compared to the type alias above. It turns out this extra indentation is currently mandatory for record assignment.

If you attempt to do the "commas at the end of the line" style like this, the parser will let you do indentation "normally" in the case of type alias (as you can see earlier in the file), but if you try to use this style with record assignment (as with emptyState) and use "normal" indentation instead of awkward extra indentation, you get the following syntax error:

>> Error when compiling Dreamwriter.Model:
>> 
>> Parse error at (line 41, column 1):
>> unexpected "}"
>> expecting a newline or whitespace
Warning: Error when compiling Dreamwriter.Model:

Parse error at (line 41, column 1):
unexpected "}"
expecting a newline or whitespace

Proposal: Generators

I have an experimental branch I've been playing with. After the discussion in #152, I've been trying to come up with an elegant and performant way of expressing loops. The concept that I kept coming back to is generators. You can see how they are implemented, and also how list functions can be implemented in terms of them. Note that I was able to remove several native List functions in favor of just the 3 in Native.Generator. It should be possible to do the same with loops in other native modules, e.g. Native.Regex.

So how do they perform? Good, although not as good as I would like. From preliminary testing, the biggest slowdown seems to be allocation / garbage collection of Maybe objects. The good news is that if we implement Maybe elision (i.e. Just x => x and Nothing to null in JavaScript) in the compiler, Generators should perform extremely close to their non-abstracted counterparts. (Other code will get faster too, of course.)

Below are some benchmark numbers (time in seconds; lower is better). All benchmarking was done on an old laptop to magnify performance gaps. With the exception of the last column, all benchmarks were done over a 500,000 element list. For the last column (foldl/100), I instead ran the test over 100 5,000 element lists. All higher-order functions (e.g. the f for map or the reduce for foldl) were as simple and dumb as possible to put emphasis on the speed of iteration.

branch map take filterMap repeat
master 4.15 4.05 4.20 1.25
generators 4.05 3.90 4.00 1.25
branch any foldl foldr drop foldl/100
master 1.05 1.05 1.10 1.0 0.95
generators 1.25 1.20 1.25 1.15 1.05

The takeaways, in my opinion, are:

  • For anything like mapping, Generators are a win. They do this by cheating (using mutation in JavaScript), but said cheating is confined to a single native method and every Generator benefits from it.
  • For pure iteration (involving no computation overhead), Generators are ~15% slower than data structure-specific native loops.
  • Performance could be improved by implementing Maybe elision as a compiler optimization, making the wins greater and virtually eliminating the losses.

Desired operations for Transform2D library

I think that the Transform2D type is a bit too abstract. I'm currently trying to debug something involving them and it's impossible to actually inspect them. The module itself provides no way to define functions out of the type, and it seems the only place Transform2Ds can be used is in Graphics.Collage.groupTransform. Such a library is of general use, i.e., not only with forms, and I think some version of the following functions would be quite reasonable to add:

apply : Transform2D -> (Float, Float) -> (Float, Float)

type alias TransformView =
  { matrix      : (Float, Float, Float, Float)
  , translation : (Float, Float)
  }
view : Transform2D -> TransformView

In fact these two functions are interderivable (up to floating point errors), so just one would be enough if you're all feeling spartan.

Sending Json.Value over a Port doesn't Work

File

module Main where

import Json.Encode as Json
import Signal
import Text (..)
import Time (..)

port out : Signal Json.Value
port out = Signal.sampleOn (every second) (Signal.constant (Json.object []) )

main = plainText "test" 

Compile this to a file main.js and then open this html file:

<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="main.js"></script>
</head>
<body>
<h1>Test</h1>
<div id="bug"></div>

<script type="text/javascript">
 var handler = function(o) { console.log(o) };
var div = document.getElementById('bug');
var test = Elm.embed(Elm.Main, div, { });
test.ports.out.subscribe(handler); 
</script>
</body>
</html> 

and get the error:

Initialization Error on port 'out':

    $Native$Json is not defined

Don't clear canvas by resetting width and height

This issue is part of trying to make animations run more smoothly in Firefox.

Currently, on each draw of a collage, the following is executed:

https://github.com/elm-lang/core/blob/9687580e6f7b012cdee712c2f14471b272c85488/src/Native/Graphics/Collage.js#L324

function nextContext(transforms) {
    while (i < kids.length) {
        var node = kids[i];
        if (node.getContext) {
            node.width = w;
            node.height = h;
            node.style.width = w + 'px';
            node.style.height = h + 'px';
            ++i;
            return transform(transforms, node.getContext('2d'));
        }
        div.removeChild(node);
    }
    var canvas = makeCanvas(w,h);
    div.appendChild(canvas);
    // we have added a new node, so we must step our position
    ++i;
    return transform(transforms, canvas.getContext('2d'));
}

Resetting the canvas node's height and width serves two purposes:

  1. Clearing the canvas
  2. Resetting any transforms that were applied to the canvas on the previous frame.

Unfortunately, it appears that resetting the canvas this way also produces a canvas-sized amount of garbage on every frame in Firefox.

Clearing the canvas can also be accomplished by calling ctx.clearRect(0, 0, w, h). However, this does not reset the transforms. Transforms can be reset through disciplined use of ctx.save() and ctx.restore(), but there are currently saves that are never restored:

https://github.com/elm-lang/core/blob/9687580e6f7b012cdee712c2f14471b272c85488/src/Native/Graphics/Collage.js#L313

function transform(transforms, ctx) {
    ctx.translate(w/2, h/2);
    ctx.scale(1,-1);
    var len = transforms.length;
    for (var i = 0; i < len; ++i) {
        var m = transforms[i];
        ctx.save();
        ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
    }
    return ctx;
}

There are two problems here:

  1. No one ever saves before or restores after the translate and scale in the first two lines of this function
  2. When there are additional transforms passed, it appears that the save inside the for loop is not matched anywhere by a corresponding restore.

I think there is a potentially large win to be had by using transforms in a more disciplined way so that it is possible to avoid resetting the canvas width and height on every draw if they have not changed.

Will the next release of core be version 2.0.0?

All the Travis tests are failing right now because Elm-Test relies on the List function maximum : List comparable -> comparable function, which has now changed to maximum : List comparable -> Maybe comparable.

It's pretty easy to fix this with a new version of Elm-Test, but I want to set the correct version bounds, so when all this new core stuff is released it won't mess people up if they're still using core-1.x.x

Semantics of `fpsWhen` is quite off.

So, in jvoigtlaender@274cd7e I had been trying (as part of the effort to make timestamp work in a consistent manner over all signals) to refactor fpsWhen while preserving its semantics. I failed in that, which luckily was caught by @jwmerrill, and fixed in elm-lang@6a36cd7. Throughout all this, I hadn't been checking what the semantics of fpsWhen was exactly, only trying to preserve it. Have now looked into the semantics of fpsWhen and found serious problems, I think.

Let's consider a signal isOn with the following behavior:

  • initial value False
  • at 0.5 seconds, has a True event
  • at 2.0 seconds, has a False event
  • at 3.5 seconds, has a True event
  • at 4.0 seconds, has a False event
  • no further events

For example,

isOn = flip member [1,7] <~ keepIf (flip member [1,4,7,8]) 0 (foldp (\_ c -> c+1) 0 (every 500))

Let's now consider the signal obtained by fpsWhen 1 isOn. Surprisingly, it shows the following behavior (since at least Elm-0.13):

  • at 0.5 seconds, has an event with value 0
  • at around 1.5 seconds, has an event with value 0
  • at 2.0 seconds, has an event with value 0
  • at around 2.5 seconds, has an event with value around 1000
  • at 3.5 seconds, has an event with (same) value around 1000
  • at 4.0 seconds, has an event with (same) value around 1000
  • at around 4.5 seconds, has an event with value 0
  • no further events

One way to check these claims is to run

main = asText << snd <~ foldp (\(t',d) (t,l) -> (t',(t'-t,d)::l)) (0,[]) (timestamp (fpsWhen 1 isOn))

(for example with different language versions at http://share-elm.com)

Many of the values we see appearing are dubious (for example, isOn was True only for 2 seconds overall, and yet we see three time deltas of 1 second each). Also, the events at 2.5 and 4.5 seconds shouldn't be happening at all. It turns out that the clearTimeout in the implementation of fpsWhen has no effect whatsoever. PR https://github.com/elm-lang/core/pull/138 fixes that specific "bogus events" aspect. However, even after that fix, the semantics of fpsWhen is still off. For the above situation it now behaves as follows:

  • at 0.5 seconds, has an event with value 0
  • at around 1.5 seconds, has an event with value 0
  • at 2.0 seconds, has an event with value 0
  • at 3.5 seconds, has an event with value 0
  • at 4.0 seconds, has an event with value 0
  • no further events

Now the bogus events at 2.5 and 4.5 seconds are gone, but all other events show value 0, even though the isOn signal has been True for 2 seconds, of which 1.5 seconds were consecutively, so certainly should have shown some non-0 time value passing, given that our granularity was "1 frame per second".

Http.send behavior

From the mailing list:

Right now, the way Http.send works, the Waiting state only occurs for the first request. If the URL changes thereafter, it will maintain the previous Response until the new response comes in. I can see why that would be a useful behavior to have, especially if you hook up your output/views directly to the response signal.

In more stateful applications however, it would be useful to have a different Http.send (not sure what I would name it) which, when the URL changes, will revert to the Waiting state while waiting for the new response to come in. This would allow someone to have a loading animation be displayed whenever requests to the server are happening, so the user is aware that something is being waited on. In this style, if the programmer wants to display the old results while the new results are fetching, he can do that by storing results in his/her application state.

Jeff Smits added that under this new behavior, "you can do a dropIf ((==) Waiting) Waiting to get the old heaviour back." Whereas you cannot derive this new behavior from the old behavior.

Just wanted to put this suggestion out there for the next revision of Http. The change itself is just a single line swap in Native/Http.js

Graphics.Input.hoverable causes runtime error

Minimum example:

import Graphics.Element as E
import Graphics.Input as Input
import Signal as S

chan = S.channel False

main = E.spacer 100 200 |> Input.hoverable (S.send chan)

Produces:

Cannot read property 'make' of undefined

Open the developer console for more details.

It seems to error on var Text = Elm.Native.Text.make(localRuntime); because Elm.Native.Text is undefined. Seems like a dependency ordering issue.

Allow rendering of text to collages

Could we have a function in the Collage or Text package that allows rendering of text to the 2D canvas?

eg: (if in the Collage library)

fromText : Text -> Shape
fromTextWithMaxWidth : Text -> Float -> Shape

I know it's possible to convert the text first to an Element, then to a Form, which overlays a span on the canvas. However this doesn't support text stroke styles, and scaling can be wonky. I'd also like this so we can have text in WebGL (once we've added a function to elm-gl to convert a collage to a webgl texture).

Am happy to have a stab at doing a pull request for this if folks think it's a good idea?

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.