diff --git a/pages/statistics/statistics.go b/pages/statistics/statistics.go index 8cc06f90..6d916c2c 100644 --- a/pages/statistics/statistics.go +++ b/pages/statistics/statistics.go @@ -18,69 +18,21 @@ func Get(ctx *aero.Context) string { return ctx.Error(http.StatusInternalServerError, "Couldn't retrieve analytics", err) } - screenSizes := map[string]int{} + screenSize := map[string]float64{} + platform := map[string]float64{} + pixelRatio := map[string]float64{} for _, info := range analytics { + platform[info.System.Platform]++ + pixelRatio[fmt.Sprintf("%.1f", info.Screen.PixelRatio)]++ + size := arn.ToString(info.Screen.Width) + " x " + arn.ToString(info.Screen.Height) - screenSizes[size]++ + screenSize[size]++ } - screenSizesSorted := []*utils.AnalyticsItem{} - - for size, count := range screenSizes { - item := &utils.AnalyticsItem{ - Key: size, - Value: count, - } - - if len(screenSizesSorted) == 0 { - screenSizesSorted = append(screenSizesSorted, item) - continue - } - - found := false - - for i := 0; i < len(screenSizesSorted); i++ { - if count >= screenSizesSorted[i].Value { - // Append empty element - screenSizesSorted = append(screenSizesSorted, nil) - - // Move all elements after index "i" 1 position up - copy(screenSizesSorted[i+1:], screenSizesSorted[i:]) - - // Set value for index "i" - screenSizesSorted[i] = item - - // Set flag - found = true - - // Leave loop - break - } - } - - if !found { - screenSizesSorted = append(screenSizesSorted, item) - } - } - - slices := []*utils.PieChartSlice{} - current := 0.0 - hueOffset := 0.0 - hueScaling := 60.0 - - for _, item := range screenSizesSorted { - percentage := float64(item.Value) / float64(len(analytics)) - - slices = append(slices, &utils.PieChartSlice{ - From: current, - To: current + percentage, - Title: fmt.Sprintf("%s (%d%%)", item.Key, int(percentage*100+0.5)), - Color: fmt.Sprintf("hsl(%.1f, 75%%, 50%%)", current*hueScaling+hueOffset), - }) - - current += percentage - } - - return ctx.HTML(components.Statistics(slices)) + return ctx.HTML(components.Statistics( + utils.NewPieChart("Screen sizes", screenSize), + utils.NewPieChart("Platforms", platform), + utils.NewPieChart("Pixel ratios", pixelRatio), + )) } diff --git a/pages/statistics/statistics.pixy b/pages/statistics/statistics.pixy index 1f07df54..d342ebe9 100644 --- a/pages/statistics/statistics.pixy +++ b/pages/statistics/statistics.pixy @@ -1,13 +1,14 @@ -component Statistics(screenSizes []*utils.PieChartSlice) +component Statistics(pieCharts ...*utils.PieChart) h1 Statistics - .statistics - h3 Screen size - PieChart(screenSizes) - //- canvas#screen-sizes.graph(data-values=utils.ToJSON(screenSizes)) + .widgets.statistics + each pie in pieCharts + .widget + h3.widget-title= pie.Title + PieChart(pie.Slices) component PieChart(slices []*utils.PieChartSlice) - svg.graph(viewBox="-1.05 -1.05 2.1 2.1") + svg.pie-chart(viewBox="-1.1 -1.1 2.2 2.2") each slice in slices g title= slice.Title diff --git a/pages/statistics/statistics.scarlet b/pages/statistics/statistics.scarlet index 4061a482..2f7878ae 100644 --- a/pages/statistics/statistics.scarlet +++ b/pages/statistics/statistics.scarlet @@ -1,11 +1,8 @@ .statistics - vertical - align-items center + // -.graph +.pie-chart transform rotate(-90deg) - width 250px - height 250px .slice color black diff --git a/utils/AnalyticsItem.go b/utils/AnalyticsItem.go index e7efafff..82b3288f 100644 --- a/utils/AnalyticsItem.go +++ b/utils/AnalyticsItem.go @@ -3,5 +3,5 @@ package utils // AnalyticsItem ... type AnalyticsItem struct { Key string - Value int + Value float64 } diff --git a/utils/PieChart.go b/utils/PieChart.go new file mode 100644 index 00000000..28cab8fe --- /dev/null +++ b/utils/PieChart.go @@ -0,0 +1,118 @@ +package utils + +import ( + "fmt" + "math" +) + +// PieChart ... +type PieChart struct { + Title string + Slices []*PieChartSlice +} + +// PieChartSlice ... +type PieChartSlice struct { + From float64 + To float64 + Title string + Color string +} + +// coords returns the coordinates for the given percentage. +func coords(percent float64) (float64, float64) { + x := math.Cos(2 * math.Pi * percent) + y := math.Sin(2 * math.Pi * percent) + return x, y +} + +// SVGSlicePath creates a path string for a slice in a pie chart. +func SVGSlicePath(from float64, to float64) string { + x1, y1 := coords(from) + x2, y2 := coords(to) + + largeArc := "0" + + if to-from > 0.5 { + largeArc = "1" + } + + return fmt.Sprintf("M %.3f %.3f A 1 1 0 %s 1 %.3f %.3f L 0 0", x1, y1, largeArc, x2, y2) +} + +// NewPieChart ... +func NewPieChart(title string, data map[string]float64) *PieChart { + return &PieChart{ + Title: title, + Slices: ToPieChartSlices(data), + } +} + +// ToPieChartSlices ... +func ToPieChartSlices(data map[string]float64) []*PieChartSlice { + if len(data) == 0 { + return nil + } + + dataSorted := []*AnalyticsItem{} + sum := 0.0 + + for key, value := range data { + sum += value + + item := &AnalyticsItem{ + Key: key, + Value: value, + } + + if len(dataSorted) == 0 { + dataSorted = append(dataSorted, item) + continue + } + + found := false + + for i := 0; i < len(dataSorted); i++ { + if value >= dataSorted[i].Value { + // Append empty element + dataSorted = append(dataSorted, nil) + + // Move all elements after index "i" 1 position up + copy(dataSorted[i+1:], dataSorted[i:]) + + // Set value for index "i" + dataSorted[i] = item + + // Set flag + found = true + + // Leave loop + break + } + } + + if !found { + dataSorted = append(dataSorted, item) + } + } + + slices := []*PieChartSlice{} + current := 0.0 + hueOffset := 0.0 + hueScaling := 60.0 + + for _, item := range dataSorted { + percentage := float64(item.Value) / sum + + slices = append(slices, &PieChartSlice{ + From: current, + To: current + percentage, + Title: fmt.Sprintf("%s (%d%%)", item.Key, int(percentage*100+0.5)), + Color: fmt.Sprintf("hsl(%.2f, 75%%, 50%%)", current*hueScaling+hueOffset), + }) + + current += percentage + } + + return slices +} diff --git a/utils/SVGPieChartPath.go b/utils/SVGPieChartPath.go deleted file mode 100644 index b82d9729..00000000 --- a/utils/SVGPieChartPath.go +++ /dev/null @@ -1,35 +0,0 @@ -package utils - -import ( - "fmt" - "math" -) - -// PieChartSlice ... -type PieChartSlice struct { - From float64 - To float64 - Title string - Color string -} - -// coords returns the coordinates for the given percentage. -func coords(percent float64) (float64, float64) { - x := math.Cos(2 * math.Pi * percent) - y := math.Sin(2 * math.Pi * percent) - return x, y -} - -// SVGSlicePath creates a path string for a slice in a pie chart. -func SVGSlicePath(from float64, to float64) string { - x1, y1 := coords(from) - x2, y2 := coords(to) - - largeArc := "0" - - if to-from > 0.5 { - largeArc = "1" - } - - return fmt.Sprintf("M %.3f %.3f A 1 1 0 %s 1 %.3f %.3f L 0 0", x1, y1, largeArc, x2, y2) -}