From 77de17a784a072428eeb02c9008ca726f503a9bc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 16 Feb 2024 12:18:02 +0800 Subject: [PATCH] update feat(DateTime): add Chart datalabel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 更改命名空间 * test: 移除命名空间 * refactor: 移除命名空间 * feat: 增加扩展方法 * refactor: 使用扩展方法 * test: 更新单元测试 --- .../BootstrapBlazor.Server.csproj | 3 +- .../Components/Samples/Charts/Bar.razor | 11 +++++ .../Components/Samples/Charts/Bar.razor.cs | 48 ++++++++++++++++++- src/BootstrapBlazor.Server/Locales/en-US.json | 6 ++- src/BootstrapBlazor.Server/Locales/zh-CN.json | 6 ++- .../DateTimePicker/DatePickerBody.razor.cs | 40 ++-------------- .../InputNumber/BootstrapInputNumber.razor.cs | 1 - .../BootstrapBlazorOptionsExtensions.cs | 2 +- .../Extensions/DateTimeExtensions.cs | 42 ++++++++++++++++ .../Components/Chart/Chart.razor.js | 31 ++++++++++-- .../Chart/ChartDataLabelPosition.cs | 31 ++++++++++++ .../Components/Chart/ChartDataset.cs | 10 +++- .../Components/Chart/ChartOptions.cs | 22 +++++++++ .../wwwroot/js/chartjs-plugin-datalabels.js | 7 +++ .../UnitTest/Components/DateTimePickerTest.cs | 19 ++------ .../Options/BootstrapBlazorOptionsTest.cs | 2 - 16 files changed, 213 insertions(+), 68 deletions(-) create mode 100644 src/BootstrapBlazor/Extensions/DateTimeExtensions.cs create mode 100644 src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataLabelPosition.cs create mode 100644 src/Extensions/Components/BootstrapBlazor.Chart/wwwroot/js/chartjs-plugin-datalabels.js diff --git a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj index dc5ae4040..f3d280b87 100644 --- a/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj +++ b/src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj @@ -34,7 +34,7 @@ - + @@ -64,6 +64,7 @@ + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor index 556df7c7a..2a24339d3 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor @@ -47,3 +47,14 @@ Name="BarAspectRatio"> + + + + + + + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs index 53deddaf9..aae27d225 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Charts/Bar.razor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ +using DocumentFormat.OpenXml.Office2010.Excel; + namespace BootstrapBlazor.Server.Components.Samples.Charts; /// @@ -53,7 +55,6 @@ public partial class Bar { ds.Options.Title = "Bar Histogram"; } - ds.Options.X.Title = "days"; ds.Options.Y.Title = "Numerical value"; ds.Options.X.Stacked = stacked; @@ -177,4 +178,49 @@ public partial class Bar } return Task.FromResult(ds); } + + private Task OnInitShowDataLabel(bool showDataLabel, bool setTitle = true) + { + var ds = new ChartDataSource(); + if (setTitle) + { + ds.Options.Title = "Bar Histogram"; + } + ds.Options.ShowLegend = false; + ds.Options.ShowDataLabel = showDataLabel; + ds.Options.Align = ChartDataLabelPosition.Start; + ds.Options.Anchor = ChartDataLabelPosition.End; + ds.Options.ChartDataLabelColor = "black"; + ds.Options.X.Title = "days"; + ds.Options.Y.Title = "Numerical value"; + ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString()); + ds.Data.Add(new ChartDataset() + { + Label = $"Set {0}", + Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast() + }); + return Task.FromResult(ds); + } + + private Task OnInitBarColorSeparately(bool barColorSeparately, bool setTitle = true) + { + var ds = new ChartDataSource(); + if (setTitle) + { + ds.Options.Title = "Bar Histogram"; + } + ds.Options.ShowLegend = false; + ds.Options.BarColorSeparately = barColorSeparately; + ds.Options.X.Title = "days"; + ds.Options.Y.Title = "Numerical value"; + ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString()); + ds.Data.Add(new ChartDataset() + { + Label = $"Set {0}", + Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast(), + BackgroundColor = ["rgb(54, 162, 235, 0.5)", "rgb(75, 192, 192, 0.5)", "rgb(255, 99, 132, 0.5)", "rgb(255, 159, 64, 0.5)", "rgb(255, 205, 86, 0.5)", "rgb(255, 99, 71, 0.5)", "rgb(255, 192, 203, 0.5)"], + BorderColor = ["rgb(54, 162, 235)", "rgb(75, 192, 192)", "rgb(255, 99, 132)", "rgb(255, 159, 64)", "rgb(255, 205, 86)", "rgb(255, 99, 71)", "rgb(255, 192, 203)"] + }); + return Task.FromResult(ds); + } } diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index f92839a87..e0ad46b09 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -566,7 +566,11 @@ "BarTwoYAxesTitle": "Double Y axis", "BarTwoYAxesIntro": "Show secondary Y axis: alignment, title and data group", "BarAspectRatioTitle": "Chart ratio", - "BarAspectRatioIntro": "Setting the height and width will automatically disable the constraint chart ratio, and the chart will fill the container" + "BarAspectRatioIntro": "Setting the height and width will automatically disable the constraint chart ratio, and the chart will fill the container", + "BarShowDataLabelTitle": "Display chart data values", + "BarShowDataLabelIntro": "By setting ShowDataLabel property,control whether to display chart data values", + "BarColorSeparatelyTitle": "Set bar chart colors separately", + "BarColorSeparatelyIntro": "By setting BarColorSeparately property,control whether to Set bar chart colors separately,and By setting BackgroundColor property, set bar chart color" }, "BootstrapBlazor.Server.Components.Samples.Transitions": { "TransitionsTitle": "Transition effect", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index fc370a707..e242f50b5 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -566,7 +566,11 @@ "BarTwoYAxesTitle": "双Y轴", "BarTwoYAxesIntro": "显示第二Y轴:对齐方式,标题和对应数据组", "BarAspectRatioTitle": "图表比例", - "BarAspectRatioIntro": "设置了高度和宽度,会自动禁用约束图表比例, 图表充满容器" + "BarAspectRatioIntro": "设置了高度和宽度,会自动禁用约束图表比例, 图表充满容器", + "BarShowDataLabelTitle": "显示图表数据值", + "BarShowDataLabelIntro": "通过设置ShowDataLabel 属性,控制是否显示数据值", + "BarColorSeparatelyTitle": "单独设置柱状图颜色", + "BarColorSeparatelyIntro": "通过设置BarColorSeparately属性,控制是否单独设置柱状图颜色,以及通过BackgroundColor 集合设置柱状图颜色" }, "BootstrapBlazor.Server.Components.Samples.Transitions": { "TransitionsTitle": "Transition 过渡效果", diff --git a/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs b/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs index 21511d83a..d657b1c40 100644 --- a/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs +++ b/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs @@ -452,7 +452,7 @@ public partial class DatePickerBody private void OnClickPrevMonth() { ShowTimePicker = false; - CurrentDate = GetSafeMonthDateTime(CurrentDate, -1); + CurrentDate = CurrentDate.GetSafeMonthDateTime(-1); Ranger?.UpdateStart(CurrentDate); } @@ -472,7 +472,7 @@ public partial class DatePickerBody private void OnClickNextMonth() { ShowTimePicker = false; - CurrentDate = GetSafeMonthDateTime(CurrentDate, 1); + CurrentDate = CurrentDate.GetSafeMonthDateTime(1); Ranger?.UpdateEnd(CurrentDate); } @@ -567,7 +567,7 @@ public partial class DatePickerBody /// /// /// - private DateTime GetMonth(int month) => GetSafeMonthDateTime(CurrentDate, month - CurrentDate.Month); + private DateTime GetMonth(int month) => CurrentDate.GetSafeMonthDateTime(month - CurrentDate.Month); /// /// 获取 月视图下的月份单元格样式 @@ -686,40 +686,6 @@ public partial class DatePickerBody return @base; } - /// - /// - /// - /// - /// - /// - protected static DateTime GetSafeMonthDateTime(DateTime dt, int month) - { - var @base = dt; - if (month < 0) - { - if (DateTime.MinValue.AddMonths(0 - month) < dt) - { - @base = dt.AddMonths(month); - } - else - { - @base = DateTime.MinValue.Date; - } - } - else if (month > 0) - { - if (DateTime.MaxValue.AddMonths(0 - month) > dt) - { - @base = dt.AddMonths(month); - } - else - { - @base = DateTime.MaxValue.Date; - } - } - return @base; - } - /// /// /// diff --git a/src/BootstrapBlazor/Components/InputNumber/BootstrapInputNumber.razor.cs b/src/BootstrapBlazor/Components/InputNumber/BootstrapInputNumber.razor.cs index 772a458be..3c7761b3a 100644 --- a/src/BootstrapBlazor/Components/InputNumber/BootstrapInputNumber.razor.cs +++ b/src/BootstrapBlazor/Components/InputNumber/BootstrapInputNumber.razor.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ -using BootstrapBlazor.Extensions; using Microsoft.Extensions.Localization; using System.Globalization; diff --git a/src/BootstrapBlazor/Extensions/BootstrapBlazorOptionsExtensions.cs b/src/BootstrapBlazor/Extensions/BootstrapBlazorOptionsExtensions.cs index 96be72754..1224db8b1 100644 --- a/src/BootstrapBlazor/Extensions/BootstrapBlazorOptionsExtensions.cs +++ b/src/BootstrapBlazor/Extensions/BootstrapBlazorOptionsExtensions.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ -namespace BootstrapBlazor.Extensions; +namespace BootstrapBlazor.Components; /// /// BootstrapBlazorOptions 配置类扩展方法 diff --git a/src/BootstrapBlazor/Extensions/DateTimeExtensions.cs b/src/BootstrapBlazor/Extensions/DateTimeExtensions.cs new file mode 100644 index 000000000..5572c4fed --- /dev/null +++ b/src/BootstrapBlazor/Extensions/DateTimeExtensions.cs @@ -0,0 +1,42 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +internal static class DateTimeExtensions +{ + /// + /// 获得安全的月份时间 + /// + /// + /// + /// + public static DateTime GetSafeMonthDateTime(this DateTime dt, int month) + { + var @base = dt; + if (month < 0) + { + if (DateTime.MinValue.AddMonths(0 - month) < dt) + { + @base = dt.AddMonths(month); + } + else + { + @base = DateTime.MinValue.Date; + } + } + else if (month > 0) + { + if (DateTime.MaxValue.AddMonths(0 - month) > dt) + { + @base = dt.AddMonths(month); + } + else + { + @base = DateTime.MaxValue.Date; + } + } + return @base; + } +} diff --git a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/Chart.razor.js b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/Chart.razor.js index 2db78cbf4..70c73281f 100644 --- a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/Chart.razor.js +++ b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/Chart.razor.js @@ -1,6 +1,8 @@ import '../../js/chart.js' +import '../../js/chartjs-plugin-datalabels.js' import Data from '../../../BootstrapBlazor/modules/data.js' import EventHandler from "../../../BootstrapBlazor/modules/event-handler.js" +Chart.register(ChartDataLabels) //注册插件 const chartOption = { options: { @@ -165,12 +167,18 @@ const getChartOption = function (option) { config = { ...chartOption } - colorFunc = function (data) { - const color = chartColors[colors.shift()] + if (option.options.barColorSeparately) { + colorFunc = function (data) { + data.borderWidth = 1 + } + } else { + colorFunc = function (data) { + const color = chartColors[colors.shift()] - data.backgroundColor = Chart.helpers.color(color).alpha(0.5).rgbString() - data.borderColor = color - data.borderWidth = 1 + data.backgroundColor = Chart.helpers.color(color).alpha(0.5).rgbString() + data.borderColor = color + data.borderWidth = 1 + } } } else if (option.type === 'pie' || option.type === 'doughnut') { @@ -193,6 +201,7 @@ const getChartOption = function (option) { data.backgroundColor = colors.slice(0, data.data.length).map(function (name) { return chartColors[name] }) + data.borderColor = 'white' } if (option.type === 'doughnut') { @@ -285,6 +294,18 @@ const getChartOption = function (option) { title: { display: option.options.title != null, text: option.options.title + + }, + //配置datalabel显示 + datalabels: { + anchor: option.options.anchor, + align: option.options.align, + formatter: Math.round, + display: option.options.showDataLabel, + color: option.options.chartDataLabelColor, + font: { + weight: 'bold' + } } }, scales: scale diff --git a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataLabelPosition.cs b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataLabelPosition.cs new file mode 100644 index 000000000..f5aa83aa4 --- /dev/null +++ b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataLabelPosition.cs @@ -0,0 +1,31 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using System.ComponentModel; + +namespace BootstrapBlazor.Components; + +/// +/// Chart DataLabel 对齐方式 +/// +public enum ChartDataLabelPosition +{ + /// + /// 上 + /// + [Description("start")] + Start = 1, + + /// + /// 下 + /// + [Description("center")] + Center = 2, + + /// + /// 左 + /// + [Description("end")] + End = 3, +} diff --git a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataset.cs b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataset.cs index 4cab654c0..47ebcd658 100644 --- a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataset.cs +++ b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartDataset.cs @@ -68,6 +68,12 @@ public class ChartDataset /// 获得/设置 折线图(Line) 宽度 默认 3 个像素 /// public double BorderWidth { get; set; } = 3; - - + /// + /// 获得/设置 柱状图的颜色数组 + /// + public string[] BackgroundColor { get; set; } = { "rgb(255, 205, 86, 0)" }; + /// + /// 获得/设置 柱状图的边框颜色数组 + /// + public string[] BorderColor { get; set; } = { "rgb(255, 205, 86, 0)" }; } diff --git a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartOptions.cs b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartOptions.cs index c723f2182..7cb6b698a 100644 --- a/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartOptions.cs +++ b/src/Extensions/Components/BootstrapBlazor.Chart/Components/Chart/ChartOptions.cs @@ -153,4 +153,26 @@ public class ChartOptions /// 获得/设置 X轴网格刻度线颜色 /// public string? YScalesGridTickColor { get; set; } + /// + /// 获得/设置 是否显示柱状图数据值 + /// + public bool ShowDataLabel { get; set; } + /// + /// 获得/设置 是否单独设置柱状图颜色 + /// + public bool BarColorSeparately { get; set; } + /// + /// 获得/设置 柱状图数据值的对齐方式 默认中间对齐 + /// + [JsonConverter(typeof(ChartEnumDescriptionConverter))] + public ChartDataLabelPosition Align { get; set; } = ChartDataLabelPosition.Center; + /// + /// 获得/设置 柱状图数据值的位置 默认显示在顶部 + /// + [JsonConverter(typeof(ChartEnumDescriptionConverter))] + public ChartDataLabelPosition Anchor { get; set; } = ChartDataLabelPosition.End; + /// + /// 获得/设置 柱状图数据值的颜色 + /// + public string ChartDataLabelColor { get; set; } = "rgb(75, 192, 192, 0.9)"; } diff --git a/src/Extensions/Components/BootstrapBlazor.Chart/wwwroot/js/chartjs-plugin-datalabels.js b/src/Extensions/Components/BootstrapBlazor.Chart/wwwroot/js/chartjs-plugin-datalabels.js new file mode 100644 index 000000000..77a0d51d0 --- /dev/null +++ b/src/Extensions/Components/BootstrapBlazor.Chart/wwwroot/js/chartjs-plugin-datalabels.js @@ -0,0 +1,7 @@ +/*! + * chartjs-plugin-datalabels v2.2.0 + * https://chartjs-plugin-datalabels.netlify.app + * (c) 2017-2022 chartjs-plugin-datalabels contributors + * Released under the MIT license + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js/helpers"),require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js/helpers","chart.js"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).ChartDataLabels=e(t.Chart.helpers,t.Chart)}(this,(function(t,e){"use strict";var r=function(){if("undefined"!=typeof window){if(window.devicePixelRatio)return window.devicePixelRatio;var t=window.screen;if(t)return(t.deviceXDPI||1)/(t.logicalXDPI||1)}return 1}(),a=function(e){var r,a=[];for(e=[].concat(e);e.length;)"string"==typeof(r=e.pop())?a.unshift.apply(a,r.split("\n")):Array.isArray(r)?e.push.apply(e,r):t.isNullOrUndef(e)||a.unshift(""+r);return a},o=function(t,e,r){var a,o=[].concat(e),n=o.length,i=t.font,l=0;for(t.font=r.string,a=0;ar.right&&(a|=2),er.bottom&&(a|=4),a}function u(t,e){var r,a,o=e.anchor,n=t;return e.clamp&&(n=function(t,e){for(var r,a,o,n=t.x0,i=t.y0,l=t.x1,u=t.y1,d=s(n,i,e),c=s(l,u,e);d|c&&!(d&c);)8&(r=d||c)?(a=n+(l-n)*(e.top-i)/(u-i),o=e.top):4&r?(a=n+(l-n)*(e.bottom-i)/(u-i),o=e.bottom):2&r?(o=i+(u-i)*(e.right-n)/(l-n),a=e.right):1&r&&(o=i+(u-i)*(e.left-n)/(l-n),a=e.left),r===d?d=s(n=a,i=o,e):c=s(l=a,u=o,e);return{x0:n,x1:l,y0:i,y1:u}}(n,e.area)),"start"===o?(r=n.x0,a=n.y0):"end"===o?(r=n.x1,a=n.y1):(r=(n.x0+n.x1)/2,a=(n.y0+n.y1)/2),function(t,e,r,a,o){switch(o){case"center":r=a=0;break;case"bottom":r=0,a=1;break;case"right":r=1,a=0;break;case"left":r=-1,a=0;break;case"top":r=0,a=-1;break;case"start":r=-r,a=-a;break;case"end":break;default:o*=Math.PI/180,r=Math.cos(o),a=Math.sin(o)}return{x:t,y:e,vx:r,vy:a}}(r,a,t.vx,t.vy,e.align)}var d=function(t,e){var r=(t.startAngle+t.endAngle)/2,a=Math.cos(r),o=Math.sin(r),n=t.innerRadius,i=t.outerRadius;return u({x0:t.x+a*n,y0:t.y+o*n,x1:t.x+a*i,y1:t.y+o*i,vx:a,vy:o},e)},c=function(t,e){var r=l(t,e.origin),a=r.x*t.options.radius,o=r.y*t.options.radius;return u({x0:t.x-a,y0:t.y-o,x1:t.x+a,y1:t.y+o,vx:r.x,vy:r.y},e)},h=function(t,e){var r=l(t,e.origin),a=t.x,o=t.y,n=0,i=0;return t.horizontal?(a=Math.min(t.x,t.base),n=Math.abs(t.base-t.x)):(o=Math.min(t.y,t.base),i=Math.abs(t.base-t.y)),u({x0:a,y0:o+i,x1:a+n,y1:o,vx:r.x,vy:r.y},e)},f=function(t,e){var r=l(t,e.origin);return u({x0:t.x,y0:t.y,x1:t.x+(t.width||0),y1:t.y+(t.height||0),vx:r.x,vy:r.y},e)},x=function(t){return Math.round(t*r)/r};function y(t,e){var r=e.chart.getDatasetMeta(e.datasetIndex).vScale;if(!r)return null;if(void 0!==r.xCenter&&void 0!==r.yCenter)return{x:r.xCenter,y:r.yCenter};var a=r.getBasePixel();return t.horizontal?{x:a,y:null}:{x:null,y:a}}function v(t,e,r){var a=r.backgroundColor,o=r.borderColor,n=r.borderWidth;(a||o&&n)&&(t.beginPath(),function(t,e,r,a,o,n){var i=Math.PI/2;if(n){var l=Math.min(n,o/2,a/2),s=e+l,u=r+l,d=e+a-l,c=r+o-l;t.moveTo(e,u),sr.x+r.w+2||t.y>r.y+r.h+2)},intersects:function(t){var e,r,a,o=this._points(),n=t._points(),i=[M(o[0],o[1]),M(o[0],o[3])];for(this._rotation!==t._rotation&&i.push(M(n[0],n[1]),M(n[0],n[3])),e=0;et.getProps([e],!0)[e]}),n=a.geometry(),i=$(l,a.model(),n),o._box.update(i,n,a.rotation()));(function(t,e){var r,a,o,n;for(r=t.length-1;r>=0;--r)for(o=t[r].$layout,a=r-1;a>=0&&o._visible;--a)(n=t[a].$layout)._visible&&o._box.intersects(n._box)&&e(o,n)})(t,(function(t,e){var r=t._hidable,a=e._hidable;r&&a||a?e._visible=!1:r&&(t._visible=!1)}))}(t)},lookup:function(t,e){var r,a;for(r=t.length-1;r>=0;--r)if((a=t[r].$layout)&&a._visible&&a._box.contains(e))return t[r];return null},draw:function(t,e){var r,a,o,n,i,l;for(r=0,a=e.length;r