Fakultas Ilmu Komputer UI

utils.tsx 11.6 KB
Newer Older
1
2
import React from 'react';
import { Sector } from 'recharts';
Sean Zeliq Urian's avatar
Sean Zeliq Urian committed
3
import { jsPDF } from "jspdf";
4
import { PIE_COLORS } from 'constant';
5
import { PassThrough } from 'stream';
6
7
8
9
10
11
12
13
14
15
16
17
18
19

interface ActiveShapeProps {
  cx: number, cy: number, midAngle: number, innerRadius: number,
  outerRadius: number, startAngle: number, endAngle: number,
  fill: never, payload: { name: string }, percent : number, value: string,
}

const translate = (str: string) => {
  if (str.toLowerCase() === 'male') {
    return 'Pria';
  } 
  if (str.toLowerCase() === 'female') {
    return 'Wanita';
  }
20
21
22
23
24
25
26
  
  if (str.toLowerCase() === 'pria') {
    return 'male';
  } 
  if (str.toLowerCase() === 'wanita') {
    return 'female';
  }
27
28
29
  return str;
};

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const translateTypetoKey = (str: string) => {  
  if (str.toLowerCase() === 'kecamatan') {
    return 'district';
  } 
  if (str.toLowerCase() === 'kelurahan') {
    return 'sub_district';
  }
  if (str.toLowerCase() === 'jenis kelamin') {
    return 'sex';
  }
  if (str.toLowerCase() === 'umur') {
    return 'age';
  }
  return str;
};

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
const translateToMonth = (bulan: string) => {
  const bulan2 = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'];
  const noBulan = parseInt(bulan.slice(1,2)) - 1;
  for (var i = 0, len = bulan2.length ; i < len; i++) { 
    return bulan2[noBulan];
  }
};

const translateChartType = (input: boolean) => {
  if(!input){
    return 'Bar';
  }
  else{
    return 'Pie';
  } 
}

