louismrose / eugenia-live

A tool for quickly prototyping graphical editors for domain-specific languages.
http://eugenialive.herokuapp.com
Eclipse Public License 1.0
8 stars 4 forks source link

Canvas Size #9

Open zolotas4 opened 10 years ago

zolotas4 commented 10 years ago

Right now the canvas width is explicitly set in source code. This should change and the canvas size should be set based on the width of the DIV element that contains it.

I've tried to make this change using Javascript, however, it doesn't work because the width of the DIV element is not explicitly set. The width of the DIV container is defined at runtime based on the span class that contains all the elements of the page (including the toolbox and the selected item properties). So, the following logic is not working:

theDiv = document.getElementById("divId"); theCanvas = document.getElementById("drawing"); theCanvas.width = theDiv.width;

If we explicitly set the DIV width then the above is working however, this is not what we want as again the width of the canvas will be hardcoded and not dynamically set based on the size of the client's screen.

JoostvanPinxten commented 10 years ago

This is quite a common problem with web-pages and canvas based pages in specific; generally, i've found that the solution is something as follows:

Also; have you tried to capture the calculated width (not the css-definition, like you are saying above) of the div with the width() method of jQuery? I.e.: $('#divId').width() should output the current (calculated) width in pixels.

zolotas4 commented 10 years ago

The first method you propose is what I've thought as the final solution. I think that this is a little bit of "hacking" so I'll will end up doing that if I can't find any other more straight solution.

I think that I tried the width() method but it didn't work. I'll try again because I am not sure.

JoostvanPinxten commented 10 years ago

Does this fiddle work for you? It works for me in the latest Firefox on Windows!

zolotas4 commented 10 years ago

I can now get the width of the div dynamically but I can't assign it to the canvas width. What I am not sure about is when the "resizing" has to take place. e.g. onload or during any other event?

JoostvanPinxten commented 10 years ago

Both, actually! Unless the resize event is triggered on rendering of the canvas div and element. I'd have to look up how the canvas inner size need to be changed to resize with, but it may also include setting some kind of parameters in the javascript; i.e. the paper.js canvas. Not sure about that, you could check out the paper.js demos and View reference!

JoostvanPinxten commented 10 years ago

This concept shows how it works with a plain canvas, but it is slow somehow... There must be something I'm overlooking... It is, however, exactly as they have done in this (old?) tutorial

zolotas4 commented 10 years ago

I will read the old tutorial and I'll tell you if I have any progress...

zolotas4 commented 10 years ago

Just and update to that. I am not sure if this is correct programming, a hack or a workaround, but this is the only thing that works:

function fixSize() {
    //the 'drawing' in our project is the HTML5 canvas and the 'canvas' is the Div element
    theDrawing = document.getElementById("drawing");
    theDiv = document.getElementById("canvas");
    theDivInitHeight = $('#canvas').height();
    theDivInitWidth = $('#canvas').width();
    theDrawing.width = theDivInitWidth;
    theDrawing.height = theDivInitHeight;
    theDrawing.style.width = theDivInitWidth+"px";
    theDrawing.style.height = theDivInitHeight+"px";
}

I did that before but what I haven't done was to re-draw the canvas. So I thought that it didn't work. When I trigger the re-draw method (right now by drawing another element) the elements are shown resized. However, if I set the width and height properties of the 'drawing' only, the re-drawn elements appear stretched. I also have to set the CSS width and height values of the canvas to make the elements keep their initial ratio.

I face the following 2 problems right now: 1) I don't know how to call the draw method from the views/drawing/show.eco file where all the above code is written. As I said, I tested it by drawing another element to force trigger the re-draw method. 2) I can't add this function to the onload event of the views/drawing/show.eco template file. Inserting a tag doesn't work. Including a window.onload(fixSize()) in the script block is not working, too. I also tried writing $(fixSize()) which works but crashes the canvas.

JoostvanPinxten commented 10 years ago

I'll try to setup Louis' new Grunt environment this weekend, I need to get back into my own code anyway. I'll also have a stab at it; there is a redraw mechanism, which I've added in my branch; Paper.js has one that can be easily called, but I cannot find it right now.

zolotas4 commented 10 years ago

Well I found it. It is as simple as that: paper.view.draw(); And it re-draws. Easy. Now, the only problem remaining is number 2...

louismrose commented 10 years ago

Hey chaps, thanks for your great work on this bug!

To answer your 2nd question Thanos, I think the best place for your code is in the render method of the Show class in controllers/drawings.coffee. From memory, I think it should work if you place it after the other code in render. You will want to convert it to coffeescript first (e.g., using http://js2coffee.org).

If that doesn't work, you might need to use window.setTimeout. We do this in palettes.coffee (see lines 113-122), because window on load and DOM ready don't work perfectly in Eugenia Live (because it's a single-page Javascript app).

HTH, and thanks again!

JoostvanPinxten commented 10 years ago

@zolotas4 I agree with @louismrose on the 2nd solution @louismrose I'd not classify this as a bug per sé, rather as a feature request ^^

zolotas4 commented 10 years ago

If I place it inside the render method the dynamic width of the div element is 0 and thus the width of the 'drawing' (the canvas is our case) is set to 0. The height which is not set dynamically, takes the correct value (400px). But if I implement it using the setTimeout Louis suggested, everything works fine. I've also finished the aesthetic part of this feature and I will upload the patch after some necessary testing that will reveal more problems....

JoostvanPinxten commented 10 years ago

I've changed the constructor of the 'Show' controller class of the Drawings package.

  class Show extends Spine.Controller
    constructor: ->
      super
      # install our resize handler on the window:
      $(window).resize(@resize)
      @active @change

    resize: () =>
      containingDiv = $('#canvas');
      canvasHeight = containingDiv.height();
      canvasWidth = containingDiv.width();
      @log canvasHeight, canvasWidth
      if paper and paper.view
        paper.view.setViewSize(canvasWidth, canvasHeight)
        paper.view.draw()

And this works quite well, as far as I can see. One of the (possible) problems here, is that the updateDrawingCache will return images with different aspect ratios?

    updateDrawingCache: =>
      @drawing.cache = @canvas.toDataURL()
      @drawing.save()

As for @zolotas4 point 2, this has also popped up with this solution. I am not quite sure when the Bootstrap code adds the widths/percentages to the divs with the fluid classes, but that would be my guess for the source of this problem. @resize() at the end of @render does not get a calculated width yet...