fill-xform.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /* eslint-disable max-classes-per-file */
  2. const BaseXform = require('../base-xform');
  3. const ColorXform = require('./color-xform');
  4. class StopXform extends BaseXform {
  5. constructor() {
  6. super();
  7. this.map = {
  8. color: new ColorXform(),
  9. };
  10. }
  11. get tag() {
  12. return 'stop';
  13. }
  14. render(xmlStream, model) {
  15. xmlStream.openNode('stop');
  16. xmlStream.addAttribute('position', model.position);
  17. this.map.color.render(xmlStream, model.color);
  18. xmlStream.closeNode();
  19. }
  20. parseOpen(node) {
  21. if (this.parser) {
  22. this.parser.parseOpen(node);
  23. return true;
  24. }
  25. switch (node.name) {
  26. case 'stop':
  27. this.model = {
  28. position: parseFloat(node.attributes.position),
  29. };
  30. return true;
  31. case 'color':
  32. this.parser = this.map.color;
  33. this.parser.parseOpen(node);
  34. return true;
  35. default:
  36. return false;
  37. }
  38. }
  39. parseText() {}
  40. parseClose(name) {
  41. if (this.parser) {
  42. if (!this.parser.parseClose(name)) {
  43. this.model.color = this.parser.model;
  44. this.parser = undefined;
  45. }
  46. return true;
  47. }
  48. return false;
  49. }
  50. }
  51. class PatternFillXform extends BaseXform {
  52. constructor() {
  53. super();
  54. this.map = {
  55. fgColor: new ColorXform('fgColor'),
  56. bgColor: new ColorXform('bgColor'),
  57. };
  58. }
  59. get name() {
  60. return 'pattern';
  61. }
  62. get tag() {
  63. return 'patternFill';
  64. }
  65. render(xmlStream, model) {
  66. xmlStream.openNode('patternFill');
  67. xmlStream.addAttribute('patternType', model.pattern);
  68. if (model.fgColor) {
  69. this.map.fgColor.render(xmlStream, model.fgColor);
  70. }
  71. if (model.bgColor) {
  72. this.map.bgColor.render(xmlStream, model.bgColor);
  73. }
  74. xmlStream.closeNode();
  75. }
  76. parseOpen(node) {
  77. if (this.parser) {
  78. this.parser.parseOpen(node);
  79. return true;
  80. }
  81. switch (node.name) {
  82. case 'patternFill':
  83. this.model = {
  84. type: 'pattern',
  85. pattern: node.attributes.patternType,
  86. };
  87. return true;
  88. default:
  89. this.parser = this.map[node.name];
  90. if (this.parser) {
  91. this.parser.parseOpen(node);
  92. return true;
  93. }
  94. return false;
  95. }
  96. }
  97. parseText(text) {
  98. if (this.parser) {
  99. this.parser.parseText(text);
  100. }
  101. }
  102. parseClose(name) {
  103. if (this.parser) {
  104. if (!this.parser.parseClose(name)) {
  105. if (this.parser.model) {
  106. this.model[name] = this.parser.model;
  107. }
  108. this.parser = undefined;
  109. }
  110. return true;
  111. }
  112. return false;
  113. }
  114. }
  115. class GradientFillXform extends BaseXform {
  116. constructor() {
  117. super();
  118. this.map = {
  119. stop: new StopXform(),
  120. };
  121. // if (model) {
  122. // this.gradient = model.gradient;
  123. // if (model.center) {
  124. // this.center = model.center;
  125. // }
  126. // if (model.degree !== undefined) {
  127. // this.degree = model.degree;
  128. // }
  129. // this.stops = model.stops.map(function(stop) { return new StopXform(stop); });
  130. // } else {
  131. // this.stops = [];
  132. // }
  133. }
  134. get name() {
  135. return 'gradient';
  136. }
  137. get tag() {
  138. return 'gradientFill';
  139. }
  140. render(xmlStream, model) {
  141. xmlStream.openNode('gradientFill');
  142. switch (model.gradient) {
  143. case 'angle':
  144. xmlStream.addAttribute('degree', model.degree);
  145. break;
  146. case 'path':
  147. xmlStream.addAttribute('type', 'path');
  148. if (model.center.left) {
  149. xmlStream.addAttribute('left', model.center.left);
  150. if (model.center.right === undefined) {
  151. xmlStream.addAttribute('right', model.center.left);
  152. }
  153. }
  154. if (model.center.right) {
  155. xmlStream.addAttribute('right', model.center.right);
  156. }
  157. if (model.center.top) {
  158. xmlStream.addAttribute('top', model.center.top);
  159. if (model.center.bottom === undefined) {
  160. xmlStream.addAttribute('bottom', model.center.top);
  161. }
  162. }
  163. if (model.center.bottom) {
  164. xmlStream.addAttribute('bottom', model.center.bottom);
  165. }
  166. break;
  167. default:
  168. break;
  169. }
  170. const stopXform = this.map.stop;
  171. model.stops.forEach(stopModel => {
  172. stopXform.render(xmlStream, stopModel);
  173. });
  174. xmlStream.closeNode();
  175. }
  176. parseOpen(node) {
  177. if (this.parser) {
  178. this.parser.parseOpen(node);
  179. return true;
  180. }
  181. switch (node.name) {
  182. case 'gradientFill': {
  183. const model = (this.model = {
  184. stops: [],
  185. });
  186. if (node.attributes.degree) {
  187. model.gradient = 'angle';
  188. model.degree = parseInt(node.attributes.degree, 10);
  189. } else if (node.attributes.type === 'path') {
  190. model.gradient = 'path';
  191. model.center = {
  192. left: node.attributes.left ? parseFloat(node.attributes.left) : 0,
  193. top: node.attributes.top ? parseFloat(node.attributes.top) : 0,
  194. };
  195. if (node.attributes.right !== node.attributes.left) {
  196. model.center.right = node.attributes.right ? parseFloat(node.attributes.right) : 0;
  197. }
  198. if (node.attributes.bottom !== node.attributes.top) {
  199. model.center.bottom = node.attributes.bottom ? parseFloat(node.attributes.bottom) : 0;
  200. }
  201. }
  202. return true;
  203. }
  204. case 'stop':
  205. this.parser = this.map.stop;
  206. this.parser.parseOpen(node);
  207. return true;
  208. default:
  209. return false;
  210. }
  211. }
  212. parseText(text) {
  213. if (this.parser) {
  214. this.parser.parseText(text);
  215. }
  216. }
  217. parseClose(name) {
  218. if (this.parser) {
  219. if (!this.parser.parseClose(name)) {
  220. this.model.stops.push(this.parser.model);
  221. this.parser = undefined;
  222. }
  223. return true;
  224. }
  225. return false;
  226. }
  227. }
  228. // Fill encapsulates translation from fill model to/from xlsx
  229. class FillXform extends BaseXform {
  230. constructor() {
  231. super();
  232. this.map = {
  233. patternFill: new PatternFillXform(),
  234. gradientFill: new GradientFillXform(),
  235. };
  236. }
  237. get tag() {
  238. return 'fill';
  239. }
  240. render(xmlStream, model) {
  241. xmlStream.addRollback();
  242. xmlStream.openNode('fill');
  243. switch (model.type) {
  244. case 'pattern':
  245. this.map.patternFill.render(xmlStream, model);
  246. break;
  247. case 'gradient':
  248. this.map.gradientFill.render(xmlStream, model);
  249. break;
  250. default:
  251. xmlStream.rollback();
  252. return;
  253. }
  254. xmlStream.closeNode();
  255. xmlStream.commit();
  256. }
  257. parseOpen(node) {
  258. if (this.parser) {
  259. this.parser.parseOpen(node);
  260. return true;
  261. }
  262. switch (node.name) {
  263. case 'fill':
  264. this.model = {};
  265. return true;
  266. default:
  267. this.parser = this.map[node.name];
  268. if (this.parser) {
  269. this.parser.parseOpen(node);
  270. return true;
  271. }
  272. return false;
  273. }
  274. }
  275. parseText(text) {
  276. if (this.parser) {
  277. this.parser.parseText(text);
  278. }
  279. }
  280. parseClose(name) {
  281. if (this.parser) {
  282. if (!this.parser.parseClose(name)) {
  283. this.model = this.parser.model;
  284. this.model.type = this.parser.name;
  285. this.parser = undefined;
  286. }
  287. return true;
  288. }
  289. return false;
  290. }
  291. validStyle(value) {
  292. return FillXform.validPatternValues[value];
  293. }
  294. }
  295. FillXform.validPatternValues = [
  296. 'none',
  297. 'solid',
  298. 'darkVertical',
  299. 'darkGray',
  300. 'mediumGray',
  301. 'lightGray',
  302. 'gray125',
  303. 'gray0625',
  304. 'darkHorizontal',
  305. 'darkVertical',
  306. 'darkDown',
  307. 'darkUp',
  308. 'darkGrid',
  309. 'darkTrellis',
  310. 'lightHorizontal',
  311. 'lightVertical',
  312. 'lightDown',
  313. 'lightUp',
  314. 'lightGrid',
  315. 'lightTrellis',
  316. 'lightGrid',
  317. ].reduce((p, v) => {
  318. p[v] = true;
  319. return p;
  320. }, {});
  321. FillXform.StopXform = StopXform;
  322. FillXform.PatternFillXform = PatternFillXform;
  323. FillXform.GradientFillXform = GradientFillXform;
  324. module.exports = FillXform;