mirror of
https://github.com/Freika/dawarich.git
synced 2026-04-22 03:00:29 -04:00
Merge pull request #86 from Freika/countries-and-cities-revised
Countries and cities revised
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@ class MapController < ApplicationController
|
||||
def index
|
||||
@points = current_user.tracked_points.without_raw_data.where('timestamp >= ? AND timestamp <= ?', start_at, end_at).order(timestamp: :asc)
|
||||
|
||||
@countries_and_cities = CountriesAndCities.new(@points).call
|
||||
@countries_and_cities = Visits::Calculate.new(@points).uniq_visits
|
||||
@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] }
|
||||
|
||||
@@ -12,7 +12,7 @@ class ReverseGeocodingJob < ApplicationJob
|
||||
result = Geocoder.search([point.latitude, point.longitude])
|
||||
return if result.blank?
|
||||
|
||||
point.update(
|
||||
point.update!(
|
||||
city: result.first.city,
|
||||
country: result.first.country
|
||||
)
|
||||
|
||||
89
app/services/visits/calculate.rb
Normal file
89
app/services/visits/calculate.rb
Normal file
@@ -0,0 +1,89 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Visits::Calculate
|
||||
def initialize(points)
|
||||
@points = points
|
||||
end
|
||||
|
||||
def call
|
||||
normalize_result(city_visits)
|
||||
end
|
||||
|
||||
def uniq_visits
|
||||
# Only one visit per city per day
|
||||
call.flat_map do |country|
|
||||
{ country: country[:country], cities: country[:cities].uniq { [_1[:city], Time.at(_1[:timestamp]).to_date] } }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :points
|
||||
|
||||
def group_points
|
||||
points.sort_by(&:timestamp).reject { _1.city.nil? }.group_by(&:country)
|
||||
end
|
||||
|
||||
def city_visits
|
||||
group_points.transform_values do |grouped_points|
|
||||
grouped_points
|
||||
.group_by(&:city)
|
||||
.transform_values { |city_points| identify_consecutive_visits(city_points) }
|
||||
end
|
||||
end
|
||||
|
||||
def identify_consecutive_visits(city_points)
|
||||
visits = []
|
||||
current_visit = []
|
||||
|
||||
city_points.each_cons(2) do |point1, point2|
|
||||
time_diff = (point2.timestamp - point1.timestamp) / 60
|
||||
|
||||
if time_diff <= MIN_MINUTES_SPENT_IN_CITY
|
||||
current_visit << point1 unless current_visit.include?(point1)
|
||||
current_visit << point2
|
||||
else
|
||||
visits << create_visit(current_visit) if current_visit.size > 1
|
||||
current_visit = []
|
||||
end
|
||||
end
|
||||
|
||||
visits << create_visit(current_visit) if current_visit.size > 1
|
||||
visits
|
||||
end
|
||||
|
||||
def create_visit(points)
|
||||
{
|
||||
city: points.first.city,
|
||||
points:,
|
||||
stayed_for: calculate_stayed_time(points),
|
||||
last_timestamp: points.last.timestamp
|
||||
}
|
||||
end
|
||||
|
||||
def calculate_stayed_time(points)
|
||||
return 0 if points.empty?
|
||||
|
||||
min_time = points.first.timestamp
|
||||
max_time = points.last.timestamp
|
||||
((max_time - min_time) / 60).round
|
||||
end
|
||||
|
||||
def normalize_result(hash)
|
||||
hash.map do |country, cities|
|
||||
{
|
||||
country:,
|
||||
cities: cities.values.flatten
|
||||
.select { |visit| visit[:stayed_for] >= MIN_MINUTES_SPENT_IN_CITY }
|
||||
.map do |visit|
|
||||
{
|
||||
city: visit[:city],
|
||||
points: visit[:points].count,
|
||||
timestamp: visit[:last_timestamp],
|
||||
stayed_for: visit[:stayed_for]
|
||||
}
|
||||
end
|
||||
}
|
||||
end.reject { |entry| entry[:cities].empty? }
|
||||
end
|
||||
end
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
<% if REVERSE_GEOCODING_ENABLED && @countries_and_cities&.any? %>
|
||||
<hr class='my-5'>
|
||||
<h2 class='text-lg font-semibold'>Countries and cities</h2>
|
||||
<% @countries_and_cities.each do |country| %>
|
||||
<% next if country[:cities].empty? %>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user