File: svg.R

package info (click to toggle)
r-cran-xml 3.99-0.19-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,688 kB
  • sloc: ansic: 6,659; xml: 2,890; asm: 486; sh: 12; makefile: 2
file content (158 lines) | stat: -rw-r--r-- 3,891 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#
# An example of processing an SVG document
# See the example in the parallel directory data/svg.xml.
#
#
#  xmlplot <- xmlTreeParse("data/svg.xml")
#  x11()
#  svgRender(xmlplot)
#
# See also: mathml.R
#

#
# need support for the general SVG tags and attributes
#  desc
#  path
#  image

#  viewbox
#  stroke
#  transform matrix
#

svgRender <- 
function(doc)
{
 UseMethod("svgRender",doc)
}

svgRender.default <- 
function(doc)
{
  svgRender(doc$doc$children$svg)
}

svgRender.XMLNode <- 
#
# This processes an XML node assumed to come from an
# SVG document and either 
#  a) renders the corresponding element
#     and potentially recursively operates on its children, or
#  b) stores the settings specified in a group tag (<g> or <svg>)
#     for use in the processing of the sub-nodes.
#
#  This has basic support for circles, rectangles, polygons,
#  text 
#
function(top, settings = NULL) 
{
 if(is.null(settings)) {
   settings <- SVGSettings()
 }

 if(top$name == "svg") {
   dims <- top$attributes
   frame()
   par(usr=c(0, as.integer(dims[["width"]]) + 1, 0, as.integer(dims[["height"]])+1))
 } else if(top$name == "g") {
      if(!is.na(match("style", names(top$attributes)))) {
        settings$fill <- properties(top$attributes[["style"]])[["fill"]]
      }
 }
 
 for(i in top$children) {
  if(class(i) == "XMLComment")
    next
   ats <- i$attributes
   if(i$name == "rect") {
      
      if(!is.na(match("style", names(ats)))) {
        col <- properties(ats[["style"]])[["fill"]]
      } else {
         col <- settings$fill
      }

     rect(as.integer(ats[["x"]]), as.integer(ats[["y"]]), as.integer(ats[["x"]]) + as.integer(ats[["width"]]), as.integer(ats[["y"]]) + as.integer(ats[["width"]]), col = col)
   } else if(i$name == "text") {
       # need to gather up all the children in case the text 
       # is split into different components.
     val <- i$children[[1]]$value
     text(as.integer(ats[["x"]]), as.integer(ats[["y"]]), val, adj=1.0)
   } else if(i$name == "polygon") {
       # read the points attribute as a integer vector
     data <- scan.string(ats[["points"]])
     idx <- seq(1,length(data), by=2)
     x <- data[idx]
     y <- data[idx+1]

      if(!is.na(match("style", names(ats)))) {
        col <- properties(ats[["style"]])[["fill"]]
      } else {
        col <- settings$fill
      }

     polygon(x,y, col)
   } else if(i$name == "ellipse") {
      if(!is.na(match("style", names(ats)))) {
        col <- properties(ats[["style"]])[["fill"]]
      } else {
        col <- settings$fill
      }

     r <- min(as.integer(ats[["rx"]]), as.integer(ats[["ry"]]))
     symbols(as.integer(ats[["cx"]]), as.integer(ats[["cy"]]), circles=as.integer(r),inches=F, add=T)
   } else if(i$name == "g") {
      svgRender(i, settings)
   }
 }

 invisible(return(T))
}

SVGSettings <-
#
# This class of object is used for storing the
# "global" or currently active settings for within
# an SVG group. This includes things such as color
# fill style and color,  font, etc.
function()
{
  val <- list(fill=NULL, font=NULL, fg=NULL, bg=NULL)
  class(val) <- "SVGSettings"
 val
}



#
# The following are very simple (inefficient and potentially inconsistent with R) 
# ways of manipulating strings. These would be implemented using textConnection
# objects in S4.
#
scan.string <- function(data)
{
# This could use string split
# strsplit(data, rx)

 cmd <- paste("perl -e '$x = join(\"\n\", split(/ /, $ARGV[0])); printf \"$x\n\";'", paste("'",data,"'", collapse="",sep=""))
 els <- system(cmd, intern=T)
 vals <- as.integer(sapply(els, as.integer))

 return(vals)
}

properties <-
function(str)
{
 cmd <- paste("perl -e '$x = join(\"\n\", split(/ /, $ARGV[0])); printf \"$x\n\";'", paste("'",str,"'", collapse="",sep=""))

 els <- system(cmd, intern=T)

 idx <- seq(1,length(els), by=2)
 vals <- els[idx+1]
 names(vals) <- els[idx]

 return(vals)
}