From 54a1e935aca834f2521a1694052e1c898a6c7916 Mon Sep 17 00:00:00 2001 From: Matt Marcha Date: Fri, 19 Feb 2021 19:14:50 +0100 Subject: [PATCH] Commit initial --- Views/FiltersView.php | 111 +++++++++++++++++++++ Views/inc/filters.css | 94 ++++++++++++++++++ Views/inc/filters.js | 225 ++++++++++++++++++++++++++++++++++++++++++ cent-filtres.php | 52 ++++++++++ index.php | 2 + 5 files changed, 484 insertions(+) create mode 100644 Views/FiltersView.php create mode 100644 Views/inc/filters.css create mode 100644 Views/inc/filters.js create mode 100644 cent-filtres.php create mode 100644 index.php diff --git a/Views/FiltersView.php b/Views/FiltersView.php new file mode 100644 index 0000000..749f184 --- /dev/null +++ b/Views/FiltersView.php @@ -0,0 +1,111 @@ +publish; + + // Ensuite, pour chaque catégorie donnée, on va : + // récupérer le nombre de posts de cette cat + // récupérer la couleur associée + // calculer le pourcentage sur le total de mesures + // créer un bloc html avec la data correspondante + + $stats = ["validated", "partially-validated", "discussed", "danger", "rejected", "undiscussed"]; + $obj_total = 0; + + + $html = ""; + + // C'parti pour le cacamembert + + $pie_chart = '
'; + $labels = "
"; + + foreach ($stats as $stat) { + + // TODO : Sortir la requête du foreach et monter un modèle pour les taxonomies (pour embarquer la couleur) + $stat = get_term_by('slug', $stat, 'post-status'); + $color = get_field('couleur', "category_" . $stat->term_id); + $percent = $stat->count * 100 / $total; + $huge = $percent > 50 ? 1 : 0; + + static $offset = 0; + + $pie_chart .= "
+

$stat->count

+
"; + + $offset += $percent; + + $labels .= "
"; + $labels .= "
"; + $labels .= "

+ $stat->name ( $stat->count )

"; + $labels .= "
"; + + if (in_array($stat->slug, ['validated', 'partially-validated'])) { + $obj_total += $stat->count; + } + } + $pie_chart .= '
'; + $labels .= '
'; + + //ok, on monte les filtres par catégorie maintenant + $cats_title = "

Thématique

