1

I am using c3.js, AngularJs and bootstrap to render some charts. The setup is as follows:

  1. Bind a variable to <select> form to change between chart types

  2. I have a $watch on the same variable which triggers the chart rendering.

  3. Depending on variable I render multiple charts, different types depending on it's value. I have two charts per row, each one inside a col-XX-6.
  4. Each chart group is hidden/shown using ng-show="myVariable== 'typeX'" depending on the same variable that triggers the render.

So, view and c3 render are acting on the same variable.

The first render is triggered by watch on $viewContentLoaded and everything works fine. After I change the select option, the first chart in the column renders with 100% width, disregarding bootstrap template. My theory is that c3.js renders the chart "too fast", before the view kicks in and sets the proper width. Further investigation:

  • Adding a $timeout on renderer fixes the problem but this is unacceptable solution
  • Adding a fixed width on charts works but is not acceptable, it needs to adapt to bootstrap
  • So far it seems that the only solution is to listen to the actual DOM change to see when the DOM actually becomes visible and only then start the render. But it seems that this technique is highly discouraged.

How do I fix this problem the proper way?

Edit 1: It seems that even if I render all the charts once and never refresh them, they still rarely but randomly oversize when shown.

Edit 2: Plunkr: http://plnkr.co/edit/mU5m694VoDB5GtXrmPdP

Plunkr works (...) but basically, it happens to me when you'd switch from type2 to type1, the first graph would take 100% width and mess up everything. I'll see if I can find something in Plunkr that would make it break.

Edit 3: Well, perhaps not working that well afterall. I noticed charts sometimes do not render (blank page) and they only appear after I inspect element or fiddle with the screen in some way. Seems like it could be the same problem behind this. You should increase the plunker preview to simulate a wider screen.

cen
  • 2,873
  • 3
  • 31
  • 56
  • Further research suggests that $timeout with only first parameter will execute after current digest and after DOM render but in my case it seems to behave randomly. Sometimes works, sometimes does not. http://stackoverflow.com/questions/16066239/defer-angularjs-watch-execution-after-digest-raising-dom-event – cen Jul 29 '15 at 07:23
  • can you add a fiddle or plunker – Code Warrior Jul 29 '15 at 13:34
  • Added plunker which magically works.. I'll see if I can make it break. – cen Jul 29 '15 at 18:34
  • 1
    Reproduceable using your Plunkr by : A. Select type2. B. Resize the window. C. Select type1. Nothing is rendered, until another manual window resize. – Qi Fan Oct 07 '15 at 18:25

1 Answers1

0

You mention that you are having problems with initial size, but actually, there is going to be problems when browser size changes too.

We use d3.js (not c3) extensively in our project, and we found that the best option is to set viewBox attribute of svg element created by d3 to the parent element's size when browser size change event is emitted by window.

viewBox basically translates coordinate system of svg to origin and size defined by it.

mostruash
  • 4,169
  • 1
  • 23
  • 40
  • No viewBox on my svg element but it does have width. And it seems to scale according to the window change. How do you actually listen to window change event? Using $watch? – cen Jul 29 '15 at 18:43
  • Actually you can bind resize event for parent element too. See http://stackoverflow.com/questions/599288/cross-browser-window-resize-event-javascript-jquery – mostruash Jul 29 '15 at 19:09