mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
Add nice charts to the stat cards
This commit is contained in:
parent
23805a6ef4
commit
29ac8c1136
15 changed files with 86 additions and 20 deletions
1
Gemfile
1
Gemfile
|
|
@ -17,6 +17,7 @@ gem 'turbo-rails'
|
|||
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
|
||||
gem "importmap-rails"
|
||||
gem "mapkick-rb"
|
||||
gem "chartkick"
|
||||
gem 'geocoder'
|
||||
gem 'sidekiq'
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ GEM
|
|||
msgpack (~> 1.2)
|
||||
builder (3.2.4)
|
||||
byebug (11.1.3)
|
||||
chartkick (5.0.6)
|
||||
coderay (1.1.3)
|
||||
concurrent-ruby (1.2.3)
|
||||
connection_pool (2.4.1)
|
||||
|
|
@ -323,6 +324,7 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
bootsnap
|
||||
chartkick
|
||||
debug
|
||||
devise
|
||||
dotenv-rails
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class ImportsController < ApplicationController
|
|||
files.each do |file|
|
||||
import = current_user.imports.create(
|
||||
name: file.original_filename,
|
||||
source: params[:import][:source],
|
||||
source: params[:import][:source]
|
||||
)
|
||||
|
||||
import.file.attach(file)
|
||||
|
|
@ -27,7 +27,7 @@ class ImportsController < ApplicationController
|
|||
redirect_to imports_url, notice: "#{files.size} files are queued to be imported in background", status: :see_other
|
||||
rescue StandardError => e
|
||||
Import.where(user: current_user, name: files.map(&:original_filename)).destroy_all
|
||||
Rails.logger.debug e.message
|
||||
|
||||
flash.now[:error] = e.message
|
||||
|
||||
redirect_to new_import_path, notice: e.message, status: :unprocessable_entity
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@ class PointsController < ApplicationController
|
|||
|
||||
@countries_and_cities = CountriesAndCities.new(@points).call
|
||||
@coordinates =
|
||||
@points
|
||||
.pluck(:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id)
|
||||
.map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7] }
|
||||
@points.pluck(:latitude, :longitude, :battery, :altitude, :timestamp, :velocity, :id)
|
||||
.map { [_1.to_f, _2.to_f, _3.to_s, _4.to_s, _5.to_s, _6.to_s, _7] }
|
||||
@distance = distance
|
||||
@start_at = Time.at(start_at)
|
||||
@end_at = Time.at(end_at)
|
||||
@start_at = Time.zone.at(start_at)
|
||||
@end_at = Time.zone.at(end_at)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -23,7 +22,7 @@ class PointsController < ApplicationController
|
|||
end
|
||||
|
||||
def end_at
|
||||
return Date.today.end_of_day.to_i if params[:end_at].nil?
|
||||
return Time.zone.today.end_of_day.to_i if params[:end_at].nil?
|
||||
|
||||
params[:end_at].to_datetime.to_i
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,4 +22,8 @@ module ApplicationHelper
|
|||
|
||||
{ start_at: start_at, end_at: end_at }
|
||||
end
|
||||
|
||||
def header_colors
|
||||
%w[info success warning error accent secondary primary]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,3 +7,5 @@ import "@hotwired/turbo-rails"
|
|||
import "mapkick/bundle"
|
||||
import "leaflet"
|
||||
import "leaflet-providers"
|
||||
import "chartkick"
|
||||
import "Chart.bundle"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Stat < ApplicationRecord
|
||||
validates :year, :month, presence: true
|
||||
|
||||
belongs_to :user
|
||||
|
||||
def timespan
|
||||
DateTime.new(year, month).beginning_of_month..DateTime.new(year, month).end_of_month
|
||||
end
|
||||
|
||||
def distance_by_day
|
||||
timespan.to_a.map.with_index(1) do |day, index|
|
||||
beginning_of_day = day.beginning_of_day.to_i
|
||||
end_of_day = day.end_of_day.to_i
|
||||
|
||||
data = { day: index, distance: 0 }
|
||||
|
||||
# We have to filter by user as well
|
||||
points = Point.where(timestamp: beginning_of_day..end_of_day)
|
||||
|
||||
points.each_cons(2) do |point1, point2|
|
||||
distance = Geocoder::Calculations.distance_between(
|
||||
[point1.latitude, point1.longitude], [point2.latitude, point2.longitude]
|
||||
)
|
||||
|
||||
data[:distance] += distance
|
||||
end
|
||||
|
||||
[data[:day], data[:distance].round(2)]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,4 +29,8 @@ class User < ApplicationRecord
|
|||
def total_cities
|
||||
Stat.where(user: self).pluck(:toponyms).flatten.size
|
||||
end
|
||||
|
||||
def total_reverse_geocoded
|
||||
points.where.not(country: nil, city: nil).count
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,16 +16,13 @@ class CreateStats
|
|||
end_of_month_timestamp = DateTime.new(year, month).end_of_month.to_i
|
||||
|
||||
points = points(beginning_of_month_timestamp, end_of_month_timestamp)
|
||||
|
||||
next if points.empty?
|
||||
|
||||
Stat.create(
|
||||
year: year,
|
||||
month: month,
|
||||
distance: distance(points),
|
||||
toponyms: toponyms(points),
|
||||
user: user
|
||||
)
|
||||
stat = Stat.create(year:, month:, user:, distance: distance(points), toponyms: toponyms(points))
|
||||
|
||||
stat.update(daily_distance: stat.distance_by_day) if stat.persisted?
|
||||
|
||||
stat
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
</h2>
|
||||
<ul>
|
||||
<% country[:cities].each do |city| %>
|
||||
<li><%= city[:city] %> (<%= Time.at(city[:timestamp]).strftime("%d.%m.%Y") %>)</li>
|
||||
<li><%= city[:city] %> (<%= Time.zone.at(city[:timestamp]).strftime("%d.%m.%Y") %>)</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div id="<%= dom_id stat %>" class="card w-full bg-base-200 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<%= link_to points_url(month_timespan(stat)), class: 'underline hover:no-underline' do %>
|
||||
<%= link_to points_url(month_timespan(stat)), class: "underline hover:no-underline text-#{header_colors.sample}" do %>
|
||||
<%= "#{Date::MONTHNAMES[stat.month]} of #{stat.year}" %>
|
||||
<% end %>
|
||||
</h2>
|
||||
|
|
@ -10,6 +10,13 @@
|
|||
<div class="card-actions justify-end">
|
||||
<%= stat.toponyms.count %> countries, <%= stat.toponyms.sum { _1['cities'].count } %> cities
|
||||
</div>
|
||||
<%= column_chart(
|
||||
stat.daily_distance,
|
||||
height: '100px',
|
||||
suffix: ' km',
|
||||
xtitle: 'Days',
|
||||
ytitle: 'Distance'
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,24 @@
|
|||
<div class="stat-title">Total distance</div>
|
||||
</div>
|
||||
|
||||
<div class="stat text-center">
|
||||
<div class="stat-value text-success">
|
||||
<%= number_with_delimiter current_user.points.count %>
|
||||
</div>
|
||||
<div class="stat-title">Geopoints tracked</div>
|
||||
</div>
|
||||
|
||||
<% if REVERSE_GEOCODING_ENABLED %>
|
||||
<div class="stat text-center">
|
||||
<div class="stat-value text-secondary">
|
||||
<%= current_user.total_countries %>
|
||||
<%= current_user.total_reverse_geocoded %>
|
||||
</div>
|
||||
<div class="stat-title">Reverse geocoded points</div>
|
||||
</div>
|
||||
|
||||
<div class="stat text-center">
|
||||
<div class="stat-value text-warning">
|
||||
<%= number_with_delimiter current_user.total_countries %>
|
||||
</div>
|
||||
<div class="stat-title">Countries visited</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,3 +12,5 @@ pin_all_from "app/javascript/controllers", under: "controllers"
|
|||
pin "mapkick/bundle", to: "mapkick.bundle.js"
|
||||
pin "leaflet" # @1.9.4
|
||||
pin "leaflet-providers" # @2.0.0
|
||||
pin "chartkick", to: "chartkick.js"
|
||||
pin "Chart.bundle", to: "Chart.bundle.js"
|
||||
|
|
|
|||
5
db/migrate/20240324173315_add_daily_distance_to_stat.rb
Normal file
5
db/migrate/20240324173315_add_daily_distance_to_stat.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class AddDailyDistanceToStat < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :stats, :daily_distance, :jsonb, default: {}
|
||||
end
|
||||
end
|
||||
3
db/schema.rb
generated
3
db/schema.rb
generated
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_03_24_161800) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_03_24_173315) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
|
|
@ -101,6 +101,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_24_161800) do
|
|||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.bigint "user_id", null: false
|
||||
t.jsonb "daily_distance", default: {}
|
||||
t.index ["distance"], name: "index_stats_on_distance"
|
||||
t.index ["month"], name: "index_stats_on_month"
|
||||
t.index ["user_id"], name: "index_stats_on_user_id"
|
||||
|
|
|
|||
Loading…
Reference in a new issue