namespace CairoChart { public class Legend { public enum Position { TOP = 0, // default LEFT, RIGHT, BOTTOM } public Position position = Position.TOP; public Font.Style font_style = Font.Style(); public Color bg_color = Color(1, 1, 1); public Line.Style border_style = Line.Style (); public double indent = 5; public double width = 0; public double height = 0; public double line_length = 30.0; public double text_hspace = 10.0; public double text_vspace = 2.0; public bool show = true; public Legend copy () { var legend = new Legend (); legend.position = this.position; legend.font_style = this.font_style; legend.bg_color = this.bg_color; legend.indent = this.indent; legend.height = this.height; legend.line_length = this.line_length; legend.text_hspace = this.text_hspace; legend.text_vspace = this.text_vspace; legend.width = this.width; legend.show = this.show; legend.max_font_heights = this.max_font_heights; return legend; } public Legend () { border_style.color = Color (0, 0, 0, 0.3); } public virtual void draw (Chart chart) { process (chart, ProcessType.CALC); process (chart, ProcessType.DRAW); } public virtual void draw_rect (Chart chart, out double x0, out double y0) { x0 = y0 = 0.0; if (chart.context != null) { switch (position) { case Position.TOP: x0 = (chart.width - width) / 2; y0 = chart.title_height; break; case Position.BOTTOM: x0 = (chart.width - width) / 2; y0 = chart.height - height; break; case Position.LEFT: x0 = 0; y0 = (chart.height - height) / 2; break; case Position.RIGHT: x0 = chart.width - width; y0 = (chart.height - height) / 2; break; } chart.set_source_rgba(bg_color); chart.context.rectangle (x0, y0, width, height); chart.context.fill(); border_style.set(chart); chart.context.move_to (x0, y0); chart.context.rel_line_to (width, 0); chart.context.rel_line_to (0, height); chart.context.rel_line_to (-width, 0); chart.context.rel_line_to (0, -height); chart.context.stroke (); } } public enum ProcessType { CALC = 0, // default DRAW } double [] max_font_heights; public virtual void process (Chart chart, ProcessType process_type) { var legend_x0 = 0.0, legend_y0 = 0.0; var heights_idx = 0; var leg_width_sum = 0.0; var leg_height_sum = 0.0; double max_font_h = 0.0; // prepare switch (process_type) { case ProcessType.CALC: width = 0.0; height = 0.0; max_font_heights = {}; heights_idx = 0; break; case ProcessType.DRAW: draw_rect(chart, out legend_x0, out legend_y0); break; } foreach (var s in chart.series) { if (!s.zoom_show) continue; var title_sz = s.title.get_size(chart.context); // carry switch (position) { case Position.TOP: case Position.BOTTOM: var ser_title_width = title_sz.width + line_length; if (leg_width_sum + (leg_width_sum == 0 ? 0 : text_hspace) + ser_title_width > chart.width) { // carry leg_height_sum += max_font_h; switch (process_type) { case ProcessType.CALC: max_font_heights += max_font_h; width = double.max(width, leg_width_sum); break; case ProcessType.DRAW: heights_idx++; break; } leg_width_sum = 0.0; max_font_h = 0; } break; } switch (process_type) { case ProcessType.DRAW: var x = legend_x0 + leg_width_sum + (leg_width_sum == 0.0 ? 0.0 : text_hspace); var y = legend_y0 + leg_height_sum + max_font_heights[heights_idx]; // series title chart.context.move_to (x + line_length, y); chart.set_source_rgba (s.title.color); s.title.show(chart.context); // series line style chart.context.move_to (x, y - title_sz.height / 2); s.line_style.set(chart); chart.context.rel_line_to (line_length, 0); chart.context.stroke(); Marker.draw_at_pos (chart, s.marker_type, x + line_length / 2, y - title_sz.height / 2, chart.marker_size); break; } switch (position) { case Position.TOP: case Position.BOTTOM: var ser_title_width = title_sz.width + line_length; leg_width_sum += (leg_width_sum == 0 ? 0 : text_hspace) + ser_title_width; max_font_h = double.max (max_font_h, title_sz.height) + (leg_height_sum != 0 ? text_vspace : 0); break; case Position.LEFT: case Position.RIGHT: switch (process_type) { case ProcessType.CALC: max_font_heights += title_sz.height + (leg_height_sum != 0 ? text_vspace : 0); width = double.max (width, title_sz.width + line_length); break; case ProcessType.DRAW: heights_idx++; break; } leg_height_sum += title_sz.height + (leg_height_sum != 0 ? text_vspace : 0); break; } } // TOP, BOTTOM switch (position) { case Position.TOP: case Position.BOTTOM: if (leg_width_sum != 0) { leg_height_sum += max_font_h; switch (process_type) { case ProcessType.CALC: max_font_heights += max_font_h; width = double.max(width, leg_width_sum); break; } } break; } switch (process_type) { case ProcessType.CALC: height = leg_height_sum; switch (position) { case Position.TOP: chart.cur_y_min += height; break; case Position.BOTTOM: chart.cur_y_max -= height; break; case Position.LEFT: chart.cur_x_min += width; break; case Position.RIGHT: chart.cur_x_max -= width; break; } break; } } } }