Comments (17)
Yes. I like that.
This is one those cases where it looked much cleaner before running "mix format".
Breaking up the graph into pre-compiled sub-chunks-things is definitely a good best practice. So yes. That will happen.
I'm mixed on the &
vs fn
formatting. I prefer the look of the &
version, but it isn't intuitive for a beginner as to what is going on. I can just imagine a beginner getting to a line that reads @text & &1
and giving up. Wish there was a compact version that looked like it had less magic. Open to suggestions.
I too thought about writing a DSL and macros and all that. Want to keep it as simple as possible until there is a burning need to add magic to make it cleaner. Encouraging a best practice of breaking up the code is a great way to avoid that scenario.
But most of all - Thank you for the kind words!
from scenic.
Thanks for this @pragdave, it helps a lot!
@boydm: I'm an Elixir beginner and I'm definitely more comfortable with fn
over &
.
from scenic.
from scenic.
I'm mixed on the & vs fn formatting. I prefer the look of the & version, but it isn't intuitive for a beginner as to what is going on. I can just imagine a beginner getting to a line that reads @text & &1 and giving up. Wish there was a compact version that looked like it had less magic. Open to suggestions.
This example is really bad even for non-beginners. It says almost nothing. I would add a prefix and suffix which should say much more for example: graph_text_func = & &1
, so even beginner can see func
part and would start searching for explanation like Elixir function references
or Elixir function short version
which I think should be enough. Also graph
part is important, because it could say where it would be used in this file. Finally I would like to remove @
character making it compile time variable as there is no need to use module attribute which would not be called from any function, so only final @graph
should be an attribute.
What do you think about it?
from scenic.
Do you want a PR?
Yes please Dave. I'm up to my eyeballs in features for 0.10.0, services to support it and dealing with the fact that I just moved halfway around the planet. (New Zealand is very nice :)
I'm sure you can turn this into a teaching moment with regarding the whole fn
vs &
thing.
from scenic.
While I'm on a roll, how about one wafer-thin addition to the API that curries the various primitives so they can be treated as data:
@lines [
line_spec(@line, stroke: {4, :red}),
line_spec(@line, stroke: {20, :green}, cap: :butt, t: {60, 0}),
line_spec(@line, stroke: {20, :yellow}, cap: :round, t: {120, 0}),
]
@triangle_circle_ellipse [
triangle_spec({{0, 60}, {50, 0}, {50, 60}}, fill: :khaki, stroke: {4, :green}),
circle_spec(30, fill: :green, stroke: {6, :yellow}, t: {110, 30}),
ellipse_spec({30, 40}, rotate: 0.5, fill: :green, stroke: {4, :gray}, t: {200, 30}),
]
@text [
text_spec("Hello", translate: {0, 40}),
text_spec("World", translate: {90, 40}, fill: :yellow),
text_spec("Blur", translate: {0, 80}, font_blur: 2),
text_spec("Shadow", translate: {82, 82}, font_blur: 2, fill: :light_grey),
text_spec("Shadow", translate: {80, 80}),
]
@graph Graph.build(font: :roboto, font_size: 24)
|> mgroup([
text_spec("Various primitives and styles", translate: {15, 20}),
group_spec(@lines, t: {290, 50}),
group_spec(@triangle_circle_ellipse, t: {15, 50}),
group_spec(@text, font_size: 40, t: {130, 240}),
],
translate: {15, @body_offset}
)
# Nav and Notes are added last so that they draw on top
|> Nav.add_to_graph(__MODULE__)
|> Notes.add_to_graph(@notes)
The additions to primitive.ex
are simple. Again, I'd be happy to generate a PR.
(and I'm not wedded to the name xxx_spec
. Any suggestions welcome.)
def line_spec(points, opts) do
fn g -> line(g, points, opts) end
end
def triangle_spec(points, opts) do
fn g -> triangle(g, points, opts) end
end
def circle_spec(radius, opts) do
fn g -> circle(g, radius, opts) end
end
def ellipse_spec(radii, opts) do
fn g -> ellipse(g, radii, opts) end
end
def text_spec(text, opts) do
fn g -> text(g, text, opts) end
end
def group_spec(list, opts) when is_list(list) do
fn g ->
content = fn g ->
Enum.reduce(list, g, fn element, g -> element.(g) end)
end
group(g, content, opts)
end
end
def group_spec(item, opts) do
group_spec([item], opts)
end
def mgroup(g, list, opts \\ []) do
display_list = fn g ->
list
|> Enum.reduce(g, fn item, g -> item.(g) end)
end
group(g, display_list, opts)
end
from scenic.
This is similar in spirit to what I was trying to do with the primitives.ex helper functions. I don't have an opinion yet. Just some thoughts.
pros: Very clean to read as it looks more data-like. Hides the compile time function calls. Visually gets rid of both the fn
and &
forms and avoids that whole confusion.
cons: Makes it less clear that the primitives are being added to a graph. It loses the pipelining, which makes it obvious that a graph is being transformed with each call.
This is less clear to me. Is there enough gained in cleaning it up visually to make up for the added "magic" of hiding the fact that it is transforming a graph? The end result is the same either way. The graph is transformed and that is the final object compiled and stored into the object code.
This worry is somewhat mitigated by the mgroup
function, who's job is to accept the data format and treat it as if was the pipeline form. However, it adds a new call that effectively means there are mixed metaphors in the code.
What do you (and others) think?
from scenic.
from scenic.
add_to_graph at is definitely better.
Go for it.
from scenic.
I'm in the process of bringing this in to Scenic. Should go out in v0.10.0 next week
from scenic.
On, I'm sorry. I totally missed that is said if so that. I can still do it if you haven't started.
from scenic.
Hi Dave! If you have time to refactor more of the sample code, that would be great. I'm trying to bring in a big font metrics thing I've been working on. TrueType is a total beast. Will be nice to have tho.
Otherwise, v0.10 will go out with some scenes done the spec way, some the the pipeline way. I don't mind showing both.
from scenic.
from scenic.
That is reasonable and sounds good to me. Makes me happy in fact that the functions are working as intended!
Makes me think tho that, unlike the primitives, others should feel encouraged to make new components and make them public. Will need to document guidance on how they can have their work fit the pattern...
from scenic.
from scenic.
There is other post v0.10 work that will alleviate some of that. Namely, a responsive group, where you can specify columns and it will adjust the content (via transforms) to get the positions right. Should work across multiple screen sizes.
Also, the font_metrics I'm working on now mean that buttons can optionally resize themselves to fit the content and have better vertical centering. All the components will see some level of improvement from that work.
from scenic.
This is all in master. Going out in v.10
from scenic.
Related Issues (20)
- cursor_exit is continually sent when cursor is outside rect HOT 5
- v0.11 - no function clause matching in `Scenic.start_link/1` HOT 22
- Lootie Files HOT 2
- Handle a non-configured assets module HOT 2
- Migrate Math module to Elixir's Math module HOT 2
- Video streaming
- Deeply nested groups do not get scissored by the upper most group.
- {r, g, b} in theme throws color error when used in fill with opacity.
- primitives outside of scissor region are not removed from the input list HOT 6
- Starting the app in full screen HOT 2
- `Scene.release_input/2` may not be working HOT 2
- Mouse events for buttons beyond normal 3 do not report uniquely.
- Proposal: embed graph within scene struct HOT 6
- How to use custom fonts HOT 1
- rapid redraws of the graph have tearing HOT 24
- Text paths HOT 1
- ECS Pattern HOT 4
- Further theme work HOT 2
- Window on Linux does not get repainted HOT 1
- Not receiving input HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from scenic.