Open ccorcos opened 9 years ago
You have multiple options:
engine.solve({a: 123, b: 321})
, described on http://gridstylesheets.org/guides/ccss/). This is efficientengine.solve(GSS.Parser.parse(string).commands)
engine.solve(['==', ['get', ['tag', 'div'], 'width'], ['get', 'shared-width']])
for div[width] == shared-width
. We're making an update to simplify AST representation for complex selectors , so it will be more approachable. There're two optional arguments for engine.solve
when you use it with tree: continuation and scope. Continuation is a string path, which can be passed to engine.remove(continuation)
to undo constraints. Cassowary instance are destroyed automatically for you when all continuation keys were removed. Last argument is a scope, which will be used to scope all your variables as properties (e.g engine.solve(['==', ['get', 'a'], 100], '', '$test')
will produce '$test[a]' variable, so you can use the same AST tree for multiple different instances of objects.
In case you don't want to use DOM, you may bypass most of gss completely via engine.update([{key: continuation}, ['get', '$my-id[width]', ['get', 'a']]])
. We use it for worker internally. It detects dependency graphs, and creates multiple cassowaries for you. Use engine.remove(continuation)
to clean things up.
Another example of GSS JavaScript API usage: https://github.com/gss/engine/blob/2.1.x/spec/nodejs/smoke.coffee (running on Node.js, no DOM needed!)
Ok. Suppose I want to use the parser so I can write something like #gss[width] + #cassowary[width] == 350
. How do I get CSS rules from this? Or if its done with javascript, how are those rules enforced?
GSS.Parser.parse(text).commands
will output an AST that you can pass to engine.solve()
as a first argument. There was a typo in my previous comment, it seems you have to use .commands
property to access the actual AST as of now
ok, and engine.solve will keep the dom updated?
Yes. It will observe DOM via MutationObserver and update values if new constraints were added or removed. Basically engine.solve(operation, continuation, scope)
, engine.remove(continuation)
and engine.addEventListener('solve', ...)
is most like you only things you will ever need to use.
Hi there, I've also been playing around with dynamically adding constraints in js, but I've been having problems. I thought I understood Inviz's recipe, but it seems like I don't, and hunting around the GSS 'engine' and 'document' code hasn't helped. I hope you don't mind if I ask some more details.
Here is what I imagine doing:
I've hacked together a Plunkr to do that -- http://plnkr.co/edit/HDui1UQqznAa141JkuSQ At least, I hoped it would do that.
I ran into the following problems, though:
Of course, I am perfectly aware that both of these simple examples can be solved in much simpler ways. They were just the most basic ways I could come up with to illustrate my problems.
Sorry about the basic questions. If there is some documentation of how to interact with GSS in JS that would answer all of them, please feel free just to send me there -- I looked for such documentation, but couldn't find it.
A not-very-related (hopefully small) question : it seems one keeps track of the GSS engine lifecycle by listening to events: is there a list of such events, and a description of the actual GSS lifecycle anywhere?
Thanks in advance for any help!
Hey. Sorry, it's my bad. I think I didnt rewire engine.remove
back properly when we split engine & document. It doesnt update DOM query storage, but only cleans up constraints (which we have tests for). I used this custom remove function:
engine.$remove = function(key) {
engine.solve(function() { // open transaction
engine.input.Query.prototype.unobserve(this, key); // remove observers
engine.input.Query.prototype.clean(this, key); // remove current queries
this.remove(key) // remove all globals if any
})
}
http://plnkr.co/edit/B4qNo4GXMqg35JqIofAj?p=preview
We use events very sparringly in GSS. You can find all of then in Engine.coffee
file in engine repo in commit() function. They just represent certain parts of (cycling) workflow. Only other even we do is remove
which is called for each removed string path
Continuation is a string that represents path in GSS source. I think you got that right. Your effects have global continuation like leftKey
, while .panel
selector will have continuation leftKey.panel$element-id
To push element further and further down, use suggested variables (see docs). Basically you'll have a static constraint like:
.panel[top] >= $my-special-value
then do engine.solve({'my-special-value': 100})
. For best results, make sure you initialize engine with this object so variables have some initial values, otherwise GSS will try to solve them
http://plnkr.co/edit/OIz47SIjlHKtf3flaQCe?p=preview Here's your code working without changes working on latest ranges2
branch of document. I fixed the bug. Please use that branch for now.
That's brilliant! Thanks a lot. I hope you don't mind me asking some more clarifying questions:
As to pushing the element down. I'm afraid I didn't do a very good job of explaining the point of including that button: what confuses me is that I don't seem to be able to call solve multiple times and have it have an effect. You are, of course, perfectly correct that pushing down the element can be done much more elegantly (and presumably, also with better performance) by having a single constraint with a variable that one then changes (thanks, btw, to whomever wrote the relevant documentation here: http://gridstylesheets.org/guides/ccss/) but I was playing around with adding constraints dynamically, and noticed that sometimes solve just didn't seem to act after the first constraint was added. The 'pushing down' example was the simplest I could come up with to illustrate that -- I would love to understand why it doesn't work. After all, putting something (admittedly retarded) like:
.something[top]>=::window[top];
.something[top]>=::window[top]+10;
into a gss script works perfectly well.
Ok, that is enough for now. Thanks again for your help.
1) solve()
s first argument is a problem
- either transaction closure, suggested values object or AST (which is fairly clean in itself, you might want to write it by hand instead of generating strings. Then if there's a problem argument, a following function argument might be treated as callback.You can also use engine.then()
which is the same as engine.once('solve',...)
. Unless you use workers, everything's computed synchronously - so you dont actually need to wait in most cases (as you did with outputting results of solution). I think you can remove + add constraints within a single transaction. and it wont redraw intermediate state.
https://github.com/gss/document/blob/master/src/Document.coffee#L267-L276 Here's an example of transaction used to update multiple outside values in a single tick
2) In theory the way you use lowerAST should work, but it doesnt right now, I think because of DOM Query module mishap - it consider there were no updates in .panel
collection and kinda bails out. The remedy again would be to use unique continuation strings for each source of side effect, and clean them up as well. It doesnt happen internally, because system generates unique paths during evaluation. But in your case there's just a .panel
query. I plan to revisit Query module and will think how to deal better with this problem.
Ok, thanks a lot. I made a simple change as you suggested to the plunkr, to add a unique key to each new constraint, and it works perfectly. For the sake of anyone else who stumbles on this thread, here's the result: http://plnkr.co/edit/F9LZtyk4J45EuSeRQpMN . I think I don't quite understand what continuations really are, though. I was under the impression that they were just keys, but when I tried to use a number as a continuation, the engine complained. Are they actually more subtle than just keys? And what types are accepted as continuations?
I don't think I completely understand how to use and build transactions either, but I think that's more my fault than anything else. I guess I've got some code to read...
Thanks again for all your help!
@Inviz I played around with raw cassowary tonight and it doesn't have all the layout niceness you get from GSS. Particularly if you absolutely position everything, you can't use the native layout engine for text rendering... How does GSS deal with this?
Is it possible to code up all these constraints using javascript?