/* Linear Charting Script Use this script to apply a linear chart to a solid from CSV data. Select a single Comp with a single Solid layer to act as a chart base. Create and style a text layer that reads "label" to act as a template for the chart labels. A full demo of the use of this script is available at: http://www.creative-workflow-hacks.com/2006/06/29/a-line-chart-script-for-after-effects/ Copyright 2006 - Dale Bradshaw, dale@creative-workflow-hacks.com http://creative-workflow-hacks.com Free To Distribute, but you must maintain this header if used without alteration, please also include a link to http://creative-workflow-hacks.com if posted on the web If you use parts of this script please include my contact info as attribution (suggested but not required...thanks) v0.5b1 initial public release, June 29, 2006 */ Array.prototype.max = function () { if (this.length == 0) return undefined; var n = Number(this[0]); for (var i=1; i>16) & 0xFF; var green = (rgb >>8) & 0xFF; var blue = rgb & 0xFF; var colorArray = [red/255.0, green/255.0, blue/255.0]; return colorArray; } } var chartController = { init: function(){ this.width = selectedItemInfo.source.width; this.height = selectedItemInfo.source.height; this.model = chartData; this.view = chartView; this.encoded_data = ''; this.decoded_data = ''; this.dataPoints = ''; this.cancelled = false; this.getCSV(); if(!this.cancelled){ this.parseCSV(); this.setDataPoints(); this.model.init(); this.model.setData(this.decoded_data); this.view.init(this.dataPoints, this.decoded_data); this.view.drawChart(); } }, getCSV: function(){ var pfile = fileGetDialog("Please select a CSV file.", ""); if (pfile == null){ alert("No csv file selected. "); this.cancelled = true; }else{ var readData = pfile.open("r","TEXT", "????"); if(readData){ this.encoded_data = pfile.read(); }else{ alert("Problems reading csv file"); } } }, parseCSV: function (){ //designed for numerical CSV, see //http://creative-workflow-hacks.com/downloads/CSVtoTextLayers.jsx //for regex based string CSV var i, s; this.decoded_data = new Array(); var a = this.encoded_data.split(/\r*\n/); for (i=0; i < a.length; i++){ var element = a[i].split(","); var count = element.length; this.decoded_data[i] = new Array(count); for (x=0; x < count; x++){ //if parseInt(element[x]) == parseFloat(element[x]) we are an integer as far as Javascript is concerned if (parseInt(element[x]) == parseFloat(element[x])){ this.decoded_data[i][x] = parseInt(element[x]); }else{ this.decoded_data[i][x] = parseFloat(element[x]); } } } }, setDataPoints: function(){ var rowCount = this.decoded_data.length; var columnCount = this.decoded_data[0].length //establish min and max var x, y, min, max; for(x=0; x < rowCount; x++){ var dataString = this.decoded_data[x].toString(); eval("var data = new Array(" + dataString + ")"); max = (max > data.max()) ? max : data.max(); if(min){ min = (data.min() < min) ? data.min() : min; }else{ min = data.min(); } } this.max = max; this.min = min; //establish units this.xUnit = this.width / (columnCount - 1); //use 0 for min for now, could also set range at min value //yUnit = this.height / (max - min); this.yUnit = this.height / max; //configure data points var pointArray = new Array(); for(x=0; x < rowCount; x++){ pointArray[x] = new Array(columnCount); for(y=0; y< columnCount; y++){ var xPt = (y * this.xUnit); var yPt = this.height - (this.decoded_data[x][y] * this.yUnit); var tempPoint = {"x": xPt, "y": yPt}; pointArray[x][y] = tempPoint; } } this.dataPoints = pointArray; }, getMinMaxUnits: function(){ return {"min": this.min, "max": this.max, "yUnit": this.yUnit, "xUnit": this.xUnit}; } } //UI setup //help text function usage(){ var usage = "Use this script to apply a linear chart to a solid from CSV data\nSelect a single Comp with a single Solid layer to act as a chart base.\nCreate and style a text layer that reads \"label\" to act as a template for the chart labels."; alert(usage); } //UI build function buildUI(){ if (win != null) { win.ChartPnl = win.add('panel', [20,25,230,235], 'Chart:'); win.lineSizeText = win.ChartPnl.add('statictext', [15,20,105,30], 'Line Size:'); win.lineSize = win.ChartPnl.add ("slider",[10,35,205,45], 5, 1, 50); win.lineSize.value = 5; win.labelOffsetText = win.ChartPnl.add('statictext', [15,50,105,65], 'Label Offset:'); win.labelOffset = win.ChartPnl.add ("slider",[10,65,205,75], 20, 1, 50); win.labelOffset.value = 20; win.compositeOnOriginal = win.ChartPnl.add('checkbox', [15,85,205,95], 'Composite On Original (without grid)'); win.compositeOnOriginal.value = true; win.useGridCb = win.ChartPnl.add('checkbox', [15,105, 90,115], 'Include Grid'); win.useGridCb.value = true; win.gridSettingsPnl = win.ChartPnl.add('panel', [10,120,200,200], 'Grid Settings:'); win.gridLineSizeText = win.gridSettingsPnl.add('statictext', [10,20,105,30], 'Grid Line Size:'); win.gridLineSize = win.gridSettingsPnl.add ("slider",[5,35,185,45], 2, 1, 20); win.gridLineSize.value = 2; win.gridSquareSizeText = win.gridSettingsPnl.add('statictext', [10,50,105,60], 'Grid Square Size:'); win.gridSquareSize = win.gridSettingsPnl.add ("slider",[5,65,185,75], 2, 10, 200); win.gridSquareSize.value = 50; win.animationPnl = win.add('panel', [20,240,230,320], 'Animation:'); win.chartBuildSpeedText = win.animationPnl.add('statictext', [10,15,205,25], 'Chart Build Speed:'); win.chartBuildSpeed = win.animationPnl.add ("slider",[5,30,205,40],50, 1, 100); win.chartBuildSpeed.value = 50; win.lineAnimationOverlapText = win.animationPnl.add('statictext', [10,45,205,55], 'Line Animation Overlap:'); win.lineAnimationOverlap = win.animationPnl.add ("slider",[5,60,205,70],50, 0, 100); win.lineAnimationOverlap.value = 50; win.helpBtn = win.add('button', [20,325,50,345], '?', {name:'help'}); win.helpBtn.onClick = usage; win.cancBtn = win.add('button', [105,325,165,345], 'Cancel', {name:'cancel'}); win.cancBtn.onClick = function () {this.parent.close(0)}; win.okBtn = win.add('button', [172,325,230,345], 'OK', {name:'ok'}); win.okBtn.onClick = function () {chartController.init();}; } return win } //check that a single comp is selected function checkPrerequisites(){ var selectedCount = 0; var selectAlert = "Please select a single Comp. This Comp should contain a single Solid which will act as a chart template."; if ((activeItem != null) && (activeItem instanceof CompItem)){ var layers = activeItem.layers; var layer; for (var i = 1; i <= layers.length; i++) { layer = layers[i]; //check for text layer named label var sourceText = layers[i].sourceText; if(sourceText != null){ if(sourceText.value.text.toLowerCase() == 'label'){ selectedItemInfo.labelSrc = layers[i]; } } if(layer.source){ if (layer.source.mainSource instanceof SolidSource){ selectedItemInfo.type = 'SolidSource'; selectedItemInfo.name = layer.name; selectedItemInfo.source = layer; }else{ selectedItemInfo.type = ''; selectedItemInfo.name = ''; selectedItemInfo.source = ''; alert(selectAlert); } selectedCount++; } } if(selectedCount > 1 || selectedCount == 0){ selectedItemInfo.type = ''; selectedItemInfo.name = ''; selectedItemInfo.source = ''; var selectAlert = "Please select a single Comp. This Comp should contain a single Solid which will act as a chart template."; alert(selectAlert); }else{ if(w != null){ w.show(); }else{ alert("Couldn't build UI"); } } }else{ alert(selectAlert); } } //globals var items = app.project.items; var activeItem = app.project.activeItem; var selectedItemInfo = {name: "", type:"", source:"", width:"", height:"", labelSrc:""}; var win = new Window('palette', 'Create Line Chart from CSV',[100,100,352,455]); var w = buildUI(); checkPrerequisites();