"; + $cats = "
+
"; + + return '
' . $cats_title . $cats . $pie_chart . $labels . '
' ; + + } + +} \ No newline at end of file diff --git a/Views/inc/filters.css b/Views/inc/filters.css new file mode 100644 index 0000000..5c9094b --- /dev/null +++ b/Views/inc/filters.css @@ -0,0 +1,94 @@ +/** +** Filters graph & selection +**/ + +/* Thematiques */ + +.filters-cats-label { + font-weight: 500; + margin-bottom: 0; + font-size: .8em; +} + +.filters-categories select { + font-size: .6em; + margin-bottom: 1.5em; +} + + + + + +/* Pie chart */ + +.pie { + border-radius: 100%; + height: calc(var(--size, 250) * 1px); + overflow: hidden; + position: relative; + width: calc(var(--size, 250) * 1px); +} +.pie__segment { + --a: calc(var(--over50, 0) * -100%); + --b: calc((1 + var(--over50, 0)) * 100%); + --degrees: calc((var(--offset, 0) / 100) * 360); + -webkit-clip-path: polygon(var(--a) var(--a), var(--b) var(--a), var(--b) var(--b), var(--a) var(--b)); + clip-path: polygon(var(--a) var(--a), var(--b) var(--a), var(--b) var(--b), var(--a) var(--b)); + height: 100%; + position: absolute; + transform: translate(0, -50%) rotate(90deg) rotate(calc(var(--degrees) * 1deg)); + transform-origin: 50% 100%; + width: 100%; + z-index: calc(1 + var(--over50)); +} +.pie__segment:after, +.pie__segment:before { + background: var(--bg, #e74c3c); + content: ''; + height: 100%; + position: absolute; + width: 100%; +} +.pie__segment:before { + --degrees: calc((var(--value, 45) / 100) * 360); + transform: translate(0, 100%) rotate(calc(var(--degrees) * 1deg)); + transform-origin: 50% 0%; +} +.pie__segment:after { + opacity: var(--over50, 0); +} + +/* au cas où on en revienne aux labels dans les slices :*/ + +.pie__segment .label { + position: absolute; + bottom: -30px; + color: #fff; + z-index: 99; + transform: translate(0, -50%) rotate(-90deg) rotate(calc(var(--degrees) * -1deg)); + left: 8px; + text-align: center; + font-size: .8em; + font-weight: 900; +} + +/*** Legends ***/ + +.home-legend-items { + margin-top: 1em; +} + +.home-legend-item { + position: relative; + padding-left: 30px; +} + +.home-legend-item .legend-color { + position: absolute; + left: 0; + top: 0; + bottom: 0; + margin: auto; + width: 20px; + height: 20px; +} \ No newline at end of file diff --git a/Views/inc/filters.js b/Views/inc/filters.js new file mode 100644 index 0000000..ac37809 --- /dev/null +++ b/Views/inc/filters.js @@ -0,0 +1,225 @@ +jQuery( document ).ready(function($) { + + /** Filtrage des propositions **/ + + // On crée les var : boite à filtre, et un tableua pour stocker lesdits filtres + var filters_div = $('#filters-container'); + var current_filters = new Object(); + + + /** + * filter_actions + * ajoute ou supprime les filtres au tableau et la classe selected aux filtres, en fonction de l'élément (et de si c'est select ou statut) + * + */ + + function filters_action(elem, currentFilters) { + //Si c'est le select qui a changé, on supprime les filtres par catégorie existants + if (elem.nodeName === 'OPTION') { + $('#filters_cat_select option').removeClass('active'); + currentFilters = new Object(); + $(filters_div).children().remove(); + } + + // Si la valeur est nulle on arrête tout + if (!elem.hasAttribute('filter-id')) { + $(filters_div).trigger("filters-changed", [currentFilters]); + changePie(elem, currentFilters); + return currentFilters; + } + + //Sinon s'occupe du tableau et de la classe + var filter_id = elem.getAttribute('filter-id'); + var filter_label = elem.getAttribute('filter-label'); + + // Si c'est un filtre de thématique qui a été supprimé, on réinitialise le select et les filtres + if ($(elem).hasClass('measure-filter') && !isNaN(parseInt(filter_id))) { + $('#filters_cat_select').prop('selectedIndex', 0); + // TODO : supprimer les autres filtres (status) si on supprime une catégorie + } + + // Il y est déjà : on supprime le filtre + if (filter_id in currentFilters) { + //suppression du tableau + delete currentFilters[filter_id]; + //suppression de la barre des filtres + $(filters_div).children('[filter-id="' + filter_id + '"]').remove(); + } + // il y est pas : on l'ajoute + else { + //ajout dans le tableau + currentFilters[filter_id] = filter_label; + // Ajout dans la barre + var htmlFilter = "

" + filter_label + "

