| -- @atlcompiler atl2006 |
| |
| -- ****************************************************************************** |
| -- Copyright (c) 2006 INRIA. |
| -- All rights reserved. This program and the accompanying materials |
| -- are made available under the terms of the Eclipse Public License v2.0 |
| -- which accompanies this distribution, and is available at |
| -- http://www.eclipse.org/legal/epl-v20.html |
| -- |
| -- Contributors: |
| -- INRIA - Initial implementation |
| -- |
| -- ****************************************************************************** |
| |
| --@name Table2SVG |
| --@version 1.0 |
| --@domains Table, SVG, Bar chart |
| --@authors Eric Vepa (eric.vepa <at> gmail.com) |
| --@date 2006/08/04 |
| --@description This transformation is used to transform generic tables into SVG bar charts. Each entry table is a two columns table (two cells per row). The first row contains two cells with a String (the first cell contains nothing and the second cell, the name of the chart). The other rows contains one cell with a name as String and an other cell with the value as Double. |
| |
| module Table2SVG; -- Module Template |
| create OUT : SVG from IN : Table; |
| |
| --@begin attribute helper allValidTables |
| --@comments returns all valid tables, ie tables which can be represented as bar chart |
| helper def : allValidTables : Sequence(Table!Table) = |
| Table!Table.allInstances()-> select(t|t.rows->first().cells->at(2).content.startsWith('Number')) |
| ->sortedBy(t|t.rows->first().cells->at(2).content); |
| --@end attribute helper allValidTables |
| |
| --@begin helper maxSizeName |
| --@comments returns the max size of all name of a table |
| helper context Table!Table def : maxSizeName() : Integer = |
| self.rows->subSequence(2,self.rows->size())->iterate(row; max:Integer=0| |
| let value : Integer = |
| let point : Integer = row.cells->at(2).content->indexOf('.') in |
| (row.cells->first().content + row.cells->at(2).content->substring(1,point+2))->size() + 2 in |
| if value > max |
| then value |
| else max |
| endif)*7; |
| --@end helper maxSizeName |
| |
| --@begin attribute helper prevRectWidth |
| --@comments returns the previous value of SVG rect width |
| helper def : prevRectWidth : Integer = 0; |
| --@end attribute helper prevRectWidth |
| |
| --@begin entrypoint rule SvgFile |
| --@comments creates the SVG file with one svg tag |
| helper def: svgFile : SVG!SvgFile = OclUndefined; |
| |
| entrypoint rule SvgFile() { |
| to |
| svgFile:SVG!SvgFile ( |
| tag <- svg |
| ), |
| svg:SVG!Svg ( |
| size <- svgSize, |
| namespace <- 'http://www.w3.org/2000/svg', |
| version <- '1.1' |
| ), |
| svgSize:SVG!Dimension ( |
| width <- thisModule.allValidTables->iterate(table; sum:Integer=0| |
| sum + table.maxSizeName() + 170), |
| height <- thisModule.allValidTables->iterate(table; max:Integer=0| |
| if (table.rows.size()-1) > max |
| then (table.rows.size()-1) |
| else max |
| endif)*10 + 50) |
| do { |
| thisModule.svgFile <- svgFile; |
| for (table in thisModule.allValidTables) { |
| thisModule.Table2BarChart(table); |
| } |
| } |
| } |
| --@end entrypoint rule SvgFile |
| -- |
| --@begin lazy rule Table2BarChart |
| --@comments creates a bar chart (SVG group) for one valid table |
| lazy rule Table2BarChart { |
| from |
| table:Table!Table ( |
| table.rows->first().cells->at(2).content.startsWith('Number') |
| ) |
| using { |
| rows : Sequence(Table!Row) = table.rows->subSequence(2,table.rows->size()); |
| scaleFactor : Real = 135/rows->iterate(row; max:Real=0| |
| if row.cells->at(2).content.toReal() > max |
| then row.cells->at(2).content.toReal() |
| else max |
| endif); |
| } |
| to |
| g:SVG!G ( |
| attribute <- transl, |
| attribute <- scale, |
| groupContent <- text, |
| groupContent <- rect, |
| groupContent <- axis, |
| groupContent <- rows->collect(row | thisModule.Row2Bar(rows.indexOf(row),scaleFactor,row)) |
| ), |
| rect:SVG!Rect ( |
| size <- rectSize, |
| position <- rectCoord, |
| fill <- 'none', |
| stroke <- 'blue' |
| ), |
| rectSize:SVG!Dimension ( |
| width <- 5+table.maxSizeName()+5+145+5, |
| height <- (table.rows.size()+1)*10 |
| ), |
| rectCoord:SVG!AbsoluteCoord ( |
| x <- 0-table.maxSizeName()-5, |
| y <- 0-5 |
| ), |
| transl:SVG!Translate ( |
| tx <- table.maxSizeName()+10 + thisModule.prevRectWidth, |
| ty <- 10 |
| ), |
| scale:SVG!Scale ( |
| sx <- 1, |
| sy <- scale.sx |
| ), |
| axis:SVG!Path ( |
| d <- 'M145,0 H0 V' + (table.rows.size()*10).toString() + ',0 z', |
| fill <- 'none', |
| stroke <- 'black' |
| ), |
| text:SVG!Text ( |
| position <- textCoord, |
| stroke <- 'blue', |
| fontSize <- '12', |
| --@comments text-anchor value strored in lengthAdjust attribute |
| lengthAdjust <- 'middle', |
| content <- table.rows->first().cells->at(2).content |
| ), |
| textCoord:SVG!AbsoluteCoord ( |
| x <- rectSize.width/2-table.maxSizeName(), |
| y <- rectSize.height+10 |
| ) |
| |
| do { |
| thisModule.prevRectWidth <- thisModule.prevRectWidth + rectSize.width + 5; |
| thisModule.svgFile.tag.children <- g; |
| } |
| } |
| --@end lazy rule Table2BarChart |
| |
| --@begin lazy rule Row2Bar |
| --@comments creates a bar (SVG line) for the row at position given |
| lazy rule Row2Bar { |
| from |
| position:Integer, |
| scaleFactor:Real, |
| row:Table!Row |
| using { |
| value : String = |
| let point : Integer = row.cells->at(2).content->indexOf('.') in |
| if point <= 0 |
| then row.cells->at(2).content |
| else row.cells->at(2).content->substring(1,point+2) |
| endif |
| ; |
| } |
| to |
| g:SVG!G ( |
| groupContent <- text, |
| groupContent <- bar |
| ), |
| bar:SVG!Rect ( |
| size <- barSize, |
| position <- barCoord, |
| fill <- 'blue', |
| stroke <- 'black' |
| ), |
| barSize:SVG!Dimension ( |
| width <- row.cells->at(2).content.toReal()*scaleFactor, |
| height <- 10 |
| ), |
| barCoord:SVG!AbsoluteCoord ( |
| x <- 0, |
| y <-barSize.height*(position-1) |
| ), |
| text:SVG!Text ( |
| position <- txtCoord, |
| stroke <- 'blue', |
| fontSize <- '8', |
| --@comments text-anchor value strored in lengthAdjust attribute |
| lengthAdjust <- 'end', |
| content <- row.cells->first().content + ' (' + value + ')' |
| ), |
| txtCoord:SVG!AbsoluteCoord ( |
| x <- 0-5, |
| y <- barCoord.y+barSize.height-1 |
| ) |
| } |
| --@end lazy rule Row2Bar |