Showing
6 changed files
with
348 additions
and
43 deletions
pdf/web_example/web/calendar.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'package:intl/intl.dart'; | ||
18 | +import 'package:pdf/pdf.dart'; | ||
19 | +import 'package:pdf/widgets.dart'; | ||
20 | + | ||
21 | +class Calendar extends StatelessWidget { | ||
22 | + Calendar({ | ||
23 | + this.date, | ||
24 | + this.month, | ||
25 | + this.year, | ||
26 | + }); | ||
27 | + | ||
28 | + final DateTime date; | ||
29 | + | ||
30 | + final int month; | ||
31 | + | ||
32 | + final int year; | ||
33 | + | ||
34 | + Widget title( | ||
35 | + Context context, | ||
36 | + DateTime date, | ||
37 | + ) { | ||
38 | + return Container( | ||
39 | + width: double.infinity, | ||
40 | + child: Text( | ||
41 | + DateFormat.yMMMM().format(date), | ||
42 | + style: const TextStyle( | ||
43 | + color: PdfColors.deepPurple, | ||
44 | + fontSize: 40, | ||
45 | + ), | ||
46 | + ), | ||
47 | + ); | ||
48 | + } | ||
49 | + | ||
50 | + Widget header( | ||
51 | + Context context, | ||
52 | + DateTime date, | ||
53 | + ) { | ||
54 | + return Container( | ||
55 | + color: PdfColors.blue200, | ||
56 | + padding: const EdgeInsets.all(8.0), | ||
57 | + child: Text( | ||
58 | + DateFormat.EEEE().format(date), | ||
59 | + style: const TextStyle( | ||
60 | + fontSize: 15, | ||
61 | + ), | ||
62 | + ), | ||
63 | + ); | ||
64 | + } | ||
65 | + | ||
66 | + Widget day( | ||
67 | + Context context, | ||
68 | + DateTime date, | ||
69 | + bool currentMonth, | ||
70 | + bool currentDay, | ||
71 | + ) { | ||
72 | + String text = '${date.day}'; | ||
73 | + TextStyle style = const TextStyle(); | ||
74 | + PdfColor color = PdfColors.grey300; | ||
75 | + | ||
76 | + if (currentDay) { | ||
77 | + style = TextStyle(color: PdfColors.red); | ||
78 | + color = PdfColors.lightBlue50; | ||
79 | + } | ||
80 | + | ||
81 | + if (!currentMonth) { | ||
82 | + style = TextStyle(color: PdfColors.grey); | ||
83 | + color = PdfColors.grey100; | ||
84 | + } | ||
85 | + | ||
86 | + if (date.day == 1) { | ||
87 | + text += ' ' + DateFormat.MMM().format(date); | ||
88 | + } | ||
89 | + | ||
90 | + return Container( | ||
91 | + padding: const EdgeInsets.all(4), | ||
92 | + color: color, | ||
93 | + child: Text( | ||
94 | + text, | ||
95 | + textAlign: TextAlign.right, | ||
96 | + style: style, | ||
97 | + ), | ||
98 | + ); | ||
99 | + } | ||
100 | + | ||
101 | + @override | ||
102 | + Widget build(Context context) { | ||
103 | + final DateTime _date = date ?? DateTime.now(); | ||
104 | + final int _year = year ?? _date.year; | ||
105 | + final int _month = month ?? _date.month; | ||
106 | + | ||
107 | + final DateTime start = DateTime(_year, _month, 1, 12); | ||
108 | + final DateTime end = DateTime(_year, _month + 1, 1, 12).subtract( | ||
109 | + const Duration(days: 1), | ||
110 | + ); | ||
111 | + | ||
112 | + final int startId = start.weekday - 1; | ||
113 | + final int endId = end.difference(start).inDays + startId + 1; | ||
114 | + | ||
115 | + final Row head = Row( | ||
116 | + mainAxisSize: MainAxisSize.max, | ||
117 | + children: List<Widget>.generate(7, (int index) { | ||
118 | + final DateTime d = start.add(Duration(days: index - startId)); | ||
119 | + return Expanded( | ||
120 | + child: Container( | ||
121 | + foregroundDecoration: BoxDecoration( | ||
122 | + border: BoxBorder( | ||
123 | + color: PdfColors.black, | ||
124 | + top: true, | ||
125 | + left: true, | ||
126 | + right: index % 7 == 6, | ||
127 | + bottom: true, | ||
128 | + ), | ||
129 | + ), | ||
130 | + child: header(context, d), | ||
131 | + ), | ||
132 | + ); | ||
133 | + }), | ||
134 | + ); | ||
135 | + | ||
136 | + final GridView body = GridView( | ||
137 | + crossAxisCount: 7, | ||
138 | + children: List<Widget>.generate(42, (int index) { | ||
139 | + final DateTime d = start.add(Duration(days: index - startId)); | ||
140 | + final bool currentMonth = index >= startId && index < endId; | ||
141 | + final bool currentDay = d.year == _date.year && | ||
142 | + d.month == _date.month && | ||
143 | + d.day == _date.day; | ||
144 | + return Container( | ||
145 | + foregroundDecoration: BoxDecoration( | ||
146 | + border: BoxBorder( | ||
147 | + color: PdfColors.black, | ||
148 | + left: true, | ||
149 | + right: index % 7 == 6, | ||
150 | + bottom: true, | ||
151 | + ), | ||
152 | + ), | ||
153 | + child: day(context, d, currentMonth, currentDay), | ||
154 | + ); | ||
155 | + }), | ||
156 | + ); | ||
157 | + | ||
158 | + return Container( | ||
159 | + padding: const EdgeInsets.all(20), | ||
160 | + child: Column( | ||
161 | + mainAxisAlignment: MainAxisAlignment.start, | ||
162 | + mainAxisSize: MainAxisSize.min, | ||
163 | + children: <Widget>[ | ||
164 | + title(context, DateTime(_year, _month)), | ||
165 | + head, | ||
166 | + Flexible(flex: 1, child: body), | ||
167 | + ], | ||
168 | + ), | ||
169 | + ); | ||
170 | + } | ||
171 | +} |
@@ -8,17 +8,87 @@ | @@ -8,17 +8,87 @@ | ||
8 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | 8 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
9 | <title>Pdf Web Example</title> | 9 | <title>Pdf Web Example</title> |
10 | <link rel="stylesheet" href="styles.css"> | 10 | <link rel="stylesheet" href="styles.css"> |
11 | - <script defer src="main.dart.js"></script> | 11 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.3.200/pdf.min.js"></script> |
12 | + <script src="main.dart.js"></script> | ||
13 | + <script> | ||
14 | + async function displayPdf(pdf) { | ||
15 | + let doc = await pdfjsLib.getDocument(pdf).promise; | ||
16 | + document.getElementById('page_count').innerText = doc.numPages; | ||
17 | + let metadata = await doc.getMetadata(); | ||
18 | + let title = metadata.info.Title || 'Untitled'; | ||
19 | + document.getElementById('title').innerText = title; | ||
20 | + document.title = title; | ||
21 | + | ||
22 | + let author = metadata.info.Author || ''; | ||
23 | + let producer = metadata.info.Producer || ''; | ||
24 | + document.getElementById('author').innerText = author + ' | ' + producer; | ||
25 | + | ||
26 | + let currentPage = 1; | ||
27 | + | ||
28 | + document.getElementById('prev').addEventListener('click', () => { | ||
29 | + if (currentPage <= 1) { | ||
30 | + return; | ||
31 | + } | ||
32 | + currentPage--; | ||
33 | + renderPage(doc, currentPage); | ||
34 | + }); | ||
35 | + | ||
36 | + document.getElementById('next').addEventListener('click', () => { | ||
37 | + if (currentPage >= doc.numPages) { | ||
38 | + return; | ||
39 | + } | ||
40 | + currentPage++; | ||
41 | + renderPage(doc, currentPage); | ||
42 | + }); | ||
43 | + | ||
44 | + renderPage(doc, currentPage); | ||
45 | + } | ||
46 | + | ||
47 | + async function renderPage(doc, pageNum) { | ||
48 | + document.getElementById('page_num').innerText = pageNum; | ||
49 | + | ||
50 | + let page = await doc.getPage(pageNum); | ||
51 | + let viewport = page.getViewport({ scale: 1 }); | ||
52 | + let canvas = document.getElementById('container'); | ||
53 | + canvas.width = viewport.width; | ||
54 | + canvas.height = viewport.height; | ||
55 | + | ||
56 | + let renderContext = { | ||
57 | + canvasContext: canvas.getContext('2d'), | ||
58 | + viewport: viewport | ||
59 | + }; | ||
60 | + | ||
61 | + await page.render(renderContext).promise; | ||
62 | + | ||
63 | + document.getElementById('toolbar-loading').style.display = 'none'; | ||
64 | + document.getElementById('toolbar-content').style.display = ''; | ||
65 | + document.getElementById('container').style.display = ''; | ||
66 | + document.getElementById('author').style.display = ''; | ||
67 | + } | ||
68 | + | ||
69 | + function ready() { | ||
70 | + // Dart is fully loaded | ||
71 | + let pdf = buildPdf(); | ||
72 | + displayPdf(pdf); | ||
73 | + }; | ||
74 | + </script> | ||
12 | </head> | 75 | </head> |
13 | 76 | ||
14 | <body> | 77 | <body> |
15 | - <div> | ||
16 | - <button id="generate">Generate</button> | 78 | + <div class="toolbar"> |
79 | + <div id="toolbar-loading">Loading ...</div> | ||
80 | + <div id="toolbar-content" style="display:none;"> | ||
81 | + <button id="prev">Previous</button> | ||
82 | + <button id="next">Next</button> | ||
83 | + | ||
84 | + <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span> | ||
85 | + <span id="title"></span> | ||
86 | + </div> | ||
17 | </div> | 87 | </div> |
18 | 88 | ||
19 | - <div id="container"> | ||
20 | - <object id="doc" type="application/pdf"></object> | ||
21 | - </div> | 89 | + |
90 | + <canvas id="container" style="display:none;"></canvas> | ||
91 | + <div id="author" style="display:none;"></div> | ||
22 | </body> | 92 | </body> |
23 | 93 | ||
24 | </html> | 94 | </html> |
1 | -import 'dart:convert'; | 1 | +/* |
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:async'; | ||
2 | import 'dart:html'; | 18 | import 'dart:html'; |
19 | +import 'dart:js' as js; | ||
20 | +import 'dart:typed_data'; | ||
3 | 21 | ||
4 | import 'package:pdf/pdf.dart'; | 22 | import 'package:pdf/pdf.dart'; |
5 | import 'package:pdf/widgets.dart'; | 23 | import 'package:pdf/widgets.dart'; |
6 | 24 | ||
7 | -void main() { | ||
8 | - final ButtonElement generateButton = querySelector('#generate'); | ||
9 | - | ||
10 | - generateButton.onClick.listen((_) async { | ||
11 | - final String data = Uri.encodeComponent(base64.encode(buildPdf())); | 25 | +import 'calendar.dart'; |
12 | 26 | ||
13 | - final ObjectElement doc = querySelector('#doc'); | ||
14 | - doc.data = 'data:application/pdf;base64,$data'; | ||
15 | - }); | ||
16 | -} | 27 | +Uint8List buildPdf() { |
28 | + final Document pdf = Document(title: 'My Document', author: 'David PHAM-VAN'); | ||
17 | 29 | ||
18 | -List<int> buildPdf() { | ||
19 | - final Document pdf = Document(); | ||
20 | - | ||
21 | - pdf.addPage(Page(build: (Context ctx) { | ||
22 | - return Container( | ||
23 | - width: double.infinity, | ||
24 | - height: double.infinity, | ||
25 | - child: FittedBox( | ||
26 | - child: Text( | ||
27 | - 'Hello!', | ||
28 | - style: TextStyle(color: PdfColors.blueGrey), | 30 | + pdf.addPage(Page( |
31 | + build: (Context ctx) { | ||
32 | + return Container( | ||
33 | + width: double.infinity, | ||
34 | + height: double.infinity, | ||
35 | + child: FittedBox( | ||
36 | + child: Text( | ||
37 | + 'Hello!', | ||
38 | + style: TextStyle(color: PdfColors.blueGrey), | ||
39 | + ), | ||
29 | ), | 40 | ), |
30 | - ), | ||
31 | - ); | ||
32 | - })); | 41 | + ); |
42 | + }, | ||
43 | + )); | ||
44 | + | ||
45 | + pdf.addPage(Page( | ||
46 | + pageFormat: PdfPageFormat.a4.landscape, | ||
47 | + build: (Context context) => Calendar(), | ||
48 | + )); | ||
33 | 49 | ||
34 | - return pdf.save(); | 50 | + pdf.addPage(Page( |
51 | + pageFormat: PdfPageFormat.a4.landscape, | ||
52 | + build: (Context context) => Calendar( | ||
53 | + month: DateTime.now().month + 1, | ||
54 | + ), | ||
55 | + )); | ||
56 | + | ||
57 | + pdf.addPage(Page( | ||
58 | + build: (Context ctx) { | ||
59 | + return Center(child: PdfLogo()); | ||
60 | + }, | ||
61 | + )); | ||
62 | + | ||
63 | + return Uint8List.fromList(pdf.save()); | ||
64 | +} | ||
65 | + | ||
66 | +void main() { | ||
67 | + js.context['buildPdf'] = buildPdf; | ||
68 | + Timer.run(() { | ||
69 | + js.context.callMethod('ready'); | ||
70 | + }); | ||
35 | } | 71 | } |
@@ -10,18 +10,44 @@ body { | @@ -10,18 +10,44 @@ body { | ||
10 | } | 10 | } |
11 | 11 | ||
12 | #container { | 12 | #container { |
13 | - left: 10px; | ||
14 | - right: 10px; | ||
15 | - width: auto; | ||
16 | - bottom: 10px; | ||
17 | - top: 49px; | ||
18 | - display: block; | ||
19 | - position: absolute; | ||
20 | - border: 1px dotted red; | 13 | + border: 1px solid rgb(37, 37, 37); |
14 | + box-shadow: 3px 3px 5px rgb(129, 129, 129); | ||
15 | + margin: 20px; | ||
21 | } | 16 | } |
22 | 17 | ||
23 | -#doc { | ||
24 | - width: 100%; | ||
25 | - height: 100%; | ||
26 | - display: block; | 18 | +.toolbar { |
19 | + background-color: rgb(82, 82, 82); | ||
20 | + padding: 10px; | ||
21 | + color: #fff; | ||
22 | +} | ||
23 | + | ||
24 | +button { | ||
25 | + height: 50px; | ||
26 | + width: 100px; | ||
27 | + background-color: #5cb8ff; | ||
28 | + border: 1px solid #4f90ff; | ||
29 | + display: inline-block; | ||
30 | + cursor: pointer; | ||
31 | + color: #ffffff; | ||
32 | + font-size: 17px; | ||
33 | +} | ||
34 | + | ||
35 | +button:hover { | ||
36 | + background-color: #2688ff; | ||
37 | +} | ||
38 | + | ||
39 | +button:active { | ||
40 | + background-color: #1a64be; | ||
41 | +} | ||
42 | + | ||
43 | +#title { | ||
44 | + margin-left: 2rem; | ||
45 | + font-size: 1.8em; | ||
46 | +} | ||
47 | + | ||
48 | +#author { | ||
49 | + margin-left: 20px; | ||
50 | + margin-bottom: 20px; | ||
51 | + color: rgb(65, 72, 77); | ||
52 | + font-size: 0.7em; | ||
27 | } | 53 | } |
-
Please register or login to post a comment