. */ declare(strict_types=1); namespace Fisharebest\Webtrees\Statistics\Google; use Fisharebest\Webtrees\Database; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Module\ModuleThemeInterface; use Fisharebest\Webtrees\Statistics\Helper\Country; use Fisharebest\Webtrees\Statistics\AbstractGoogle; use Fisharebest\Webtrees\Statistics\Repository\PlaceRepository; use Fisharebest\Webtrees\Statistics\Repository\IndividualRepository; use Fisharebest\Webtrees\Tree; /** * Create a chart showing where events occurred. */ class ChartDistribution extends AbstractGoogle { /** * @var Tree */ private $tree; /** * @var Country */ private $countryHelper; /** * @var IndividualRepository */ private $individualRepository; /** * @var PlaceRepository */ private $placeRepository; /** * Constructor. * * @param Tree $tree */ public function __construct(Tree $tree) { $this->tree = $tree; $this->countryHelper = new Country(); $this->individualRepository = new IndividualRepository($tree); $this->placeRepository = new PlaceRepository($tree); } /** * Create a chart showing where events occurred. * * @param int $tot_pl The total number of places * @param string $chart_shows * @param string $chart_type * @param string $surname * * @return string */ public function chartDistribution( int $tot_pl, string $chart_shows = 'world', string $chart_type = '', string $surname = '' ): string { $chart_color1 = app()->make(ModuleThemeInterface::class)->parameter('distribution-chart-no-values'); $chart_color2 = app()->make(ModuleThemeInterface::class)->parameter('distribution-chart-high-values'); $chart_color3 = app()->make(ModuleThemeInterface::class)->parameter('distribution-chart-low-values'); $map_x = app()->make(ModuleThemeInterface::class)->parameter('distribution-chart-x'); $map_y = app()->make(ModuleThemeInterface::class)->parameter('distribution-chart-y'); if ($tot_pl === 0) { return ''; } $countries = $this->countryHelper->getAllCountries(); // Get the country names for each language $country_to_iso3166 = []; foreach (I18N::activeLocales() as $locale) { I18N::init($locale->languageTag()); foreach ($this->countryHelper->iso3166() as $three => $two) { $country_to_iso3166[$three] = $two; $country_to_iso3166[$countries[$three]] = $two; } } I18N::init(WT_LOCALE); switch ($chart_type) { case 'surname_distribution_chart': if ($surname === '') { $surname = $this->individualRepository->getCommonSurname(); } $chart_title = I18N::translate('Surname distribution chart') . ': ' . $surname; // Count how many people are events in each country $surn_countries = []; $rows = Database::prepare( 'SELECT i_gedcom' . ' FROM `##individuals`' . ' JOIN `##name` ON n_id = i_id AND n_file = i_file' . ' WHERE n_file = :tree_id' . ' AND n_surn COLLATE :collate = :surname' )->execute([ 'tree_id' => $this->tree->id(), 'collate' => I18N::collation(), 'surname' => $surname, ])->fetchAll(); foreach ($rows as $row) { if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $row->i_gedcom, $matches)) { // webtrees uses 3 letter country codes and localised country names, // but google uses 2 letter codes. foreach ($matches[1] as $country) { if (\array_key_exists($country, $country_to_iso3166)) { if (\array_key_exists($country_to_iso3166[$country], $surn_countries)) { $surn_countries[$country_to_iso3166[$country]]++; } else { $surn_countries[$country_to_iso3166[$country]] = 1; } } } } } break; case 'birth_distribution_chart': $chart_title = I18N::translate('Birth by country'); // Count how many people were born in each country $surn_countries = []; $b_countries = $this->placeRepository->statsPlaces('INDI', 'BIRT', 0, true); foreach ($b_countries as $place => $count) { $country = $place; if (\array_key_exists($country, $country_to_iso3166)) { if (!isset($surn_countries[$country_to_iso3166[$country]])) { $surn_countries[$country_to_iso3166[$country]] = $count; } else { $surn_countries[$country_to_iso3166[$country]] += $count; } } } break; case 'death_distribution_chart': $chart_title = I18N::translate('Death by country'); // Count how many people were death in each country $surn_countries = []; $d_countries = $this->placeRepository->statsPlaces('INDI', 'DEAT', 0, true); foreach ($d_countries as $place => $count) { $country = $place; if (\array_key_exists($country, $country_to_iso3166)) { if (!isset($surn_countries[$country_to_iso3166[$country]])) { $surn_countries[$country_to_iso3166[$country]] = $count; } else { $surn_countries[$country_to_iso3166[$country]] += $count; } } } break; case 'marriage_distribution_chart': $chart_title = I18N::translate('Marriage by country'); // Count how many families got marriage in each country $surn_countries = []; $m_countries = $this->placeRepository->statsPlaces('FAM'); // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes. foreach ($m_countries as $place) { $country = $place->country; if (\array_key_exists($country, $country_to_iso3166)) { if (!isset($surn_countries[$country_to_iso3166[$country]])) { $surn_countries[$country_to_iso3166[$country]] = $place->tot; } else { $surn_countries[$country_to_iso3166[$country]] += $place->tot; } } } break; case 'indi_distribution_chart': default: $chart_title = I18N::translate('Individual distribution chart'); // Count how many people have events in each country $surn_countries = []; $a_countries = $this->placeRepository->statsPlaces('INDI'); // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes. foreach ($a_countries as $place) { $country = $place->country; if (\array_key_exists($country, $country_to_iso3166)) { if (!isset($surn_countries[$country_to_iso3166[$country]])) { $surn_countries[$country_to_iso3166[$country]] = $place->tot; } else { $surn_countries[$country_to_iso3166[$country]] += $place->tot; } } } break; } $chart_url = 'https://chart.googleapis.com/chart?cht=t&chtm=' . $chart_shows; $chart_url .= '&chco=' . $chart_color1 . ',' . $chart_color3 . ',' . $chart_color2; // country colours $chart_url .= '&chf=bg,s,ECF5FF'; // sea colour $chart_url .= '&chs=' . $map_x . 'x' . $map_y; $chart_url .= '&chld=' . implode('', array_keys($surn_countries)) . '&chd=s:'; foreach ($surn_countries as $count) { $chart_url .= substr(self::GOOGLE_CHART_ENCODING, (int) ($count / max($surn_countries) * 61), 1); } return view( 'statistics/other/chart-distribution', [ 'chart_title' => $chart_title, 'chart_url' => $chart_url, 'chart_color1' => $chart_color1, 'chart_color2' => $chart_color2, 'chart_color3' => $chart_color3, ] ); } }