using System; using System.Globalization; using System.Web; using System.Drawing.Imaging; using GenLogic; namespace GraphSelectionHandler { public class GraphSelectionHandler : IHttpHandler { private static Object init_lock = new Object(); private static GlgHttpRequestProcessor request_processor = null; private static GlgObject graph = null; private static GlgDemoDataSource datasource; // Graph's datasource. static String drawing_name = "packed_bar_graph.g"; static String app_path = "GraphSelectionHandler"; static String [] legend_labels = { "server 1", "server 2", "server 3" }; static String [] axis_labels = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static String [] time_stamp_labels = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; /////////////////////////////////////////////////////////////////// public bool IsReusable { get { return false; } } /////////////////////////////////////////////////////////////////// public void ProcessRequest( HttpContext context ) { lock( init_lock ) { /* First time only: create GlgHttpRequestProcessor that properly handles ASP.NET synchronization context. ProcessRequestData is registered as a custom application-specific method used by the request processor to process HTTP requests. */ if( request_processor == null ) request_processor = new GlgHttpRequestProcessor( ProcessRequestData ); } /* Request processor will invoke ProcessRequestData method to handle application-specific logic. */ GlgHttpRequestData request_data = request_processor.ProcessRequest( context ); /* Returned data contains an image or HTML text response. If there were request processing errors, the errors will be reported in the HTML output and returned data will be null. */ if( request_data != null ) { if( request_data.image != null ) { // Save image. context.Response.ContentType = "image/png"; request_data.image.Save( context.Response.OutputStream, ImageFormat.Png ); } else if( request_data.html_response != null ) // Write html response for the tooltip. context.Response.Write( request_data.html_response ); else context.Response.Write( "Error: Unexpected response.
"); } } /////////////////////////////////////////////////////////////////// // A custom method invoked to process HTTP context. // // The HTTP context is passed in the request_data.context field. // The generated image is assigned to the data.image field. // The data.custom_data field may be used to pass additional // custom data to the ProcessRequest method. // // The GlgObject.Error method may be used in the code to flag errors. // Any errors will be reported in the generated HTML by the default // GLG error handler. // // A custom GLG error handler may be set using the // GlgObject.SetErrorHandler method inside this method. // The request_data.got_errors field may be set to true to flag errors // in case if a custom error handler is used. /////////////////////////////////////////////////////////////////// void ProcessRequestData( GlgHttpRequestData request_data ) { HttpRequest request = request_data.context.Request; // Get requested width/height of the image. int width = GetIntegerParameter( request, "width", 500 ); int height = GetIntegerParameter( request, "height", 300 ); // Limit max. size to avoid running out of heap space creating an image. if( width > 1000 ) width = 1000; if( height > 1000 ) height = 1000; bool update_data; /* Load the drawing just once and share it between all instances of this HTTP handler. */ if( graph == null ) // First time: load the drawing. { GlgObject.Init(); String path; String dir = request_data.context.Server.MapPath( "~" ); if( dir.IndexOf( app_path ) == -1 ) path = dir + app_path + "\\" + drawing_name; else path = dir + "\\" + drawing_name; graph = LoadDrawing( path ); graph.SetImageSize( width, height ); // Set graph's properties and create a demo datasource to update it. InitializeGraph( graph ); update_data = true; // Fill data just once } else // Already loaded, reuse the drawing. { graph.SetImageSize( width, height ); /* Update data only if requested. Don't update data when changing size. */ update_data = ( GetIntegerParameter( request, "update_data", 0 ) != 0 ); } // Use title from the request if supplied as a parameter. String title = request.QueryString[ "title" ]; if( title == null ) title = "Used Bandwidth"; // Default graph.SetSResource( "Title/String", title ); // Push new data into the graph. if( update_data ) UpdateGraphData(); // Setup after data update to prepare to generate image. graph.SetupHierarchy(); String action = GetStringParameter( request, "action", "GetImage" ); // Main action: Generate Image. if( action.Equals( "GetImage" ) ) { request_data.image = graph.CreateImage( null ); } // Secondary action: ProcessEvent. else if( action.Equals( "ProcessEvent" ) ) { // Get x and y coordinates of the mouse click. int x = GetIntegerParameter( request, "x", -1 ); int y = GetIntegerParameter( request, "y", -1 ); // Selection rectangle around the mouse click. GlgCube click_box = new GlgCube(); int selection_sensitivity = 0; // Extend by a few pixels if necessary. click_box.p1.x = x - selection_sensitivity; click_box.p1.y = y - selection_sensitivity; click_box.p2.x = x + selection_sensitivity; click_box.p2.y = y + selection_sensitivity; // Find selected object using named object selection. String selection_info = null; if( x > 0 && y > 0 ) { // Query array of selected objects. GlgObject selection = null; selection = GlgObject.CreateSelection( graph, click_box, graph ); // Get requested selection type, use Tooltip as default if omitted. String event_type = GetStringParameter( request, "event_type", "Tooltip" ); // Find selected bar and extract its value. selection_info = GetSelectionInfo( selection, event_type ); } request_data.html_response = ( selection_info == null ? "None" : selection_info ); } else Error( "Unsupported action!" ); } ///////////////////////////////////////////////////////////////// // Helper methods ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// int GetIntegerParameter( HttpRequest request, String name, int default_value ) { String parameter_string = request.QueryString[ name ]; if( parameter_string == null || parameter_string.Equals( "" ) ) return default_value; try { return int.Parse( parameter_string, CultureInfo.InvariantCulture ); } catch( Exception ) { Error( "Invalid parameter value for: " + name + " = " + parameter_string ); return default_value; } } ///////////////////////////////////////////////////////////////// String GetStringParameter( HttpRequest request, String name, String default_value ) { String parameter_string = request.QueryString[ name ]; if( parameter_string == null ) return default_value; else return parameter_string; } ///////////////////////////////////////////////////////////////// // Can be used only in ProcessRequestData() or methods // originating from it. ///////////////////////////////////////////////////////////////// void Error( String message ) { GlgObject.Error( GlgErrorType.USER_ERROR, message, null ); } ///////////////////////////////////////////////////////////////// GlgObject LoadDrawing( String drawing_path ) { GlgObject drawing; drawing = GlgObject.LoadWidget( drawing_path, GlgMediumType.FILE ); if( drawing == null ) { Error( "Can't load drawing: " + drawing_path ); return null; } // Disable drawing border in the image: let html define it if needed. drawing.SetDResource( "LineWidth", 0.0 ); return drawing; } ///////////////////////////////////////////////////////////////// // Demonstrates how to set various graph properties: // number of datasamples, labels, major and minor ticks, etc. // Alternatively, all graph properties other than the data may be // defined in the drawing. ///////////////////////////////////////////////////////////////// void InitializeGraph( GlgObject graph ) { // Hardcoded data just to demo a graph const double low = 0.0; const double high = 10.0; // Use 12 labels and major ticks. graph.SetDResource( "XLabelGroup/Factor", 12.0 ); // Disable minor ticks graph.SetDResource( "XLabelGroup/MinorFactor", 1.0 ); // Set the number of datasamples to 12. graph.SetDResource( "DataGroup/Factor", 12.0 ); // Set the number of values in each pack of the packed bar graph to 3. graph.SetDResource( "DataGroup/Pack/Factor", 3.0 ); // Set the range of graph's value axis. graph.SetDResource( "YLabelGroup/YLabel/Low", low ); graph.SetDResource( "YLabelGroup/YLabel/High", high ); // Set value axis format graph.SetSResource( "YLabelGroup/YLabel/Format", "%.0lf GB" ); // Set title graph.SetSResource( "Title/String", "Used Bandwidth" ); // Disable axis labels and vertical grid. graph.SetDResource( "YAxisLabel/Visibility", 0.0 ); graph.SetDResource( "XAxisLabel/Visibility", 0.0 ); graph.SetDResource( "XGridGroup/Visibility", 0.0 ); // Set the packed bar graph's legend. for( int i=0; i<3; ++i ) graph.SetSResource( "LegendObject/LegendGroup/Legend/Text" + i, legend_labels[ i ] ); // Create datasource to fill graph with demo data. datasource = new GlgDemoDataSource( low + 0.4 * ( high - low ), low + 0.7 * ( high - low ), 3, 0 ); graph.SetupHierarchy(); // Setup to prepare to receive data } ///////////////////////////////////////////////////////////////// void UpdateGraphData() { int i, j; // Push data into the graph. The packed bar graph used in the demo // displays 12 samples, each sample containing a pack of 3 values. for( i=0; i<12; ++i ) { datasource.UpdateData(); for( j=0; j<3; ++j ) graph.SetDResource( "DataGroup/EntryPoint", datasource.GetValue( j ) ); // For each datasample, fill the time stamp custom property // For this demo, it matches the time axis labels. graph.SetSResource( "DataGroup/Pack" + i + "/TimeStamp", time_stamp_labels[i] ); } // Push graph labels as well. for( i=0; i<12; ++i ) graph.SetSResource( "XLabelGroup/EntryPoint", axis_labels[i] ); } ///////////////////////////////////////////////////////////////// String GetSelectionInfo( GlgObject selection, String event_type ) { if( selection == null ) return null; // Process selection by requesting a list of all selected objects. // This allows to use out of the box graph drawing, with no need // to attach tooltip and mouse click actions to the chart's datasample // template. int size = selection.GetSize(); for( int i=0; iServer: " + ( server_index + 1 ) + "
Month: " + month + "
Bandwidth: " + GlgObject.Printf( "%.2f GB", value ); } // MouseClick: display values for all three servers. else if( event_type.Equals( "MouseClick" ) ) { double value0 = parent.GetDResource( "DataSample0/Value" ).doubleValue(); double value1 = parent.GetDResource( "DataSample1/Value" ).doubleValue(); double value2 = parent.GetDResource( "DataSample2/Value" ).doubleValue(); return "" + month + " Bandwidth" + "
" + "Server 1: " + GlgObject.Printf( "%.2f GB", value0 ) + "
Server 2: " + GlgObject.Printf( "%.2f GB", value1 ) + "
Server 3: " + GlgObject.Printf( "%.2f GB", value2 ); } else return "Unsupported event_type"; } return null; } } }