PluginProbe
WebTotem Security / 2.4.14
WebTotem Security v2.4.14
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.14, at includes/js/chart.js

853 lines 26.4 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 if(typeof attacks_map == "object"){
556 attacksMap();
557 }
558 });
559 }
560
561 // disk-chart
562
563 async function drawDiskChart_(elementSelector, data) {
564 // set the dimensions and margins of the graph
565 var width = 150
566 height = 150
567 margin = 1
568
569 // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
570 var radius = Math.min(width, height) / 2 - margin
571
572 // append the svg object to the div called 'my_dataviz'
573 var svg = d3.select(elementSelector)
574 .append("svg")
575 .attr("width", width)
576 .attr("height", height)
577 .append("g")
578 .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
579
580 // Create dummy data
581 // var data = {a: 9, b: 20, c:30, d:8, e:12}
582
583 // set the color scale
584 var color = d3.scaleOrdinal()
585 .domain(data)
586 .range(["#5E6977", "#3D50DF"])
587
588 // Compute the position of each group on the pie:
589 var pie = d3.pie()
590 .value(function(d) {return d.value; })
591 var data_ready = pie(d3.entries(data))
592
593 // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
594 svg
595 .selectAll('whatever')
596 .data(data_ready)
597 .enter()
598 .append('path')
599 .attr('d', d3.arc()
600 .innerRadius(30) // This is the size of the donut hole
601 .outerRadius(radius)
602 )
603 .attr('fill', function(d){ return(color(d.data.key)) })
604 .attr("stroke", "white")
605 .style("stroke-width", "15px")
606 .style("opacity", 1)
607
608 }
609
610
611 const drawDiskChart = (data) => {
612 const diskData = {use: data.used, free: data.free};
613 const discChartSelector = "#disk-chart";
614 drawDiskChart_(discChartSelector, diskData);
615 };
616
617 if(typeof disc_chart == "object") {
618 drawDiskChart(disc_chart);
619 }
620
621 /**
622 * Create chart "Attacks on world map"
623 * @returns {Promise<void>}
624 */
625 async function attacksMap() {
626
627 var countries = attacks_map['countries'];
628 var labels = attacks_map['labels'];
629 new Chart(document.getElementById("firewall"), {
630 type: "horizontalBar",
631
632 data: {
633 labels: labels,
634 datasets: [
635 {
636 backgroundColor: "#3D50DF",
637 data: attacks_map['attacks'],
638 },
639 ],
640 },
641 options: {
642 cornerRadius: 3,
643 maintainAspectRatio: false,
644 scales: {
645 yAxes: [
646 {
647 barPercentage: 0.6,
648 stacked: true,
649 gridLines: {
650 display: true,
651 },
652 },
653 ],
654 xAxes: [
655 {
656 gridLines: {
657 display: false,
658 },
659 },
660 ],
661 },
662 legend: {
663 display: false,
664 },
665 },
666 });
667
668 const fill = (country) => {
669 svg._groups[0][0].childNodes[0].childNodes.forEach((e) => {
670 if (e.__data__.properties.name === country) {
671 d3.select(e).style("fill", "#3D50DF");
672 }
673 });
674 };
675 // The svg
676 var svg = d3.select("#firewallMap"),
677 width = +svg.attr("width"),
678 height = +svg.attr("height");
679
680 // Map and projection
681 var path = d3.geoPath();
682 var projection = d3
683 .geoMercator()
684 .scale(60)
685 .center([0, 0])
686 .translate([210, 220]);
687
688 // Load external data and boot
689 d3.queue().defer(d3.json, world_map_json).await(ready);
690
691 function ready(error, topo) {
692
693 // Draw the map
694 svg.append("g")
695 .selectAll("path")
696 .data(topo.features)
697 .enter()
698 .append("path")
699 // draw each country
700 .attr("d", d3.geoPath().projection(projection))
701 // set the color of each country
702 .attr("fill", function () {
703 return "#5E6977";
704 })
705 .style("stroke", "transparent")
706 .attr("class", function () {
707 return "Country";
708 });
709 countries.map((e) => {
710 fill(e);
711 });
712 }
713
714
715 Chart.elements.Rectangle.prototype.draw = function () {
716 function t(t) {
717 return s[(f + t) % 4];
718 }
719 var r,
720 e,
721 i,
722 o,
723 _,
724 h,
725 l,
726 a,
727 b = this._chart.ctx,
728 d = this._view,
729 n = d.borderWidth,
730 u = this._chart.config.options.cornerRadius;
731 if (
732 (u < 0 && (u = 0),
733 void 0 === u && (u = 0),
734 d.horizontal
735 ? ((r = d.base),
736 (e = d.x),
737 (i = d.y - d.height / 2),
738 (o = d.y + d.height / 2),
739 (_ = e > r ? 1 : -1),
740 (h = 1),
741 (l = d.borderSkipped || "left"))
742 : ((r = d.x - d.width / 2),
743 (e = d.x + d.width / 2),
744 (i = d.y),
745 (_ = 1),
746 (h = (o = d.base) > i ? 1 : -1),
747 (l = d.borderSkipped || "bottom")),
748 n)
749 ) {
750 var T = Math.min(Math.abs(r - e), Math.abs(i - o)),
751 v = (n = n > T ? T : n) / 2,
752 g = r + ("left" !== l ? v * _ : 0),
753 c = e + ("right" !== l ? -v * _ : 0),
754 C = i + ("top" !== l ? v * h : 0),
755 w = o + ("bottom" !== l ? -v * h : 0);
756 g !== c && ((i = C), (o = w)),
757 C !== w && ((r = g), (e = c));
758 }
759 b.beginPath(),
760 (b.fillStyle = d.backgroundColor),
761 (b.strokeStyle = d.borderColor),
762 (b.lineWidth = n);
763 var s = [
764 [r, o],
765 [r, i],
766 [e, i],
767 [e, o],
768 ],
769 f = ["bottom", "left", "top", "right"].indexOf(l, 0);
770 -1 === f && (f = 0);
771 var q = t(0);
772 b.moveTo(q[0], q[1]);
773 for (var m = 1; m < 4; m++)
774 (q = t(m)),
775 (nextCornerId = m + 1),
776 4 == nextCornerId && (nextCornerId = 0),
777 (nextCorner = t(nextCornerId)),
778 (width = s[2][0] - s[1][0]),
779 (height = s[0][1] - s[1][1]),
780 (x = s[1][0]),
781 (y = s[1][1]),
782 (a = u) > Math.abs(height) / 2 &&
783 (a = Math.floor(Math.abs(height) / 2)),
784 a > Math.abs(width) / 2 &&
785 (a = Math.floor(Math.abs(width) / 2)),
786 height < 0
787 ? ((x_tl = x),
788 (x_tr = x + width),
789 (y_tl = y + height),
790 (y_tr = y + height),
791 (x_bl = x),
792 (x_br = x + width),
793 (y_bl = y),
794 (y_br = y),
795 b.moveTo(x_bl + a, y_bl),
796 b.lineTo(x_br - a, y_br),
797 b.quadraticCurveTo(x_br, y_br, x_br, y_br - a),
798 b.lineTo(x_tr, y_tr + a),
799 b.quadraticCurveTo(x_tr, y_tr, x_tr - a, y_tr),
800 b.lineTo(x_tl + a, y_tl),
801 b.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl + a),
802 b.lineTo(x_bl, y_bl - a),
803 b.quadraticCurveTo(x_bl, y_bl, x_bl + a, y_bl))
804 : width < 0
805 ? ((x_tl = x + width),
806 (x_tr = x),
807 (y_tl = y),
808 (y_tr = y),
809 (x_bl = x + width),
810 (x_br = x),
811 (y_bl = y + height),
812 (y_br = y + height),
813 b.moveTo(x_bl + a, y_bl),
814 b.lineTo(x_br - a, y_br),
815 b.quadraticCurveTo(x_br, y_br, x_br, y_br - a),
816 b.lineTo(x_tr, y_tr + a),
817 b.quadraticCurveTo(x_tr, y_tr, x_tr - a, y_tr),
818 b.lineTo(x_tl + a, y_tl),
819 b.quadraticCurveTo(x_tl, y_tl, x_tl, y_tl + a),
820 b.lineTo(x_bl, y_bl - a),
821 b.quadraticCurveTo(x_bl, y_bl, x_bl + a, y_bl))
822 : (b.moveTo(x + a, y),
823 b.lineTo(x + width - a, y),
824 b.quadraticCurveTo(
825 x + width,
826 y,
827 x + width,
828 y + a
829 ),
830 b.lineTo(x + width, y + height - a),
831 b.quadraticCurveTo(
832 x + width,
833 y + height,
834 x + width - a,
835 y + height
836 ),
837 b.lineTo(x + a, y + height),
838 b.quadraticCurveTo(
839 x,
840 y + height,
841 x,
842 y + height - a
843 ),
844 b.lineTo(x, y + a),
845 b.quadraticCurveTo(x, y, x + a, y));
846 b.fill(), n && b.stroke();
847 };
848 }
849
850 if(typeof attacks_map == "object"){
851 attacksMap();
852 }
853