const translateToString = (input: Array<number>) => {
  let res: Array<string> = [];
    for (var i = 0, len = input.length ; i < len; i++) {
      var casesPositive = input[i].toString();
      res.push(casesPositive);
    }
  return res;
}

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
const renderActiveShape = (props: ActiveShapeProps) => {
  const RADIAN = Math.PI / 180;
  const {
    cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle,
    fill, payload, percent, value,
  } = props;
  const sin = Math.sin(-RADIAN * midAngle);
  const cos = Math.cos(-RADIAN * midAngle);
  const sx = cx + (outerRadius + 10) * cos;
  const sy = cy + (outerRadius + 10) * sin;
  const mx = cx + (outerRadius + 30) * cos;
  const my = cy + (outerRadius + 30) * sin;
  const ex = mx + (cos >= 0 ? 1 : -1) * 22;
  const ey = my;
  const textAnchor = cos >= 0 ? 'start' : 'end';

  return (
    <g>
      <Sector
        cx={cx}
        cy={cy}
        innerRadius={innerRadius}
        outerRadius={outerRadius}
        startAngle={startAngle}
        endAngle={endAngle}
        fill={fill}
      />
      <Sector
        cx={cx}
        cy={cy}
        startAngle={startAngle}
        endAngle={endAngle}
        innerRadius={outerRadius + 6}
        outerRadius={outerRadius + 10}
        fill={fill}
      />
      <path d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`} stroke={fill} fill="none" />
      <circle cx={ex} cy={ey} r={2} fill={fill} stroke="none" />
      <text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} textAnchor={textAnchor} fill="#333">{`Total: ${value}`}</text>
      <text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill="#999">
        {`(${(percent * 100).toFixed(2)}%)`}
      </text>
    </g>
  );
};

118
const image2pdf  = (imageType: string, type: string, key: string, dataType: string, chartType: boolean, total: string, info: Array<number>) => {
119
  const imgWidth = 232;  
120

121
  const imgHeight = 130;  
Sean Zeliq Urian's avatar
Sean Zeliq Urian committed
122
123
  const pageWidth = 297;
  const pageHeight = 210;
124
125
126
127
  const imgPieWidth = 212;
  const imgPieHeight = 110; 
  const pageImgWidth = 38;
  const pageImgHeight = 30;
128
  
Sean Zeliq Urian's avatar
Sean Zeliq Urian committed
129
130
131
  const marginX = (pageWidth - imgWidth) / 2;
  
  const doc = new jsPDF({orientation: "l", format:[pageWidth, pageHeight]});
132
133
134
135
136
137
138
  const date1st = dataType.slice(8,10) + " " + translateToMonth(dataType.slice(5,7)) +" "+ dataType.slice(0,4);
  const date2nd = dataType.slice(23,25) + " " + translateToMonth(dataType.slice(20,22)) + " " + dataType.slice(15,19);
  const caseP = info[0].toString();
  const caseN = info[1].toString();
  const caseU = info[2].toString();
  const cases = translateToString(info);

Nabilah Adani's avatar
Nabilah Adani committed
139
  const header = (doc: jsPDF) => {
140
    doc.setFontSize(26);
Nabilah Adani's avatar
Nabilah Adani committed
141
    doc.setFont("arial", "bold");
142
    if (key === "Tanggal")
Nabilah Adani's avatar
Nabilah Adani committed
143
      doc.text("DATA KASUS TBC DEPOK", pageWidth/2, 24, {align:"center"});
144
    else 
145
146
147
148
      if (chartType)
        doc.text("DATA KASUS TBC DEPOK", pageWidth/2, 18, {align:"center"});
      else 
        doc.text("DATA KASUS TBC DEPOK", pageWidth/2, 18, {align:"center"});
149
150
151
152
  }

  const writeInfoCases = (doc: jsPDF) => {
    doc.setFontSize(20);
Nabilah Adani's avatar
Nabilah Adani committed
153
154
155
156
    doc.setFont("arial", "bold");
    doc.text(caseP, 90, 35, {align:"center"});
    doc.text(caseN, 145, 35, {align:"center"});
    doc.text(caseU, 200, 35, {align:"center"});
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  }

  const writeInfoCaseP = (doc: jsPDF) => {
    doc.setFontSize(13);
    doc.setFont("arial", "light");
	  doc.text("P: " + cases[0], 65, 43, {align:"center"});
    doc.text("P: " + cases[3], 83, 43, {align:"center"});
    doc.text("P: " + cases[6], 102, 43, {align:"center"});
    doc.text("P: " + cases[9], 120, 43, {align:"center"});
    doc.text("P: " + cases[12], 138, 43, {align:"center"});
    doc.text("P: " + cases[15], 157, 43, {align:"center"});
    doc.text("P: " + cases[18], 175, 43, {align:"center"});
    doc.text("P: " + cases[21], 193, 43, {align:"center"});
    doc.text("P: " + cases[24], 212, 43, {align:"center"});
    doc.text("P: " + cases[27], 230, 43, {align:"center"});
    doc.text("P: " + cases[30], 248, 43, {align:"center"});
  }

  const writeInfoCaseN = (doc: jsPDF) => {
    doc.setFontSize(13);
    doc.setFont("arial", "light");
	  doc.text("N: " + cases[1], 65, 50, {align:"center"});
    doc.text("N: " + cases[4], 83, 50, {align:"center"});
    doc.text("N: " + cases[7], 102, 50, {align:"center"});
    doc.text("N: " + cases[10], 120, 50, {align:"center"});
    doc.text("N: " + cases[13], 138, 50, {align:"center"});
    doc.text("N: " + cases[16], 157, 50, {align:"center"});
    doc.text("N: " + cases[19], 175, 50, {align:"center"});
    doc.text("N: " + cases[22], 193, 50, {align:"center"});
    doc.text("N: " + cases[25], 212, 50, {align:"center"});
    doc.text("N: " + cases[28], 230, 50, {align:"center"});
    doc.text("N: " + cases[31], 248, 50, {align:"center"});
  }

  const writeInfoCaseU = (doc: jsPDF) => {
    doc.setFontSize(13);
    doc.setFont("arial", "light");
	  doc.text("T: " + cases[2], 65, 57, {align:"center"});
    doc.text("T: " + cases[5], 83, 57, {align:"center"});
    doc.text("T: " + cases[8], 102, 57, {align:"center"});
    doc.text("T: " + cases[11], 120, 57, {align:"center"});
    doc.text("T: " + cases[14], 138, 57, {align:"center"});
    doc.text("T: " + cases[17], 157, 57, {align:"center"});
    doc.text("T: " + cases[20], 175, 57, {align:"center"});
    doc.text("T: " + cases[23], 193, 57, {align:"center"});
    doc.text("T: " + cases[26], 212, 57, {align:"center"});
    doc.text("T: " + cases[29], 230, 57, {align:"center"});
    doc.text("T: " + cases[32], 248, 57, {align:"center"});
205
206
207
208
209
  }

  const writeTotal = (doc: jsPDF) => {
    doc.setFontSize(20);
    doc.setFont("arial", "bold");
210
    if (key === "Tanggal")
Nabilah Adani's avatar
Nabilah Adani committed
211
      doc.text("Total Keseluruhan : " + total + " Kasus" , pageWidth/2, 155, {align:"center"})
212
213
    else 
      if (chartType)
214
        doc.text("Total Keseluruhan : " + total + " Kasus", pageWidth/2, 150, {align:"center"})
215
      else  
Nabilah Adani's avatar
Nabilah Adani committed
216
        doc.text("Total Keseluruhan : " + total + " Kasus", pageWidth/2, 150, {align:"center"})
Nabilah Adani's avatar
Nabilah Adani committed
217
  }
Sean Zeliq Urian's avatar
Sean Zeliq Urian committed
218

219
  const writeTextToPDF = (doc: jsPDF) =>  {
Nabilah Adani's avatar
Nabilah Adani committed
220
    doc.setFontSize(20);
221
    doc.setFont("arial", "italic-bold");
222
223
    if(key === "Tanggal")
      if(dataType === "")
224
        doc.text("Keseluruhan Kasus TBC di DEPOK", pageWidth/2, 170, {align:"center"});
225
      else
226
227
228
229
        if(date1st === date2nd)
          doc.text("Berdasarkan tanggal " + date1st, pageWidth/2, 170, {align:"center"})
        else
          doc.text("Berdasarkan tanggal " + date1st + " sampai " + date2nd, pageWidth/2, 170, {align:"center"})
230
    else
231
      if(dataType === "")
232
        doc.text("Keseluruhan Kasus TBC berdasarkan " + type + " " + key, pageWidth/2, 165, {align:"center"});
233
234
235
236
237
      else
        if(date1st === date2nd)
          doc.text(type + " " + key + " pada tanggal " + date1st, pageWidth/2, 165, {align:"center"});
        else
          doc.text(type + " " + key + " dari tanggal " + date1st + " sampai " + date2nd, pageWidth/2, 165, {align:"center"});
238

239
    doc.setFillColor(PIE_COLORS[0]);
240
    doc.rect(30, 190, 5, 5, 'F');
241
    doc.setFillColor(PIE_COLORS[1]);
242
    doc.rect(120, 190, 5, 5, 'F');
243
    doc.setFillColor(PIE_COLORS[2]);
244
    doc.rect(220, 190, 5, 5, 'F');
245

246
    doc.setFont("arial", "normal");
247
248
249
    doc.text("Kasus Positif", 40, 194, {align:"left"});
    doc.text("Kasus Negatif", 130, 194, {align:"left"});
    doc.text("Kasus Terduga", 230, 194, {align:"left"});
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  }

  const svgToBlob = (svg: Element) => {
    svg.setAttribute("width", "952");
    svg.setAttribute("height", "589");
    svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
    let svgURL = new XMLSerializer().serializeToString(svg);
    let svgBlob = new Blob([svgURL], { type: "image/svg+xml;charset=utf-8" });
    return svgBlob
  }

  const addImageToDoc = (img: CanvasImageSource, doc: jsPDF) => {
    let canvas = document.createElement('canvas');
    canvas.width = 952;
    canvas.height = 589;
    let context = canvas.getContext('2d')!;
    context.drawImage(img, 0, 0, context.canvas.width, context.canvas.height);
    let png = canvas.toDataURL('image/png', 1.0);
268
    if (key === "Tanggal")
269
270
      doc.addImage(png, imageType, marginX, 12, 252, 156, undefined, "SLOW");
    else 
271
272
273
274
      if (chartType)
        doc.addImage(png, imageType, pageImgWidth, pageImgHeight, imgPieWidth, imgPieHeight, undefined, "SLOW");
      else 
        doc.addImage(png, imageType, marginX, 12, imgWidth, imgHeight, undefined, "SLOW");
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  }

  const blobToImage = (blob: Blob) => {
    return new Promise<CanvasImageSource>(resolve => {
      const url = URL.createObjectURL(blob)
      let img = new Image()
      img.onload = () => {
        URL.revokeObjectURL(url)
        resolve(img)
      }
      img.src = url
    })
  }

  let svg: Element = document.getElementById(type)?.children[0]?.children[0].cloneNode(true)! as Element;
  let svgBlob = svgToBlob(svg);
  
  blobToImage(svgBlob).then(img => {
Nabilah Adani's avatar
Nabilah Adani committed
293
    header(doc);
294
    if (!chartType && key != "Tanggal"){
295
      writeInfoCases(doc);
296
297
298
299
300
301
    }
    if (key === "Tanggal"){
      writeInfoCaseP(doc);
      writeInfoCaseN(doc);
      writeInfoCaseU(doc);
    }
302
    addImageToDoc(img, doc);
303
    writeTotal(doc);
304
    writeTextToPDF(doc);
305
306
    if(key === "Tanggal")
      if (dataType === "")
307
308
        doc.save("Statistik Keseluruhan Kasus TBC.pdf");
      else
309
310
311
312
        if(date1st === date2nd)
          doc.save("Statistik berdasarkan tanggal " + date1st + ".pdf")
        else 
          doc.save("Statistik berdasarkan tanggal " + date1st + " sampai " + date2nd + ".pdf")
313
        
314
    else 
315
316
      if (dataType === "")
        doc.save("Diagram " + translateChartType(chartType) + " Keseluruhan Kasus TBC berdasarkan " + type + " " + key + ".pdf")
317
      else 
318
319
320
321
        if(date1st === date2nd)
          doc.save("Diagram " + translateChartType(chartType) + " berdasarkan "+ type + " " + key + " pada tanggal " + date1st + ".pdf");
        else 
          doc.save("Diagram " + translateChartType(chartType) + " berdasarkan "+ type + " " + key + " dari tanggal " + date1st + " sampai " + date2nd + ".pdf");
322
  });
323
324
};

325
326
const downloadAsPDF = (type: string, selectedKey: string, dataType: string, chartType: boolean, total: string, info: Array<number>) => {
  image2pdf("PNG", type, translate(selectedKey), dataType, chartType, total, info);
327
328
}

329
export { translate, renderActiveShape, image2pdf, downloadAsPDF, translateTypetoKey, translateToMonth, translateToString, translateChartType };