Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    SmartClient/HighChart integration

    Hi,

    I'm trying to integrate the HighChart graphics library with SmartClient 8.2p (2012-08-14).

    What I did is have a new class created which extends Canvas and use HighChart to render
    inside the DOM with chart.renderTo = Canvas.getHandle();

    The problem I have is that when I do hide() on my Canvas, there is some bleeding (bleed-through)
    on both IE and Firefox ...

    The only way, I'm able to fix this is issuing a destroy() and re-create() on my Canvas, which is
    something I'd rather avoid, since this isn't what happens under the hood whenever my layouts
    get resized, etc.

    Any idea on how this should be handled ? Following is a simple test bed you can use to reproduce
    what I'm seeing.

    Thanks,

    Code:
    <HTML>
    	<HEAD>
    <SCRIPT>
    window.isomorphicDir = 'isomorphic/';
    </SCRIPT>
    
    		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    		<script type="text/javascript" src="http://code.highcharts.com/highcharts.js"></script>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_Core.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_Foundation.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_Containers.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_Grids.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_Forms.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/system/modules/ISC_DataBinding.js"></SCRIPT>
    		<SCRIPT SRC="isomorphic/skins/MEI/load_skin.js"></SCRIPT>
    
    		<TITLE>Investigation - Highcharts bleeding</TITLE>
    	</HEAD>
    
    	<BODY STYLE="overflow:hidden">
    		<SCRIPT>
    
    		//--------------------------------------------------------------------------------------------------------------------------------
    		/**
    		 * Wrapper/bridge class for Highcharts (http://www.highcharts.com/).
    		 */
    		//--------------------------------------------------------------------------------------------------------------------------------
    		var BaseChart = isc.defineClass('BaseChart', 'Canvas');
    
    		//-----------------------------
    		//Instance class members
    		//-----------------------------
    		BaseChart.addProperties( /** @lends BaseChart.prototype */
    		{
    			//-----------------------------
    			// Properties
    			//-----------------------------
    
    			autoDraw : true,
    
    			/**
    			 * Highcharts' native object. Becomes non-null via _afterInitWidget().
    			 * 
    			 * @field
    			 * @type Object
    			 * @default null
    			 */
    			highchartsObj : null,
    
    			/**
    			 * Options given to Highcharts.chart(). Mandatory parameter for create().
    			 * 
    			 * @field
    			 * @type Object
    			 * @default null
    			 */
    			renderOptions : null,
    
    			//-----------------------------
    			// Methods
    			//-----------------------------
    
    			//----------------------------------------------------------------------------------------------------------------------------
    			/**
    			 * Initializes the object. Overrides the ISC framework <b>initWidget()</b> method. This method is called automatically
    			 * by the ISC framework when this object gets created. This method must not be called explicitly.<br><br>
    			 *
    			 * @inner
    			 * @return {void}
    			 */
    			//----------------------------------------------------------------------------------------------------------------------------
    			initWidget : function()
    			{
    				this.Super('initWidget', arguments);
    
    				// We must allow initWidget() to completely "unstack" before calling _afterInitWidget() so 
    				// a call to this.getHandle() will not return null.
    				Class.delayCall('_afterInitWidget', [], 0, this);
    			},
    
    			// ----------------------------------------------------------------------------------------------------------------------------
    			/**
    			 * Method to allow a chart to adjust the default render options before they are provided to Highcharts
    			 */
    			// ----------------------------------------------------------------------------------------------------------------------------
    			_adjustDefaultRenderOptions : function(defaultRenderOptions)
    			{
    				return defaultRenderOptions;
    			},
    
    			//----------------------------------------------------------------------------------------------------------------------------
    			_afterInitWidget : function()
    			{
    				if (!this.renderOptions)
    				{
    					this.renderOptions = this._getDefaultRenderOptions();
    				}
    
    				if (!this.renderOptions.chart) {
    					this.renderOptions.chart = {};
    				}
    
    				if (!this.renderOptions.credits)
    				{
    					this.renderOptions.credits =
    					{
    						enabled : false
    					};
    				}
    
    				if (!this.renderOptions.title)
    				{
    					this.renderOptions.title = null;
    				}
    
    				// We always override the handle that will contain the chart (in case there is a difference).
    				this.renderOptions.chart.renderTo = this.getHandle();
    
    				this.highchartsObj = new Highcharts.Chart(this.renderOptions);
    				this.highchartsObj.meiObj = {};
    			},
    
    			//----------------------------------------------------------------------------------------------------------------------------
    			/**
    			 * Method that can be overriden for a specialized chart.
    			 *
    			 * We set the the tooltips' default padding not to lose it (http://highslide.com/forum/viewtopic.php?f=9&t=10398)
    			 * 
    			 * @inner
    			 * @return The default render options used by HighCharts.
    			 */
    			//----------------------------------------------------------------------------------------------------------------------------
    			_getDefaultRenderOptions : function()
    			{
    				var returnValue = {
    					tooltip: {
    						style: {
    							padding: 5
    						}
    					}
    				};
    
    				return returnValue;
    			},
    
    			//----------------------------------------------------------------------------------------------------------------------------
    			/**
    			 * Hook to tell Highcharts to resize.
    			 * 
    			 * @inner
    			 * @return {void}
    			 */
    			//----------------------------------------------------------------------------------------------------------------------------
    			resized : function()
    			{
    				this.Super('resized', arguments);
    
    				this.resizeHighcharts();
    			},
    
    			//----------------------------------------------------------------------------------------------------------------------------
    			/**
    			 * This method is a hook to call HighCharts' setSize() method so the chart
    			 * uses the appropriate area.
    			 * 
    			 * @inner
    			 * @return {void}
    			 */
    			//----------------------------------------------------------------------------------------------------------------------------
    			resizeHighcharts : function()
    			{
    				if (this.highchartsObj)
    				{
    					this.highchartsObj.setSize(this.getInnerWidth(),this.getInnerHeight());
    				}
    			}
    		});
    
    		//----------------------------------------------------------------------------------------------------------------------------
    		function createChart(chartOptions, chartData)
    		{
    			var baseOptions = {};
    			var allOptions = isc.addProperties(baseOptions, chartOptions);
    
    			var largestValue = chartData.max();
    
    			var chartRenderOptions = 
    				{
    	    			chart:
    	    			{
    	    				backgroundColor : null,
    						width : allOptions['width'],
    	    				height : allOptions['height'],
    	                    type : 'bar' // With a bar chart, the series MUST be provided to the constructor.
    	                },
    	                title: { text: null },
    	                xAxis:
    	                {
    	                    categories:
    	                	[
    	                		'Fcst',
    	                		'Exp',
    	                		'Act'
    	            		]
    	                },
    	                yAxis: {
    	                    title: { text: null },
    	                    labels: { enabled : false },
    	                    max : largestValue,
    	                    endOnTick : false
    	                },
    	                legend : { enabled : false },
    	                tooltip: {
    	                    formatter: function()
    	                    {
    	                        return '<b>Spend ' + this.point.category + '*</b><br/>' + this.point.y;
    	                    }
    	                },
    	                series: [ { data: chartData } ]
    				};
    
    			var chart =
    				BaseChart.create
    				({
    					width : allOptions['width'],
    					height : allOptions['height'],
    					renderOptions : chartRenderOptions
    				});
    
    			return chart;
    		}
    
    		//----------------------------------------------------------------------------------------------------------------------------
    		// main
    		//----------------------------------------------------------------------------------------------------------------------------
    		
    		var chartMember = createChart({width : 300, height : 200}, [120, 200, 180]);
    		var hideButton = IButton.create({ title : "Hide chart", click : 'chartMember.hide();' });
    		var showButton = IButton.create({ title : "Show chart", click : 'chartMember.show();' });
    		var destroyButton = IButton.create({ title : "Destroy chart", click : 'chartMember.destroy();' });
    
    		VLayout.create({
    			members :
    				[
    					chartMember,
    					hideButton,
    					showButton,
    					destroyButton
    				]
    		})
    		</SCRIPT>
    	</BODY>
    </HTML>

    #2
    getHandle() is an internal API and definitely the wrong approach. Instead, use getInnerHTML() to write out a DIV *inside* the Canvas, and replace that.

    The burn-through suggests that the charting engine is using IFrames or other special DOM elements where browsers have lots of bugs. There's an internal, undocumented property canvas.hideUsingDisplayNone that may work around this at the expense of possibly crashing older / lower quality browsers.

    Also, bear in mind that the built-in FacetChart is being rapidly enhanced, and certain features like drag and drop onto charts won't be feasible with HighCharts without a lot of low-level hacking.

    Comment


      #3
      The hideUsingDisplayNone fixed our problem. Thanks!

      Comment


        #4
        Hi, would you please post your solution for this.
        I m struggling from the same issue.

        Thank you very much

        Comment


          #5
          Hi,

          As stated in my reply, I applied Isomorphic's recommendation of setting hideUsingDisplayNone = true
          on my Canvas derived class and that did the trick. The complete code is the one I posted already in this thread
          plus the addition of that extra boolean.

          That's it and seem to be working great ...

          Kind regards,

          Comment


            #6
            Thank you very much !
            I did it with div trick at changed event for the canvas.

            Thanks again

            Comment


              #7
              sorry resized event :)

              Comment

              Working...
              X