+
"; + filters_div.append(htmlFilter); + } + + // on switche la classe + $('#measures-filters-container [filter-id="' + filter_id + '"]').toggleClass('active'); + + console.log($(elem).attr('filter-id')); + if(!isNaN(filter_id)){ + changePie(elem, currentFilters); + } + + // Enfin on déclenche l'event filters-change + $(filters_div).trigger("filters-changed", [currentFilters]); + + // On renvoie la liste des filtres mise à jour; + return currentFilters; + } + + // Au clic sur un élément (ou change du select), on appelle la fonction avec l'élément (id&label) en argument + + //Les statuts + $(".home-legend-item .status-title, .pie .pie__segment").click(function(){ + current_filters = filters_action(this, current_filters); + }); + // les catégories + $("#filters_cat_select").change(function(){ + var elem = $(this).children(':selected').get(0); + current_filters = filters_action(elem, current_filters); + + // on change la pie + changePie(elem, current_filters); + }); + // La barre de filtres + + $("body").on("click", "div.filters-container .filter-close", function (){ + elem = $(this).closest('.measure-filter').get(0); + current_filters = filters_action(elem, current_filters); + + }); + + /** + * filters-changed + * Evènement gérant l'affichage/masquage des mesures selon les filtres + */ + $(filters_div).on("filters-changed", function(event, currentFilters) { + + var measures = $("article.measure-wrapper"); + + // si aucun filtre on affiche tout + if ($.isEmptyObject(currentFilters)) { + measures.show(); + return; + } + + // On récupère les filtres triés + var filters = filtersSeparation(currentFilters); + + // On filtre pour afficher/masquer ce qui correspond aux bonnes classe + measures.filter(filters[0] + filters[1].join(', ' + filters[0] )).show(); + measures.not(filters[0] + filters[1].join(', ' + filters[0] )).hide(); + + }); + /** + * filtersSeparation + * Spare les filtres en catégories et statuts + */ + function filtersSeparation(currentFilters){ + + // On parcourt le tableau actuel des filtres, et on récupère les ID + var idsToShow = Object.keys(currentFilters); + // séparer catégories et statut : si une valeur nupérique est présente dans les filtres, on la récupère et l'extrait. + var cat = ''; + var status = []; + + // On parcourt la liste des id et on sépare cat et stat + for (var i = 0; i < idsToShow.length; i++) { + + // Si c'est numérique c'est une catégorie (AND) + if (!isNaN(parseInt(idsToShow[i]))) { + cat = '.' + idsToShow[i]; + } + //sinon c'est un statut (OR) + else { + status.push('.' + idsToShow[i]); + } + } + + return [cat, status]; + } + + + /** + * ChangePie + * Met à jour le pie chart à partir de l'option selectionnée + */ + + function changePie(elem, currentFilters) { + var container = $('div#measures-filters-container'); + var measures = $('div#measures-container'); + + + // On récupère les filtres triés + var filters = filtersSeparation(currentFilters); + + + // C'est parti pour les calculs ! + + // Pour chaque statut, on calcule en fonction des filtres + var statusNames = ["validated", 'partially-validated', "discussed", "danger", "rejected", "undiscussed"]; + //total des mesures + var counts = {'total': measures.children('.measure-wrapper' + filters[0]).length}; + + var offset = 0; + for (var i = 0; i < statusNames.length; i++) { + // on compte + counts[statusNames[i]] = measures.children('.measure-wrapper' + filters[0] + '.' + statusNames[i]).length; + + var percent = counts[statusNames[i]] * 100 / counts['total']; + var huge = percent > 50 ? 1 : 0; + + // on change les custom val + + container.find('.pie .pie__segment.' + statusNames[i]).css('--value', percent); + container.find('.pie .pie__segment.' + statusNames[i]).css('--offset', offset); + container.find('.pie .pie__segment.' + statusNames[i]).css('--over50', huge); + container.find('.statusTotal.' + statusNames[i]).text(counts[statusNames[i]]); + + //mise à jour de l'offset + offset = offset + percent; + } + + } + + + + + /** + * Recherche de type texte + * + */ + + var css_selector = ".measure-wrapper, .measure-wrapper"; + + /* Par recherche texte */ + function clearSearchField() { + $(".search-container #measure-search").val(""); + } + + $(".search-container #measure-search").keyup(function() { + + // récupération du query actuel + var query = $.trim($(this).val()); + + if (query === "") { // si il est vide on affiche tout + // on affiche toutes les propositions, en tenant compte des filtres éventuels + $(css_selector).show(); + } + else { + // on va chercher les mentions de ce query dans les mesures et on cache celles qui ne l'ont pas + $(css_selector).show().not(':Contains(' + query + ')').hide(); + } + }); + + $(".search-container #measure-search-reset").click(function () { + clearSearchField(); + $(".search-container #measure-search").trigger("keyup"); + }); + + + + +}); \ No newline at end of file diff --git a/cent-filtres.php b/cent-filtres.php new file mode 100644 index 0000000..c4ef510 --- /dev/null +++ b/cent-filtres.php @@ -0,0 +1,52 @@ +