PluginProbe
WebTotem Security / 2.4.2
WebTotem Security v2.4.2
3.0.2 3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 All 110 releases
wt-security / includes / js / chart.js

chart.js in WebTotem Security 2.4.2, at includes/js/chart.js

847 lines 26.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 const isDarkThemeSet = ()=> {
2 return !!document.querySelector(".wtotem_theme—dark")}
3 ;
4
5 async function drawLineChart(dataset) {
6 var diagram = document.getElementById('wtotem_chart_diagram');
7 var days = diagram.dataset.days;
8
9 const attacksAccessor = (d) => d.attacks;
10 const blockedAccessor = (d) => d.blocked;
11 const biggerAccessor = (d) =>
12 d.attacks > d.blocked ? d.attacks : d.blocked;
13 const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d");
14 const xAccessor = (d) => dateParser(d.date);
15
16
17 const chartWrapper = document.getElementById('line-chart')
18 let dimensions = {
19 width: chartWrapper.offsetWidth,
20 height: 251,
21 margin: {
22 top: 15,
23 right: 15,
24 bottom: 40,
25 left: 60,
26 },
27 };
28 dimensions.boundedWidth =
29 dimensions.width - dimensions.margin.left - dimensions.margin.right;
30 dimensions.boundedHeight =
31 dimensions.height - dimensions.margin.top - dimensions.margin.bottom;
32
33 const wrapper = d3
34 .select("#line-chart")
35 .append("svg")
36 .attr("width", dimensions.width)
37 .attr("height", dimensions.height);
38
39 const bounds = wrapper
40 .append("g")
41 .style(
42 "transform",
43 `translate(${dimensions.margin.left - 10}px, ${
44 dimensions.margin.top
45 }px)`
46 );
47
48
49 const yValues = dataset.reduce(
50 (acc, curr) => [...acc, curr.attacks, curr.blocked],
51 [0, 100]
52 );
53
54 const yScale = d3
55 .scaleLinear()
56 .domain(d3.extent(yValues))
57 .range([dimensions.boundedHeight, 0]);
58 const xScale = d3
59 .scaleTime()
60 .domain(d3.extent(dataset, xAccessor))
61 .range([0, dimensions.boundedWidth]);
62
63 function make_y_gridlines() {
64 return d3.axisLeft(yScale).ticks(5);
65 }
66
67 bounds
68 .append("g")
69 .attr("class", "grid")
70 .call(
71 make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("")
72 );
73
74 const area1 = d3
75 .area()
76 .x((d) => xScale(xAccessor(d)))
77 .y0(yScale(0))
78 .y1((d) => yScale(attacksAccessor(d)));
79
80 const area2 = d3
81 .area()
82 .x((d) => xScale(xAccessor(d)))
83 .y0(yScale(0))
84 .y1((d) => yScale(blockedAccessor(d)));
85
86 const isDarkTheme = isDarkThemeSet();
87 const minOpacity = isDarkTheme ? 0.2 : 0.1;
88 const maxOpacity = isDarkTheme ? 0.8 : 0.6;
89
90 bounds
91 .append("linearGradient")
92 .attr("id", "area-gradient1")
93 .attr("gradientUnits", "userSpaceOnUse")
94 .attr("x1", 0)
95 .attr("y1", yScale(0))
96 .attr("x2", 0)
97 .attr("y2", yScale(100))
98 .selectAll("stop")
99 .data([
100 { offset: "0%", color: "#d46c6a", opacity: minOpacity},
101 { offset: "100%", color: "#d46c6a", opacity: maxOpacity},
102 ])
103 .enter()
104 .append("stop")
105 .attr("offset", function (d) {
106 return d.offset;
107 })
108 .attr("stop-color", function (d) {
109 return d.color;
110 })
111 .attr("stop-opacity", function (d) {
112 return d.opacity;
113 });
114
115 bounds
116 .append("linearGradient")
117 .attr("id", "area-gradient2")
118 .attr("gradientUnits", "userSpaceOnUse")
119 .attr("x1", 0)
120 .attr("y1", yScale(0))
121 .attr("x2", 0)
122 .attr("y2", yScale(100))
123 .selectAll("stop")
124 .data([
125 { offset: "0%", color: "#bace3d", opacity: minOpacity },
126 { offset: "100%", color: "#bace3d", opacity: maxOpacity},
127 ])
128 .enter()
129 .append("stop")
130 .attr("offset", function (d) {
131 return d.offset;
132 })
133 .attr("stop-color", function (d) {
134 return d.color;
135 })
136 .attr("stop-opacity", function (d) {
137 return d.opacity;
138 });
139
140 const lineGenerator1 = d3
141 .line()
142 .x((d) => xScale(xAccessor(d)))
143 .y((d) => yScale(attacksAccessor(d)));
144 const lineGenerator2 = d3
145 .line()
146 .x((d) => xScale(xAccessor(d)))
147 .y((d) => yScale(attacksAccessor(d)));
148
149 const line1 = bounds
150 .append("path")
151 .datum(dataset)
152 .attr("d", lineGenerator1(dataset))
153 .attr("class", "area")
154 .attr("d", area1)
155 .style("fill", "url(#area-gradient1)");
156
157 const line2 = bounds
158 .append("path")
159 .datum(dataset)
160 .attr("d", lineGenerator2(dataset))
161 .attr("class", "area")
162 .attr("d", area2)
163 .style("fill", "url(#area-gradient2)");
164
165 const yAxisGenerator = d3.axisLeft().scale(yScale);
166 // const xAxisGenerator = d3.axisBottom().scale(xScale);
167
168 let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d");
169 const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) :
170 (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) :
171 (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) :
172 d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat);
173 //const xAxisGenerator = d3.axisBottom().scale(xScale).ticks(ticks).tickFormat(dateFormat);
174
175 const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator);
176 const xAxis = bounds
177 .append("g")
178 .call(xAxisGenerator)
179 .attr("class", "axis chart-date")
180 .style("transform", `translateY(${dimensions.boundedHeight}px)`);
181
182 const listeningRect = bounds
183 .append("rect")
184 .attr("class", "listening-rect")
185 .attr("width", dimensions.boundedWidth)
186 .attr("height", dimensions.boundedHeight)
187 .on("mousemove", onMouseMove)
188 .on("mouseleave", onMouseLeave);
189
190 const tooltipAttacks = d3.select("#tooltipAttacks");
191 const tooltipBlocked = d3.select("#tooltipBlocked");
192 const tooltipCircle1 = bounds
193 .append("circle")
194 .attr("class", "tooltip-circle")
195 .attr("r", 4)
196 .attr("stroke", "#F3F5F6")
197 .attr("fill", "#1D293F")
198 .attr("stroke-width", 2)
199 .style("opacity", 0);
200 const tooltipCircle2 = bounds
201 .append("circle")
202 .attr("class", "tooltip-circle")
203 .attr("r", 4)
204 .attr("stroke", "#F3F5F6")
205 .attr("fill", "#1D293F")
206 .attr("stroke-width", 2)
207 .style("opacity", 0);
208 function onMouseMove() {
209 const mousePosition = d3.mouse(this);
210 const hoveredDate = xScale.invert(mousePosition[0]);
211
212 const getDistanceFromHoveredDate = (d) =>
213 Math.abs(xAccessor(d) - hoveredDate);
214 const closestIndex = d3.scan(
215 dataset,
216 (a, b) =>
217 getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b)
218 );
219 const closestDataPoint = dataset[closestIndex];
220
221 const closestXValue = xAccessor(closestDataPoint);
222 const closestAttacksValue = attacksAccessor(closestDataPoint);
223 const closestBlockedValue = blockedAccessor(closestDataPoint);
224
225 const x = xScale(closestXValue) + dimensions.margin.left + 8;
226 const yAttacks =
227 yScale(closestAttacksValue) + dimensions.margin.top + 10;
228 const yBlocked =
229 yScale(closestBlockedValue) + dimensions.margin.top + 10;
230
231 tooltipAttacks.style(
232 "transform",
233 `translate(` +
234 `calc( -50% + ${x}px),` +
235 `calc(-100% + ${yAttacks}px)` +
236 `)`
237 );
238 tooltipBlocked.style(
239 "transform",
240 `translate(` +
241 `calc( -50% + ${x}px),` +
242 `calc(-100% + ${yBlocked}px)` +
243 `)`
244 );
245
246 tooltipAttacks.style("opacity", 1);
247 tooltipBlocked.style("opacity", 1);
248
249 tooltipAttacks.select("#countAttacks").html(closestAttacksValue);
250 tooltipBlocked.select("#countBlocked").html(closestBlockedValue);
251 tooltipCircle1
252 .attr("cx", xScale(closestXValue))
253 .attr("cy", yScale(closestAttacksValue))
254 .style("opacity", 1);
255 tooltipCircle2
256 .attr("cx", xScale(closestXValue))
257 .attr("cy", yScale(closestBlockedValue))
258 .style("opacity", 1);
259 }
260
261 function onMouseLeave() {
262 tooltipAttacks.style("opacity", 0);
263 tooltipBlocked.style("opacity", 0);
264
265 tooltipCircle1.style("opacity", 0);
266 tooltipCircle2.style("opacity", 0);
267 }
268 }
269
270 const drawWafChart = (data) => {
271 var firewallChart = d3.select("#line-chart").selectAll("svg")
272 firewallChart = firewallChart.remove();
273 drawLineChart(data);
274 };
275
276 if(typeof waf_chart == "object"){
277 drawWafChart(waf_chart);
278 }
279
280 var resizeTimerFirewallChart;
281 window.onresize = function (event) {
282 clearTimeout(resizeTimerFirewallChart);
283 resizeTimerFirewallChart = setTimeout(function () {
284 drawLineChart(waf_chart);
285 }, 10);
286 };
287
288 // server-status
289 async function drawServerStatusChart(id, elementSelector, tooltipSelector, tooltipValueSelector, color, dataset) {
290 const dataAccessor = (d) => d.value;
291
292 let diagram = document.querySelector(elementSelector);
293 let days = diagram.dataset.days;
294
295 const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d");
296
297 const xAccessor = (d) => dateParser(d.date);
298
299 const chartWrapper = document.querySelector(elementSelector);
300 let dimensions = {
301 width: chartWrapper.offsetWidth,
302 height: 251,
303 margin: {
304 top: 15,
305 right: 15,
306 bottom: 40,
307 left: 60,
308 },
309 };
310 dimensions.boundedWidth =
311 dimensions.width - dimensions.margin.left - dimensions.margin.right;
312 dimensions.boundedHeight =
313 dimensions.height - dimensions.margin.top - dimensions.margin.bottom;
314
315 const wrapper = d3
316 .select(elementSelector)
317 .append("svg")
318 .attr("width", dimensions.width)
319 .attr("height", dimensions.height);
320
321 const bounds = wrapper
322 .append("g")
323 .style(
324 "transform",
325 `translate(${dimensions.margin.left - 10}px, ${
326 dimensions.margin.top
327 }px)`
328 );
329
330 const yValues = dataset.reduce(
331 (acc, curr) => [...acc, curr.value],
332 [0, 100]
333 );
334
335 const yScale = d3
336 .scaleLinear()
337 .domain(d3.extent(yValues))
338 .range([dimensions.boundedHeight, 0]);
339 const xScale = d3
340 .scaleTime()
341 .domain(d3.extent(dataset, xAccessor))
342 .range([0, dimensions.boundedWidth]);
343
344 function make_y_gridlines() {
345 return d3.axisLeft(yScale).ticks(5);
346 }
347
348 bounds
349 .append("g")
350 .attr("class", "grid")
351 .call(
352 make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("")
353 );
354
355 const area1 = d3
356 .area()
357 .x((d) => xScale(xAccessor(d)))
358 .y0(yScale(0))
359 .y1((d) => yScale(dataAccessor(d)));
360
361 const gradientAreaId = "area-gradient-" + id;
362
363 const isDarkTheme = isDarkThemeSet();
364 const minOpacity = isDarkTheme ? 0.2 : 0.1;
365 const maxOpacity = isDarkTheme ? 0.8 : 0.6;
366
367 bounds
368 .append("linearGradient")
369 .attr("id", gradientAreaId)
370 .attr("gradientUnits", "userSpaceOnUse")
371 .attr("x1", 0)
372 .attr("y1", yScale(0))
373 .attr("x2", 0)
374 .attr("y2", yScale(100))
375 .selectAll("stop")
376 .data([
377 { offset: "0%", color: color, opacity: minOpacity },
378 { offset: "100%", color: color, opacity: maxOpacity },
379 ])
380 .enter()
381 .append("stop")
382 .attr("offset", function (d) {
383 return d.offset;
384 })
385 .attr("stop-color", function (d) {
386 return d.color;
387 })
388 .attr("stop-opacity", function (d) {
389 return d.opacity;
390 });
391
392 const lineGenerator1 = d3
393 .line()
394 .x((d) => xScale(xAccessor(d)))
395 .y((d) => yScale(dataAccessor(d)));
396
397 const line1 = bounds
398 .append("path")
399 .datum(dataset)
400 .attr("d", lineGenerator1(dataset))
401 .attr("class", "area")
402 .attr("d", area1)
403 .style("fill", "url(#"+gradientAreaId+")");
404
405 const yAxisGenerator = d3.axisLeft().scale(yScale);
406 // const xAxisGenerator = d3.axisBottom().scale(xScale);
407 let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d");
408 const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) :
409 (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) :
410 (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) :
411 d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat);
412
413 const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator);
414 const xAxis = bounds
415 .append("g")
416 .call(xAxisGenerator)
417 .attr("class", "axis")
418 .style("transform", `translateY(${dimensions.boundedHeight}px)`);
419
420 const listeningRect = bounds
421 .append("rect")
422 .attr("class", "listening-rect")
423 .attr("width", dimensions.boundedWidth)
424 .attr("height", dimensions.boundedHeight)
425 .on("mousemove", onMouseMove)
426 .on("mouseleave", onMouseLeave);
427
428 const tooltipData = d3.select(tooltipSelector);
429 const tooltipCircle1 = bounds
430 .append("circle")
431 .attr("class", "tooltip-circle")
432 .attr("r", 4)
433 .attr("stroke", "#F3F5F6")
434 .attr("fill", "#1D293F")
435 .attr("stroke-width", 2)
436 .style("opacity", 0);
437
438 function onMouseMove() {
439 const mousePosition = d3.mouse(this);
440 const hoveredDate = xScale.invert(mousePosition[0]);
441
442 const getDistanceFromHoveredDate = (d) =>
443 Math.abs(xAccessor(d) - hoveredDate);
444 const closestIndex = d3.scan(
445 dataset,
446 (a, b) =>
447 getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b)
448 );
449 const closestDataPoint = dataset[closestIndex];
450
451 const closestXValue = xAccessor(closestDataPoint);
452 const closestValue = dataAccessor(closestDataPoint);
453
454 const x = xScale(closestXValue) + dimensions.margin.left + 8;
455 const yAttacks =
456 yScale(closestValue) + dimensions.margin.top + 10;
457
458 tooltipData.style(
459 "transform",
460 `translate(` +
461 `calc( -50% + ${x}px),` +
462 `calc(-100% + ${yAttacks}px)` +
463 `)`
464 );
465
466 tooltipData.style("opacity", 1);
467
468 tooltipData.select(tooltipValueSelector).html(closestValue);
469 tooltipCircle1
470 .attr("cx", xScale(closestXValue))
471 .attr("cy", yScale(closestValue))
472 .style("opacity", 1);
473 }
474
475 function onMouseLeave() {
476 tooltipData.style("opacity", 0);
477 tooltipCircle1.style("opacity", 0);
478 }
479 }
480
481 const drawRamChart = (data) => {
482 const ramChartSelector = "#ram-chart";
483 const ramTooltipSelector = "#tooltipRam";
484 const ramTooltipValueSelector = "#countRam";
485 const ramChartColor = "#3d50df";
486
487
488 let chartRam = d3.select(ramChartSelector).selectAll("svg")
489 chartRam = chartRam.remove();
490
491 drawServerStatusChart("ram", ramChartSelector, ramTooltipSelector, ramTooltipValueSelector, ramChartColor, data);
492 }
493
494
495 if(typeof ram_chart == "object"){
496 drawRamChart(ram_chart);
497 }
498
499
500 const drawCpuChart = (data) => {
501 const cpuChartSelector = "#cpu-chart";
502 const cpuTooltipSelector = "#tooltipCpu";
503 const cpuTooltipValueSelector = "#countCpu";
504 const cpuChartColor = "#6d3594";
505
506 let chartCpu = d3.select(cpuChartSelector).selectAll("svg");
507 chartCpu = chartCpu.remove();
508
509 drawServerStatusChart("cpu", cpuChartSelector, cpuTooltipSelector, cpuTooltipValueSelector, cpuChartColor, data);
510 }
511
512 if(typeof cpu_chart == "object") {
513 drawCpuChart(cpu_chart);
514 }
515
516
517 var resizeTimerRamChart;
518 var resizeTimerCpuChart;
519
520 window.onresize = function (event) {
521
522 if (document.querySelector("#ram-chart") !== null) {
523 clearTimeout(resizeTimerRamChart);
524 resizeTimerRamChart = setTimeout(function () {
525 if(typeof ram_chart == "object") {
526 drawRamChart(ram_chart);
527 }
528 }, 10);
529 }
530
531 if (document.querySelector("#cpu-chart") !== null) {
532 clearTimeout(resizeTimerCpuChart);
533 resizeTimerCpuChart = setTimeout(function () {
534 if(typeof cpu_chart == "object") {
535 drawCpuChart(cpu_chart);
536 }
537 }, 10);
538 }
539 };
540
541
542 const colorModeToggle = document.querySelector("#color_scheme_toggle");
543 if(colorModeToggle){
544 const addThemeChangeEventListener = (callback)=>{
545 colorModeToggle.addEventListener("change", callback)
546 }
547
548 addThemeChangeEventListener(()=>{
549 if(typeof cpu_chart == "object") {
550 drawCpuChart(cpu_chart);
551 }
552 if(typeof ram_chart == "object") {
553 drawRamChart(ram_chart);
554 }
555 });
556 }
557
558 // disk-chart
559
560 async function drawDiskChart_(elementSelector, data) {
561 // set the dimensions and margins of the graph
562 var width = 150
563 height = 150
564 margin = 1
565
566 // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
567 var radius = Math.min(width, height) / 2 - margin
568
569 // append the svg object to the div called 'my_dataviz'
570 var svg = d3.select(elementSelector)
571 .append("svg")
572 .attr("width", width)
573 .attr("height", height)
574 .append("g")
575 .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
576
577 // Create dummy data
578 // var data = {a: 9, b: 20, c:30, d:8, e:12}
579
580 // set the color scale
581 var color = d3.scaleOrdinal()
582 .domain(data)
583 .range(["#5E6977", "#3D50DF"])
584
585 // Compute the position of each group on the pie:
586 var pie = d3.pie()
587 .value(function(d) {return d.value; })
588 var data_ready = pie(d3.entries(data))
589
590 // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
591 svg
592 .selectAll('whatever')
593 .data(data_ready)
594 .enter()
595 .append('path')
596 .attr('d', d3.arc()
597 .innerRadius(30) // This is the size of the donut hole
598 .outerRadius(radius)
599 )
600 .attr('fill', function(d){ return(color(d.data.key)) })
601 .attr("stroke", "white")
602 .style("stroke-width", "15px")
603 .style("opacity", 1)
604
605 }
606
607
608 const drawDiskChart = (data) => {
609 const diskData = {use: data['use'], free: data['free']};
610 const discChartSelector = "#disk-chart";
611 drawDiskChart_(discChartSelector, diskData);
612 };
613
614 if(typeof disc_chart == "object") {
615 drawDiskChart(disc_chart);
616 }
617
618 /**
619 * Create chart "Attacks on world map"
620 * @returns {Promise<void>}
621 */
622 async function attacksMap() {
623
624 var countries = attacks_map['countries'];
625 var labels = attacks_map['labels'];
626 new Chart(document.getElementById("firewall"), {
627 type: "horizontalBar",
628
629 data: {
630 labels: labels,
631 datasets: [
632 {
633 backgroundColor: "#3D50DF",
634 data: attacks_map['attacks'],
635 },
636 ],
637 },
638 options: {
639 cornerRadius: 3,
640 maintainAspectRatio: false,
641 scales: {
642 yAxes: [
643 {
644 barPercentage: 0.6,
645 stacked: true,
646 gridLines: {
647 display: true,
648 },
649 },
650 ],
651 xAxes: [
652 {
653 gridLines: {
654 display: false,
655 },
656 },
657 ],
658 },
659 legend: {
660 display: false,
661 },
662 },
663 });
664
665 const fill = (country) => {
666 svg._groups[0][0].childNodes[0].childNodes.forEach((e) => {
667 if (e.__data__.properties.name === country) {
668 d3.select(e).style("fill", "#3D50DF");
669 }
670 });
671 };
672 // The svg
673 var svg = d3.select("#firewallMap"),
674 width = +svg.attr("width"),
675 height = +svg.attr("height");
676
677 // Map and projection
678 var path = d3.geoPath();
679 var projection = d3
680 .geoMercator()
681 .scale(60)
682 .center([0, 0])
683 .translate([210, 220]);
684
685 // Load external data and boot
686 d3.queue().defer(d3.json, world_map_json).await(ready);
687
688 function ready(error, topo) {
689
690 // Draw the map
691 svg.append("g")
692 .selectAll("path")
693 .data(topo.features)
694 .enter()
695 .append("path")
696 // draw each country
697 .attr("d", d3.geoPath().projection(projection))
698 // set the color of each country
699 .attr("fill", function () {
700 return "#5E6977";
701 })
702 .style("stroke", "transparent")
703 .attr("class", function () {
704 return "Country";
705 });
706 countries.map((e) => {
707 fill(e);
708 });
709 }
710
711
712 Chart.elements.Rectangle.prototype.draw = function () {
713 function t(t) {
714 return s[(f + t) % 4];
715 }
716 var r,
717 e,
718 i,
719 o,
720 _,
721 h,
722 l,
723 a,
724 b = this._chart.ctx,
725 d = this._view,
726 n = d.borderWidth,
727 u = this._chart.config.options.cornerRadius;
728 if (
729 (u < 0 && (u = 0),
730 void 0 === u && (u = 0),
731 d.horizontal
732 ? ((r = d.base),
733 (e = d.x),
734 (i = d.y - d.height / 2),
735 (o = d.y + d.height / 2),
736 (_ = e > r ? 1 : -1),
737 (h = 1),
738 (l = d.borderSkipped || "left"))
739 : ((r = d.x - d.width / 2),
740 (e = d.x + d.width / 2),
741 (i = d.y),
742 (_ = 1),
743 (h = (o = d.base) > i ? 1 : -1),
744 (l = d.borderSkipped || "bottom")),
745 n)
746 ) {
747 var T = Math.min(Math.abs(r - e), Math.abs(i - o)),
748 v = (n = n > T ? T : n) / 2,
749 g = r + ("left" !== l ? v * _ : 0),
750 c = e + ("right" !== l ? -v * _ : 0),
751 C = i + ("top" !== l ? v * h : 0),
752 w = o + ("bottom" !== l ? -v * h : 0);
753 g !== c && ((i = C), (o = w)),
754 C !== w && ((r = g), (e = c));
755 }
756 b.beginPath(),
757 (b.fillStyle = d.backgroundColor),
758 (b.strokeStyle = d.borderColor),
759 (b.lineWidth = n);
760 var s = [
761 [r, o],
762 [r, i],
763 [e, i],
764 [e, o],
765 ],
766 f = ["bottom", "left", "top", "right"].indexOf(l, 0);
767 -1 === f && (f = 0);
768 var q = t(0);
769 b.moveTo(q[0], q[1]);
770 for (var m = 1; m < 4; m++)
771 (q = t(m)),
772 (nextCornerId = m + 1),
773 4 == nextCornerId && (nextCornerId = 0),
774 (nextCorner = t(nextCornerId)),
775 (width = s[2][0] - s[1][0]),
776 (height = s[0][1] - s[1][1]),
777 (x = s[1][0]),
778 (y = s[1][1]),
779 (a = u) > Math.abs(height) / 2 &&
780 (a = Math.floor(Math.abs(height) / 2)),
781 a > Math.abs(width) / 2 &&
782 (a = Math.floor(Math.abs(width) / 2)),
783 height < 0
784 ? ((x_tl = x),
785 (x_tr = x + width),
786 (y_tl = y + height),
787 (y_tr = y + height),
788 (x_bl = x),
789 (x_br = x + width),
790 (y_bl = y),
791 (y_br = y),
792 b.moveTo(x_bl + a, y_bl),
793 b.lineTo(x_br - a, y_br),
794 b.quadraticCurveTo(x_br, y_br, x_br, y_br - a),
795 b.lineTo(x_tr, y_tr + a),
796 b.quadraticCurveTo(x_tr, y_tr, x_tr - a, y_tr),
797 b.lineTo(x_tl + a, y_tl),
798 b.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl + a),
799 b.lineTo(x_bl, y_bl - a),
800 b.quadraticCurveTo(x_bl, y_bl, x_bl + a, y_bl))
801 : width < 0
802 ? ((x_tl = x + width),
803 (x_tr = x),
804 (y_tl = y),
805 (y_tr = y),
806 (x_bl = x + width),
807 (x_br = x),
808 (y_bl = y + height),
809 (y_br = y + height),
810 b.moveTo(x_bl + a, y_bl),
811 b.lineTo(x_br - a, y_br),
812 b.quadraticCurveTo(x_br, y_br, x_br, y_br - a),
813 b.lineTo(x_tr, y_tr + a),
814 b.quadraticCurveTo(x_tr, y_tr, x_tr - a, y_tr),
815 b.lineTo(x_tl + a, y_tl),
816 b.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl + a),
817 b.lineTo(x_bl, y_bl - a),
818 b.quadraticCurveTo(x_bl, y_bl, x_bl + a, y_bl))
819 : (b.moveTo(x + a, y),
820 b.lineTo(x + width - a, y),
821 b.quadraticCurveTo(
822 x + width,
823 y,
824 x + width,
825 y + a
826 ),
827 b.lineTo(x + width, y + height - a),
828 b.quadraticCurveTo(
829 x + width,
830 y + height,
831 x + width - a,
832 y + height
833 ),
834 b.lineTo(x + a, y + height),
835 b.quadraticCurveTo(
836 x,
837 y + height,
838 x,
839 y + height - a
840 ),
841 b.lineTo(x, y + a),
842 b.quadraticCurveTo(x, y, x + a, y));
843 b.fill(), n && b.stroke();
844 };
845 }
846
847