Plugin Directory

Changeset 700167


Ignore:
Timestamp:
04/19/2013 09:25:46 AM (13 years ago)
Author:
thmufl
Message:

Donut charts, interpolation and animation added

Location:
ipu-chart
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • ipu-chart/trunk/ipu-chart.php

    r695096 r700167  
    33    Plugin Name: IPU-Chart
    44    Plugin URI: https://www.ipublia.com/ipu-chart
    5     Description: Creates SVG based charts out of your CSV data. Currently supports bar, pie and line charts.
     5    Description: Creates SVG based charts out of your CSV data. Currently supports bar, pie, donut and line charts.
    66    Author: ipublia, Thomas Müller Flury
    7     Version: 0.2
     7    Version: 0.3
    88    Author URI: https://www.ipublia.com/author/thmufl/
    99    Text Domain: ipuchart
     
    1111 */
    1212
     13function plugin_get_version() {
     14    require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
     15    $plugin_data = get_plugin_data( __FILE__ );
     16    $plugin_version = $plugin_data['Name'] . ', Version ' . $plugin_data['Version'];
     17    return $plugin_version;
     18}
     19
     20// This is the csv tag
    1321function ipu_csv_func($atts, $content = null) {
    1422    extract(shortcode_atts(array(
     
    2432}
    2533
     34// This is the chart tag
    2635function ipu_chart_func($atts) {
    2736    extract(shortcode_atts(array(
     
    3746        'description' => 'Set a description',
    3847        'sort' => 'none',
     48        'interpolate' => 'linear',
     49        'animate' => 'none',
    3950        'img' => '',
    4051        'debug' => 'false'
    4152    ), $atts));
    4253   
    43     return ipu_render_chart($id, $csv, $type, $category, $value, $format, $color, $style, $title, $description, $sort, $img, $debug);
     54    return ipu_render_chart($id, $csv, $type, $category, $value,
     55                            $format, $color, $style,
     56                            $title, $description, $sort, $interpolate, $animate,
     57                            $img, $debug, plugin_get_version());
    4458}
    4559
     60// This is the table tag
    4661function ipu_table_func($atts) {
    4762    extract(shortcode_atts(array(
     
    6075
    6176function ipu_render_csv($id, $content) {
    62 
    6377    return "<div id='{$id}' class='csv' style='display:none;white-space:pre;'>{$content}</div>";
    6478}
    6579
    66 function ipu_render_chart($id, $csv, $type, $category, $value, $format, $color, $style, $title, $description, $sort, $img, $debug) {
     80function ipu_render_chart($id, $csv, $type, $category, $value, $format, $color, $style, $title, $description, $sort, $interpolate, $animate, $img, $debug, $version) {
    6781    return "<figure id='{$id}' class='chart'>
    6882                <script type='text/javascript'>
    69                 renderChart('{$id}', '{$csv}', '{$type}', '{$category}', '{$value}', '{$format}',
    70                             '{$color}', '{$style}', '{$title}', '{$description}', '{$sort}', '{$img}', '{$debug}');
     83                renderChart('{$id}', '{$csv}', '{$type}', '{$category}', '{$value}',
     84                            '{$format}', '{$color}', '{$style}',
     85                            '{$title}', '{$description}', '{$sort}', '{$interpolate}', '{$animate}',
     86                            '{$img}', '{$debug}', '{$version}');
    7187                </script>
    7288            </figure>";
     
    7490
    7591function ipu_render_table($id, $csv, $title, $debug) {
    76    
    7792    return "<table id='{$id}' class='chart-data'>
    7893                <script type='text/javascript'>                 
  • ipu-chart/trunk/js/ipu-chart.js

    r695096 r700167  
    99    tooltip;
    1010
     11function toArray(l) {
     12    ll = l.split(',');
     13    for(var i=0; i<ll.length; i++) {
     14        ll[i] = ll[i].trim();
     15    }
     16    return ll;
     17}
     18
    1119function parserFor(format) {
    12     format = format.toLowerCase().trim();
     20    format = format.trim();
    1321    if(format == "i" || format == "integer") return parseInt;
    1422    if(format == "f" || format == "float") return parseFloat;
    1523    if(format == "s" || format == "string") return function(s) { return s; };
    16     if(format == "yyyy-mm-dd" || format == "date") return d3.time.format("%Y-%m-%d").parse;
     24   
     25    if(format == "yyyymmdd" || format == "d" || format == "date") return d3.time.format("%Y%m%d").parse;
     26    if(format == "yyyy-mm-dd") return d3.time.format("%Y-%m-%d").parse;
    1727    if(format == "yy-mm-dd") return d3.time.format("%y-%m-%d").parse;
    1828    if(format == "yyyy/mm/dd") return d3.time.format("%Y/%m/%d").parse;
     
    2030    if(format == "dd.mm.yyyy") return d3.time.format("%d.%m.%Y").parse;
    2131    if(format == "dd.mm.yy") return d3.time.format("%d.%m.%y").parse;
     32   
    2233    return d3.time.format(format).parse;
    2334}
    2435 
    2536function scaleFor(format) {
    26     format = format.toLowerCase().trim();
     37    format = format.trim();
    2738    if(format == "i" || format == "integer") return d3.scale.linear();
    2839    if(format == "f" || format == "float") return d3.scale.linear();
     
    3041    return d3.time.scale();
    3142}
    32  
    33 function renderChart(id, csv, type, category, value, format, color, style, title, description, sort, img, debug) {
    34    
    35     var debug = (debug.toLowerCase() == "true");
    36     if(debug) { console.log("---------- START RENDERING CHART (" + id + ", " + csv + ", " + type + ") ----------"); };
     43
     44function parseData(data, category, value, format, debug) { 
     45    // Parse the datatypes 
     46    for(var i = 0; i < data.length; i++) {
     47        for(var j = 0; j < category.length; j++) {
     48            data[i][category[j]] = parserFor(format[j])(data[i][category[j]]);
     49        }
     50        for(var j = 0; j < value.length; j++) {
     51            data[i][value[j]] = parserFor(format[category.length + j])(data[i][value[j]]);
     52        }
     53    }
     54    return data;   
     55}
     56
     57function colorScale(color) {
     58    if(color[0].toLowerCase().trim() == "auto") {
     59        color = d3.scale.category20();
     60    } else {
     61        color=d3.scale.ordinal().range(color);
     62    }
     63    return color;
     64}
     65
     66function renderNoSvgSupport(figure, img) {
     67   
     68    figure.select("svg").remove();
     69   
     70    if(img && img.trim() != "") {
     71        image = figure.append("img")
     72            .attr("src", img)
     73            .attr("width", parseInt(figure.style("width")))
     74            .attr("height", parseInt(figure.style("height")) - 40);
     75    } else {
     76        figure.append("p")
     77            .text("Sorry, can't display the chart. Use a newer, SVG enabled browser.")
     78            .attr("style", "color: red;");
     79        figure.attr("style", "border: 1px solid lightgray; padding: 1em;");
     80    }
     81}
     82
     83function renderError(figure, error) {
     84    figure.select("svg").remove();
     85    figure.append("p")
     86        .text(error)
     87        .attr("style", "color: red;");
     88    figure.attr("style", "border: 1px solid lightgray; padding: 1em;");
     89    return false;
     90}
     91
     92function createFigureElement(id, title, description, style) {
     93    var figure = d3.select('#' + id);   
     94    figure.attr("style", style);
     95
     96    var svg = figure.append("svg");
     97   
     98    svg.append("g")
     99        .attr("class", "meta")
     100        .append("title").text(title)
     101        .append("description").text(description);
     102       
     103    figure.append("figcaption").text(title);   
     104
     105    var width = parseInt(figure.style("width")),
     106        height = parseInt(figure.style("height")) - parseInt(figure.select("figcaption").style("height")) - 20;
     107           
     108    svg.attr("viewBox", "0 0 " + width + " " + height)
     109        .attr("preserveAspectRatio", "xMidYMid meet")
     110        .attr("width", width)
     111        .attr("height", height)
     112        .append("g")
     113            .attr("class", "main");
     114   
     115    return figure;
     116}
     117
     118function createTooltip() {
     119    if(tooltip == null) {
     120        tooltip = d3.select("body").append("div")
     121            .attr("class", "iputooltip")
     122            .style("opacity", 0.0)
     123            .style("width", function() {return screen.width > 320 ? "260px" : "160px"; })
     124            .html("<p>tooltip</p>")
     125            .on("touchstart", hideTooltip);
     126    }
     127    return tooltip;
     128}
     129
     130function renderChart(id, csv, type, category, value, format, color, style, title, description, sort, interpolate, animate, img, debug, version) {
     131   
     132    debug = (debug.toLowerCase() == "true");
     133
    37134    if(debug) {
    38135   
     
    42139                    + "\n\tSVG support: " + svgSupport
    43140                    + "\n\tscreen width/height: " + screen.width + "px/" + screen.height + "px");
     141                   
     142        console.log("PLUGIN: "
     143                    + "\n\t" + version);
    44144                   
    45145                   
     
    56156                    + "\n\tdescription: " + description
    57157                    + "\n\tsort: " + sort
     158                    + "\n\tinterpolate: " + interpolate
     159                    + "\n\tanimate: " + animate
    58160                    + "\n\timg: " + img
    59161                    + "\n\tdebug: " + debug);
    60162    }
    61163   
    62     if(!svgSupport) {
    63        
    64         var figure = d3.select('#' + id);
    65         figure.attr("style", style);           
    66 
    67         if(img && img.trim() != "") {
    68             var width = parseInt(figure.style("width")),
    69                 height = parseInt(figure.style("height")) - 40;
    70 
    71             figure.append("figcaption").text(title);       
    72             image = figure.append("img")
    73                 .attr("src", img)
    74                 .attr("width", width)
    75                 .attr("height", height);
    76         } else {
    77             figure.append("p").text("Chart: '" + title + "'");
    78             figure.append("p")
    79                     .text("Please use a newer, SVG capable browser to view the chart.")
    80                     .attr("style", "color: red; ");
    81             figure.attr("style", "border: 1px solid lightgray; padding: 1em;");
    82         }
    83        
    84     } else {
    85         load(id, csv, type, category, value, format, color, style, title, description, sort, img, debug);
    86     }
    87 }
    88 
    89 function load(id, csv, type, category, value, format, color, style, title, description, sort, img, debug) {
    90    
     164    var figure = createFigureElement(id, title, description, style);
     165
     166    if(!svgSupport) return renderNoSvgSupport(figure, img);
     167       
     168    createTooltip();
     169   
     170    category = toArray(category);
     171    value = toArray(value);
     172    format = toArray(format);
     173    color = toArray(color);
     174    animate = toArray(animate);
     175   
     176    if(animate[0] == "slow") animate = ["5000", "linear"];
     177    else if(animate[0] == "medium") animate = ["2000", "linear"];
     178    else if(animate[0] == "fast") animate = ["1000", "linear"];
     179   
    91180    if((/^#/).test(csv)) {
    92         div = d3.select(csv),
    93         data = d3.csv.parse(div.text());
    94         if(debug) { console.log("LOADING DATA SYNC (" + csv + ")"); console.log(data); }
    95         render(id, data, type, category, value, format, color, style, title, description, sort, img, debug);           
     181        if(d3.select(csv).empty()) {
     182            return renderError(figure, "The csv '" + csv + "' does not exist in this document.");
     183        }   
     184        data = d3.csv.parse(d3.select(csv).text());
     185        if(debug) { console.log("Loaded data (sync): "); console.log(data) };
     186       
     187        render(figure, data, type, category, value, format, color, sort, interpolate, animate, debug);
     188       
    96189    } else {
    97190        d3.csv(csv, function(error, data) {
    98             if(debug) { console.log("LOADING DATA ASYNC (" + csv + ")"); console.log(data); }
    99             if(error) return console.warn(error);
    100             render(id, data, type, category, value, format, color, style, title, description, sort, img, debug);           
    101         });     
     191            if(error) {
     192                console.warn("There was an error loading the data: " + error);
     193                return renderError(figure, "There was an error loading the data: " + csv);
     194            }
     195            if(debug) { console.log("Loaded data (async): "); console.log(data) };
     196            render(figure, data, type, category, value, format, color, sort, interpolate, animate, debug);
     197        });             
    102198    }
    103  }
    104  
    105 function render(id, data, type, category, value, format, color, style, title, description, sort, img, debug) {
    106     if(debug) { console.log("RENDER (" + id + ")"); };
    107        
    108     formats = format.split(',');
    109     for(var i=0; i<formats.length; i++) {
    110         formats[i] = formats[i].trim();
    111     }
    112 
    113     if(debug) { console.log("FORMATS: " + formats); }
    114    
    115     if(color.toLowerCase().trim() == "auto") {
    116         colors = d3.scale.category20();
    117     } else {
    118         colors = color.split(',');
    119         for(var i=0; i<colors.length; i++) {
    120             colors[i] = colors[i].trim();
    121         }
    122         colors=d3.scale.ordinal().range(colors);
    123     }
    124    
    125     if(debug) { console.log("COLOR: " + color); }
    126    
    127     catParser = parserFor(formats[0]);
    128     valParser = parserFor(formats[1]);
    129 
    130     /* Not supported by IE
    131     data.forEach(function(d) {
    132         d[category] = catParser(d[category]);
    133         d[value] = valParser(d[value]);
    134     });
    135     */
    136        
    137     for(var i=0; i<data.length; i++) {
    138         data[i][category] = catParser(data[i][category]);
    139         data[i][value] = valParser(data[i][value]);
    140     }
    141 
    142     if(debug) { console.log("PARSED DATA: "); console.log(data); }
    143    
    144     var figure = d3.select('#' + id);
    145        
    146     var svg = figure.append("svg"),
    147         meta = svg.append("g").attr("class", "meta");
    148         //chart = svg.append("g").attr("class", "main");
    149    
    150     var figcaption = figure.append("figcaption").text(title);   
    151     meta.append("title").text(title);
    152     meta.append("description").text(description);
    153     figure.attr("style", style);
    154        
    155     var width = parseInt(figure.style("width")),
    156         height = parseInt(figure.style("height")) - parseInt(figcaption.style("height")) - 20;
    157 
    158     if(debug) { console.log("SVG \n\twidth: " + width + "\n\theight: " + height); }
    159    
    160     svg.attr("viewBox", "0 0 " + width + " " + height)
    161         .attr("preserveAspectRatio", "xMidYMid meet")
    162         .attr("width", width)
    163         .attr("height", height);
    164    
    165     if(tooltip == null) {
    166         tooltip = d3.select("body").append("div")
    167             .attr("class", "iputooltip")
    168             .style("opacity", 0.0)
    169             .style("width", function() {return screen.width > 320 ? "260px" : "160px"; })
    170             .html("<p>tooltip</p>")
    171             .on("touchstart", hideTooltip);
    172     }
    173    
     199}   
     200
     201function render(figure, data, type, category, value, format, color, sort, interpolate, animate, debug) {
     202   
     203    data = parseData(data, category, value, format, debug);
     204
    174205    if(type.toLowerCase().trim() == "bar")
    175         renderBar(svg, width, height, data, category, value, formats, colors, debug);
     206        renderBar(figure, data, category, value, format, color, sort, interpolate, animate, debug);
    176207       
    177208    else if(type.toLowerCase().trim() == "bar.horizontal")
    178         renderBarHorizontal(svg, width, height, data, category, value, formats, colors, debug);
     209        renderBarHorizontal(figure, data, category, value, format, color, sort, interpolate, animate, debug);
    179210             
    180211    else if(type.toLowerCase().trim() == "pie")
    181         renderPie(svg, width, height, data, category, value, formats, colors, debug);
     212        renderPie(figure, data, category, value, format, color, sort, interpolate, animate, debug);
     213       
     214    else if(type.toLowerCase().trim() == "donut")
     215        renderDonut(figure, data, category, value, format, color, sort, interpolate, animate, debug);
    182216       
    183217    else if(type.toLowerCase().trim() == "line")
    184         renderLine(svg, width, height, data, category, value, formats, colors, debug);
    185 }
    186 
    187 function renderTable(id, csv, title, debug) {
    188     var debug = (debug.toLowerCase() == "true");
    189     if(debug) { console.log("---------- START RENDER TABLE ----------"
    190                                 + "\n\tid: " + id
    191                                 + "\n\tcsv: " + csv
    192                                 + "\n\ttitle: " + title
    193                                 + "\n\tdebug: " + debug); }
    194        
    195     var div = d3.select(csv),
    196               data = d3.csv.parse(div.text());
    197    
    198     if(debug) { console.log("LOADING DATA ASYNC (" + csv + ")"); console.log(data); }
    199        
    200     var columns = d3.keys(data[0]);
    201    
    202     var table = d3.select('#' + id),
    203         caption = table.append("caption"),
    204         thead = table.append("thead"),
    205         tbody = table.append("tbody");
    206 
    207     caption.text(title);
    208    
    209     // append the header row
    210     thead.append("tr")
    211         .selectAll("th")
    212         .data(columns)
    213         .enter()
    214         .append("th")
    215             .text(function(column) { return column; });
    216 
    217     // create a row for each object in the data
    218     var rows = tbody.selectAll("tr")
    219         .data(data)
    220         .enter()
    221         .append("tr");
    222 
    223     // create a cell in each row for each column
    224     var cells = rows.selectAll("td")
    225         .data(function(row) {
    226             return columns.map(function(column) {
    227                 return {column: column, value: row[column]};
    228             });
    229         })
    230         .enter()
    231         .append("td")
    232             .text(function(d) { return d.value; });
    233            
    234     if(debug) { console.log("END RENDER TABLE"); }
    235 }
    236 
    237 function renderBar(svg, width, height, data, category, value, formats, colors, debug) {
    238     if(debug) { console.log("START RENDER BAR") };
    239    
    240     var color = d3.scale.ordinal().range(colors);
    241    
     218        renderLine(figure, data, category, value, format, color, sort, interpolate, animate, debug);
     219       
     220    else if(type.toLowerCase().trim() == "line.multi")
     221        renderLineMulti(figure, data, category, value, format, color, sort, interpolate, animate, debug);
     222}
     223
     224function renderLine(figure, data, category, value, format, color, sort, interpolate, animate, debug) {
     225    if(debug) { console.log("START RENDER LINE"); }
     226   
     227    var color = colorScale(color);
     228   
     229    var svg = figure.select("svg");
     230
    242231    var margin = {top: 20, right: 20, bottom: 40, left: 80},
    243         width = width - margin.left - margin.right,
    244         height = height - margin.top - margin.bottom;
    245        
    246     var x = scaleFor(formats[0])
    247         .rangeRoundBands([0, width], .1);
    248 
    249     var y = scaleFor(formats[1])
     232        width = parseInt(svg.attr("width")) - margin.left - margin.right,
     233        height = parseInt(svg.attr("height")) - margin.top - margin.bottom;
     234       
     235    var x = scaleFor(format[0])
     236        .range([0, width]);
     237
     238    var y = scaleFor(format[1])
    250239        .range([height, 0]);
    251 
     240       
    252241    var xAxis = d3.svg.axis()
    253242        .scale(x)
    254         .orient("bottom");
     243        .orient("bottom")
     244        .tickSize(height);
    255245
    256246    var yAxis = d3.svg.axis()
     
    259249        .tickSize(width);
    260250       
     251    var line = d3.svg.line()
     252        .interpolate(interpolate)
     253        .x(function(d) { return x(d[category]); })
     254        .y(function(d) { return y(d[value]); });
     255       
     256    x.domain(d3.extent(data, function(d) { return d[category]; }));
     257    y.domain(d3.extent(data, function(d) { return d[value]; }));
     258
     259    var chart = svg.append("g")
     260        .attr("class", "chart")
     261        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");   
     262
     263    chart.append("g")
     264        .attr("class", "x axis")
     265        .attr("transform", "translate(0," + 0 + ")")
     266        .call(xAxis);
     267
     268    chart.append("g")
     269        .attr("class", "y axis")
     270        .attr("transform", "translate(" + width + ", 0)")
     271        .call(yAxis);
     272
     273    chart.append("path")
     274        .datum(data)
     275        .attr("class", "line")
     276        .style("stroke", function(d) { return color(d[category]); })
     277        .attr("d", line);
     278       
     279    chart.selectAll(".dot")   
     280        .data(data)         
     281        .enter().append("circle")                               
     282            .attr("class", "dot")
     283            .attr("r", 5)       
     284            .attr("cx", function(d) { return x(d[category]); })       
     285            .attr("cy", function(d) { return y(d[value]); })
     286            .attr("opacity", 0.0);
     287       
     288    if(touch_device) {
     289        d3.selectAll(".dot")
     290            .on("touchstart", showTooltip);
     291    } else {
     292        d3.selectAll(".dot")   
     293            .on("mouseover", showTooltip)
     294            .on("mousemove", moveTooltip)
     295            .on("mouseout", hideTooltip);
     296    }
     297    if(debug) { console.log("END RENDER LINE") };
     298}
     299
     300function renderBar(figure, data, category, value, format, color, sort, interpolate, animate, debug) {
     301    if(debug) { console.log("START RENDER BAR") };
     302   
     303    var color = colorScale(color);
     304   
     305    var svg = figure.select("svg");
     306
     307    var margin = {top: 20, right: 20, bottom: 40, left: 80},
     308        width = parseInt(svg.attr("width")) - margin.left - margin.right,
     309        height = parseInt(svg.attr("height")) - margin.top - margin.bottom;
     310               
     311    var x = scaleFor(format[0])
     312        .rangeRoundBands([0, width], .1);
     313
     314    var y = scaleFor(format[1])
     315        .range([height, 0]);
     316
     317    var xAxis = d3.svg.axis()
     318        .scale(x)
     319        .orient("bottom");
     320
     321    var yAxis = d3.svg.axis()
     322        .scale(y)
     323        .orient("left")
     324        .tickSize(width);
     325       
    261326    x.domain(data.map(function(d) { return d[category]; }));
    262327    y.domain([0, d3.max(data, function(d) { return d[value]; })]);
    263 
    264     svg.attr("width", width + margin.left + margin.right)
    265        .attr("height", height + margin.top + margin.bottom);
    266328       
    267329    var chart = svg.append("g")
     
    287349            .attr("y", function(d) { return y(d[value]); })
    288350            .attr("height", function(d) { return height - y(d[value]); })
    289             .style("fill", function(d) { return colors(d[category]); })
     351            .style("fill", function(d) { return color(d[category]); })
    290352            .style("opacity", defaultOpacity);
    291            
     353     
     354    function startAnimation() {
     355        if(animate[0] != "none") {
     356            duration = +animate[0];
     357            ease = animate[1] != null ? animate[1] : "linear";
     358            if(debug) console.log("Starting animation, figure: " + figure.attr("id") + ", duration: " + duration + ", ease: " + ease);
     359
     360            chart.selectAll(".bar")
     361                .attr("y", y(0))
     362                .attr("height", 0)
     363                .transition()
     364                    .ease(ease)
     365                    .delay(function(d, i) { return duration/2 + i * duration; })
     366                    .duration(duration)
     367                    .attr("y", function(d) { return y(d[value]); })
     368                    .attr("height", function(d) { return height - y(d[value]); });
     369        }
     370    }
     371   
     372           
    292373    if(touch_device) {
    293374        d3.selectAll(".bar")
    294375            .on("touchstart", showTooltip);
     376           
     377        figure.selectAll("svg")
     378            .on("touchstart", startAnimation);
     379           
    295380    } else {
    296381        d3.selectAll(".bar")   
     
    298383            .on("mousemove", moveTooltip)
    299384            .on("mouseout", hideTooltip);   
     385           
     386        figure.selectAll("svg")
     387            .on("mousedown", startAnimation);           
    300388    }
    301389   
     
    304392}
    305393
    306 function renderBarHorizontal(svg, width, height, data, category, value, formats, colors, debug) {
     394function renderBarHorizontal(figure, data, category, value, format, color, sort, interpolate, animate, debug) {
    307395    if(debug) { console.log("START RENDER BAR HORIZONTAL") };
    308396   
    309     var color = d3.scale.ordinal().range(colors);
    310    
     397    var color = colorScale(color);
     398   
     399    data = data.reverse();
     400   
     401    var svg = figure.select("svg");
     402
    311403    var margin = {top: 20, right: 20, bottom: 40, left: 80},
    312         width = width - margin.left - margin.right,
    313         height = height - margin.top - margin.bottom;
    314 
    315     var x = scaleFor(formats[1])
     404        width = parseInt(svg.attr("width")) - margin.left - margin.right,
     405        height = parseInt(svg.attr("height")) - margin.top - margin.bottom;
     406
     407    var x = scaleFor(format[1])
    316408        .range([width, 0]);
    317409
    318     var y = scaleFor(formats[0])
     410    var y = scaleFor(format[0])
    319411        .rangeRoundBands([0, height], .1);
    320412       
     
    330422    y.domain(data.map(function(d) { return d[category]; }));
    331423    x.domain([d3.max(data, function(d) { return d[value]; }), 0]);
    332 
    333     svg.attr("width", width + margin.left + margin.right)
    334        .attr("height", height + margin.top + margin.bottom);
    335424       
    336425    var chart = svg.append("g")
     
    355444            .attr("height", y.rangeBand())
    356445            .attr("width", function(d) { return x(d[value]); })
    357             .style("fill", function(d) { return colors(d[category]); })
     446            .style("fill", function(d) { return color(d[category]); })
    358447            .style("opacity", defaultOpacity);
    359            
     448
     449    function startAnimation() {
     450        if(animate[0] != "none") {
     451            duration = +animate[0];
     452            ease = animate[1] != null ? animate[1] : "linear";
     453            if(debug) console.log("Starting animation, figure: " + figure.attr("id") + ", duration: " + duration + ", ease: " + ease);
     454
     455            var bars = chart.selectAll(".bar");
     456            bars
     457                .attr("width", 0)
     458                .transition()
     459                    .ease(ease)
     460                    .delay(function(d, i) { return duration/2 + (bars[0].length-i) * duration; })
     461                    .duration(duration)
     462                    .attr("width", function(d) { return x(d[value]); });
     463        }
     464    }
     465               
    360466    if(touch_device) {
    361467        d3.selectAll(".bar")
    362468            .on("touchstart", showTooltip);
     469           
     470        figure.selectAll("svg")
     471            .on("touchstart", startAnimation);
     472           
    363473    } else {
    364474        d3.selectAll(".bar")   
     
    366476            .on("mousemove", moveTooltip)
    367477            .on("mouseout", hideTooltip);   
     478           
     479        figure.selectAll("svg")
     480            .on("mousedown", startAnimation);           
    368481    }
     482   
    369483    if(debug) { console.log("END RENDER BAR HORIZONTAL") };
    370 }           
    371        
    372 function renderPie(svg, width, height, data, category, value, formats, colors, debug) {
     484}
     485
     486function renderPie(figure, data, category, value, format, color, sort, interpolate, animate, debug) {
    373487    if(debug) { console.log("START RENDER PIE") };
    374488   
     489    var color = colorScale(color);
     490   
     491    var svg = figure.select("svg");
     492       
     493    var margin = {top: 0, right: 20, bottom: 0, left: 0},
     494        width = parseInt(svg.attr("width")) - margin.left - margin.right,
     495        height = parseInt(svg.attr("height")) - margin.top - margin.bottom;
     496       
    375497    var radius = Math.min(width, height) / 2;
    376        
    377     var color = d3.scale.ordinal().range(colors);
    378498   
    379499    var arc = d3.svg.arc()
     
    397517    g.append("path")
    398518        .attr("d", arc)
    399         .style("fill", function(d) { return colors(d.data[category]); });
     519        .style("fill", function(d) { return color(d.data[category]); });
    400520
    401521    g.append("text")
     
    416536   
    417537    if(debug) { console.log("END RENDER PIE") };
    418  }
    419  
    420 function renderLine(svg, width, height, data, category, value, formats, colors, debug) {
    421     if(debug) { console.log("START RENDER LINE"); }
    422    
    423     var margin = {top: 20, right: 20, bottom: 40, left: 80},
    424         width = width - margin.left - margin.right,
    425         height = height - margin.top - margin.bottom;
    426        
    427     var x = scaleFor(formats[0])
    428         .range([0, width]);
    429 
    430     var y = scaleFor(formats[1])
    431         .range([height, 0]);
    432        
    433     var xAxis = d3.svg.axis()
    434         .scale(x)
    435         .orient("bottom")
    436         .tickSize(height);
    437 
    438     var yAxis = d3.svg.axis()
    439         .scale(y)
    440         .orient("left")
    441         .tickSize(width);;
    442        
    443     var line = d3.svg.line()
    444         .x(function(d) { return x(d[category]); })
    445         .y(function(d) { return y(d[value]); });
    446        
    447     x.domain(d3.extent(data, function(d) { return d[category]; }));
    448     y.domain(d3.extent(data, function(d) { return d[value]; }));
    449    
    450     svg.attr("width", width + margin.left + margin.right)
    451        .attr("height", height + margin.top + margin.bottom);
    452        
     538}
     539
     540function renderDonut(figure, data, category, value, format, color, sort, interpolate, animate, debug) {
     541    if(debug) { console.log("START RENDER DONUT") };
     542   
     543    var color = colorScale(color);
     544   
     545    var svg = figure.select("svg");
     546       
     547    var margin = {top: 0, right: 20, bottom: 0, left: 0},
     548        width = parseInt(svg.attr("width")) - margin.left - margin.right,
     549        height = parseInt(svg.attr("height")) - margin.top - margin.bottom;
     550       
     551    var radius = Math.min(width, height) / 2;
     552   
     553    var arc = d3.svg.arc()
     554        .outerRadius(radius - 5)
     555        .innerRadius((radius-5) * .6);
     556       
     557    var pie = d3.layout.pie()
     558        .sort(null)
     559        .value(function(d) { return d[value]; });
     560       
    453561    var chart = svg.append("g")
    454562        .attr("class", "chart")
    455         .attr("transform", "translate(" + margin.left + "," + margin.top + ")");   
    456 
    457     chart.append("g")
    458         .attr("class", "x axis")
    459         .attr("transform", "translate(0," + 0 + ")")
    460         .call(xAxis);
    461 
    462     chart.append("g")
    463         .attr("class", "y axis")
    464         .attr("transform", "translate(" + width + ", 0)")
    465         .call(yAxis);
    466 
    467     chart.append("path")
    468         .datum(data)
    469         .attr("class", "line")
    470         .style("stroke", function(d) { return colors(d[category]); })
    471         .attr("d", line);
    472        
    473     chart.selectAll(".dot")   
    474         .data(data)         
    475         .enter().append("circle")                               
    476             .attr("class", "dot")
    477             .attr("r", 5)       
    478             .attr("cx", function(d) { return x(d[category]); })       
    479             .attr("cy", function(d) { return y(d[value]); })
    480             .attr("opacity", 0.0);
     563        .attr("transform", "translate(" + width/2 + "," + height/2 + ")");
     564       
     565    var g = chart.selectAll(".arc")
     566        .data(pie(data))
     567            .enter().append("g")
     568            .attr("class", "arc")
     569            .style("opacity", defaultOpacity);
     570
     571    g.append("path")
     572        .attr("d", arc)
     573        .style("fill", function(d) { return color(d.data[category]); });
     574
     575    g.append("text")
     576        .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
     577        .attr("dy", ".35em")
     578        .style("text-anchor", "middle")
     579        .text(function(d) { return d.data[category]; });
    481580       
    482581    if(touch_device) {
    483         d3.selectAll(".dot")
    484             .on("touchstart", showTooltip);
     582        d3.selectAll(".arc")
     583            .on("touchstart", showTooltip);             
    485584    } else {
    486         d3.selectAll(".dot")   
     585        d3.selectAll(".arc")   
    487586            .on("mouseover", showTooltip)
    488587            .on("mousemove", moveTooltip)
    489             .on("mouseout", hideTooltip);
     588            .on("mouseout", hideTooltip);   
    490589    }
    491     if(debug) { console.log("END RENDER LINE") };
     590   
     591    if(debug) { console.log("END RENDER DONUT") };
     592}
     593
     594function renderTable(id, csv, title, debug) {
     595    var debug = (debug.toLowerCase() == "true");
     596    if(debug) { console.log("START RENDER TABLE"
     597                                + "\n\tid: " + id
     598                                + "\n\tcsv: " + csv
     599                                + "\n\ttitle: " + title
     600                                + "\n\tdebug: " + debug); }
     601       
     602    var div = d3.select(csv),
     603              data = d3.csv.parse(div.text());
     604   
     605    if(debug) { console.log("Loading data async (" + csv + ")"); console.log(data); }
     606       
     607    var columns = d3.keys(data[0]);
     608   
     609    var table = d3.select('#' + id),
     610        caption = table.append("caption"),
     611        thead = table.append("thead"),
     612        tbody = table.append("tbody");
     613
     614    caption.text(title);
     615   
     616    // append the header row
     617    thead.append("tr")
     618        .selectAll("th")
     619        .data(columns)
     620        .enter()
     621        .append("th")
     622            .text(function(column) { return column; });
     623
     624    // create a row for each object in the data
     625    var rows = tbody.selectAll("tr")
     626        .data(data)
     627        .enter()
     628        .append("tr");
     629
     630    // create a cell in each row for each column
     631    var cells = rows.selectAll("td")
     632        .data(function(row) {
     633            return columns.map(function(column) {
     634                return {column: column, value: row[column]};
     635            });
     636        })
     637        .enter()
     638        .append("td")
     639            .text(function(d) { return d.value; });
     640           
     641    if(debug) { console.log("END RENDER TABLE"); }
    492642}
    493643   
     
    565715        .style("opacity", defaultOpacity);
    566716       
     717    d3.selectAll(".serie").transition()
     718        .duration(200)
     719        .style("opacity", defaultOpacity);
     720       
    567721    d3.selectAll(".dot").transition()
    568722        .duration(200)
     
    576730    d3.event.preventDefault();
    577731};
    578            
  • ipu-chart/trunk/readme.txt

    r695101 r700167  
    11=== Plugin Name ===
    22Contributors: thmufl
    3 Tags: chart, diagram, svg, csv, excel, numbers, bar chart, pie chart, line chart
     3Tags: chart, diagram, svg, csv, excel, numbers, bar chart, pie chart, line chart, animation
    44Requires at least: 3.0.1
    55Tested up to: 3.5.1
    6 Stable tag: 0.2
     6Stable tag: 0.3
    77License: GPLv2 or later
    88License URI: http://www.gnu.org/licenses/gpl-2.0.html
    99
    10 Creates SVG based bar charts out of your CSV data. A powerful, easy to use shortcode.
     10Creates SVG based, animated bar, pie, donut and line charts out of your CSV data. A powerful, easy to use shortcode.
    1111
    1212== Description ==
    1313
    14 IPU-Chart is an easy to use shortcode that creates SVG based bar, pie and line charts out of your CSV data.
     14IPU-Chart is an easy to use shortcode that creates SVG based bar, pie, donut and line charts out of your CSV data.
    1515
    16 The plugin takes a csv file (Texteditor, Excel, Numbers etc.) and displays it as a chart. IPU-Chart is based on SVG and works perfectly on large computer screens as well as on tablets and smaller mobile screens. For browsers that do not support SVG an alternative image can be set.
     16The plugin takes a csv file (Texteditor, Excel, Numbers etc.) and displays it as a chart. IPU-Chart is based on [SVG](http://www.w3.org/TR/SVG/) and [D3](http://d3js.org/). It works perfectly on large computer screens as well as on tablets and smaller mobile screens. For browsers that do not support SVG an alternative image can be set.
    1717
    1818= Features =
    1919
    20 * Create bar, pie and line charts
     20* Create bar, pie, donut and line charts
    2121* Enter the csv data directy in you blog or page
    22 * Load csv data from a remote location
     22* Or load the csv data from a remote location
    2323* Create multiple views of the csv data
    24 * Animated tooltip for chart details (see screenshots)
     24* Tooltip for chart details (see screenshots)
     25* Animated bar charts
    2526* Define colors and number formats of the chart
    2627* Create an additional table view of the csv data
     
    4445[chart id='chart0'
    4546       csv='#popdata'
    46        type='bar | bar.horizontal | pie | line'
     47       type='bar | bar.horizontal | pie | donut | line'
    4748       category='Country'
    4849       value='Population'
     
    5253       title='Top five most populous countries of the world...'
    5354       description='The top five most populous countries of the world...'
    54        sort='Population"
     55       sort='Population'
     56       interpolate='cardinal'
     57       animate='medium'
    5558       img='http://www.example.com/chart0.png'
    5659       debug='false']
     
    92952. Horizontal bar chart example
    93963. Pie Chart example
    94 4. Line chart example
     974. Donut Chart example
     985. Line chart example
     996. Interpolated line chart example
    95100
    96101== Changelog ==
     
    108113* Changes in format definitions
    109114
     115= 0.3 =
     116* Donut charts added
     117* Attribute 'interpolate' added
     118* Attribute 'animate' added
     119* Enhanced error handling when loading csv data
     120
    110121== Upgrade Notice ==
    111122
    112123= 0.2 =
    113 This version adds support for pie- and line-charts. Furthermore formats for dates, integers and floats can be specified.
     124This version adds support for pie and line charts. Furthermore formats for dates, integers and floats can be specified.
     125
     126= 0.3 =
     127This version adds support for donut charts. Line chars can be interpolated. Bar charts can be animated (click or tap the bar charts to start the animation).
Note: See TracChangeset for help on using the changeset viewer.