Commit 4fc99c56 authored by Benjam's avatar Benjam Committed by Lionel DURAND
Browse files

v1.6

parent 33dda212
{
"svg.preview.background": "transparent"
}
\ No newline at end of file
import { Afficheur } from '../../commun/controleurs/Afficheur';
import { Indicateur } from '../../commun/domaines/Indicateur';
import {
EnteteTitreEtNavigation, GroupeBoutons, injecterHtmlParIdElement, MenuGlissant, rendreInvisible, rendreVisible, rendreVisibleBody,
EnteteTitreEtNavigation,
GroupeBoutons,
injecterHtmlParIdElement,
MenuGlissant,
rendreInvisible,
rendreVisible,
rendreVisibleBody,
ZoneMessageErreur
} from '../../commun/vues';
import { PanneauGlissant } from '../../commun/vues/crater/PanneauGlissant';
......
import { Afficheur } from '../../commun/controleurs/Afficheur';
import { Indicateur } from '../../commun/domaines/Indicateur';
import {
chargerContoursTerritoires, chargerCoucheHotelsDepartements, chargerCoucheHotelsRegions, chargerIndicateurs
chargerContoursTerritoires,
chargerCoucheHotelsDepartements,
chargerCoucheHotelsRegions,
chargerIndicateurs
} from '../../commun/requetes-api/requetes-api-carte';
import { chargerHierarchieTerritoires } from '../../commun/requetes-api/requetes-api-territoires';
import { EchelleTerritoriale } from '../domaines/EchelleTerritoriale';
......
......@@ -61,3 +61,11 @@ export function calculerPourcentageString(numerateur: number | null, denominateu
return formaterNombreEnEntierString((numerateur / denominateur) * 100);
}
}
export function calculerRatioString(numerateur: number | null, denominateur: number | null): string {
if (numerateur === null || denominateur === null || denominateur === 0) {
return '-';
} else {
return formaterNombreEnNDecimalesString(numerateur / denominateur, 1);
}
}
import { LevierAction } from './LevierAction';
import { Maillon } from './Maillon';
describe('Test de la classe LevierAction', () => {
it('Vérification des fonctions', () => {
expect(LevierAction.tous[0].id).toEqual('9.1');
expect(LevierAction.selection(Maillon.proximiteCommerces)).toEqual(LevierAction.tous);
});
});
import { Maillon } from './Maillon';
export class LevierAction {
constructor(public readonly id: string, public readonly titre: string, public readonly maillons: Maillon[], public readonly detail: string) {}
public static tous = [
new LevierAction(
'9.1',
"Prendre en compte l'alimentation dans la planification urbaine",
[Maillon.proximiteCommerces],
`Les collectivités doivent favoriser l’activité économique du centre-ville ou centre-bourg, notamment en y
redéployant des services publics.
Il est impératif de mettre un terme au développement des grandes surfaces commerciales périphériques,
des zones d’activité économique à dominante commerciale, et des modèles récents comme les drives, qui
concurrencent directement l’activité économique du centre-ville et ne sont accessibles qu’en voiture.
Enfin, les politiques d’aménagement doivent stopper l’étalement urbain, qui augmente les distances parcourues
par les ménages pour leurs achats alimentaires en plus de contribuer à l’artificialisation des terres agricoles.
`
),
new LevierAction(
'9.3',
'Développer les circuits courts ',
[Maillon.proximiteCommerces],
`Les collectivités peuvent soutenir le développement de circuits courts pour diversifier les modes de distribution sur le territoire et renforcer l’offre locale. De nombreuses possibilités existent : marchés traditionnels, magasins de producteurs, commerces de proximité, AMAP, points relais…
`
),
new LevierAction(
'9.4',
'Favoriser l’installation d’espaces de vente de proximité ',
[Maillon.proximiteCommerces],
`Des points de vente accessibles sans voiture sont à développer par les collectivités. Ils peuvent prendre de multiples formes, toutes permettant de commercialiser les productions du territoire, avec un nombre variable d’intermédiaires. Les collectivités peuvent apporter leur soutien de différentes façons : montage de projet, mise à disposition de locaux, services d’expertise, étude de marché, mise en relation, promotion du lieu, etc.
Ces projets de commerces de proximité ont tout intérêt à être pensés conjointement avec les centres d’action sociale afin d’en faire des moyens de lutte efficaces contre la précarité alimentaire.
`
)
];
public static selection(maillon: Maillon): LevierAction[] {
return LevierAction.tous.filter((l) => l.maillons.includes(maillon));
}
}
export class Maillon {
constructor(public readonly nom: string) {}
public static proximiteCommerces = new Maillon('Proximité aux commerces');
}
......@@ -17,6 +17,10 @@ import {
} from '../../diagnostic/domaines';
import { ClassesAges } from '../../diagnostic/domaines/rapports/diagnostics/ClassesAges';
import { ClassesSuperficies } from '../../diagnostic/domaines/rapports/diagnostics/ClassesSuperficies';
import {
IndicateursProximiteCommerces,
ProximiteCommerces
} from '../../diagnostic/domaines/rapports/diagnostics/proximite-commerces/ProximiteCommerces';
export function chargerDiagnostics(apiBaseUrl: string, hierarchieTerritoires: HierarchieTerritoires): Promise<any[]> {
let promisesChargementDiagnostics: Promise<any>[] = hierarchieTerritoires.getListeTerritoires().map((t) => chargerDiagnostic(apiBaseUrl, t.id));
......@@ -121,6 +125,15 @@ export function traduireJsonEnDiagnostic(diagJson: any): Diagnostic {
diagJson.politiqueFonciere.messagePolitiqueArtificialisation,
diagJson.politiqueFonciere.partLogementsVacants2013,
diagJson.politiqueFonciere.partLogementsVacants2018
),
new ProximiteCommerces(
new IndicateursProximiteCommerces(
diagJson.proximiteCommerces.typesCommerces,
diagJson.proximiteCommerces.distancesPlusProcheCommerceMetres,
diagJson.proximiteCommerces.pourcentagesPopulationAccesAPied,
diagJson.proximiteCommerces.pourcentagesPopulationAccesAVelo,
diagJson.proximiteCommerces.pourcentagesPopulationDependanteVoiture
)
)
);
}
......
......@@ -30,6 +30,9 @@ interface SourcesDonnees {
hvn: SourceDonnee;
surfaces_agricoles_bio: SourceDonnee;
besoins_sau: SourceDonnee;
base_permanente_equipements: SourceDonnee;
commerces_osm: SourceDonnee;
carroyage_insee: SourceDonnee;
}
export const sourcesDonnees: SourcesDonnees = {
......@@ -322,5 +325,32 @@ export const sourcesDonnees: SourcesDonnees = {
perimetre_geographique: 'Communes, EPCIs, Départements, Régions, France métropolitaine au 1e janvier 2019',
source: `<a href="https://parcel-app.org/" target="_blank">PARCEL</a>`,
legende: 'PARCEL 2019'
},
base_permanente_equipements: {
nom: 'Base permanente des équipements',
definition: "La base permanente des équipements (BPE) est une source statistique qui fournit le niveau d'équipements et de services rendus à la population sur un territoire.",
annee: '2020',
perimetre_geographique: 'Géolocalisée (coordonnées XY)',
source: `<a href="https://www.insee.fr/fr/statistiques/3568638?sommaire=3568656" target="_blank">Base permanente des équipements (INSEE 2020)</a>`,
legende: 'INSEE 2020'
},
commerces_osm: {
nom: 'Base de données des commerces',
definition: "Base de données ouverte et collaborative OpenStreetMap des commerces",
annee: '2021',
perimetre_geographique: 'Géolocalisée (coordonnées XY)',
source: `<a href="https://babel.opendatasoft.com/explore/dataset/osm-shop-fr/information/?disjunctive.type&disjunctive.region&disjunctive.departement&disjunctive.commune" target="_blank">Base de données des commerces OSM 2021</a>`,
legende: 'OSM 2021'
},
carroyage_insee: {
nom: 'Données carroyées ',
definition: "Informations socio-économiques sur l'ensemble de la France discrétisée en carreaux de 200 mètres de côté.",
annee: '2015',
perimetre_geographique: 'Carroyage INSEE 200m',
source: `<a href="https://www.insee.fr/fr/statistiques/4176290?sommaire=4176305" target="_blank">Données carroyées INSEE 2015</a>`,
legende: 'Données carroyées INSEE 2015'
}
};
......@@ -163,7 +163,7 @@ a:hover {
--c-ligne-serie-2: var(--bleu);
--c-ligne-serie-3: var(--rouge);
--c-ligne-serie-4: var(--orange);
--c-ligne-serie-5: var(--gris5);
--c-ligne-serie-5: var(--noir);
--c-grille-charts: var(--gris3);
--c-bords-charts: var(--gris4);
......
......@@ -93,6 +93,7 @@
<div id="message-cle-pratiques-agricoles"></div>
<div id="message-cle-population-agricole"></div>
<div id="message-cle-politique-fonciere"></div>
<div id="message-cle-proximite-commerces"></div>
</div>
</div>
<p id="message-licence" class="afficher-dans-pdf masquer-par-defaut">
......@@ -407,12 +408,10 @@
<figure class="conteneur-chart">
<div id="pratiques-agricoles-evolution-qsa-nodu-chart"></div>
<div class="chart-legende">
<p>
Source : Les Greniers d'Abondance, à partir des données
<abbr title="Banque Nationale des Ventes de produits phytopharmaceutiques par les Distributeurs agréés">BNVD</abbr> (2021)
et des arrêtés ministériels fixant les <abbr title="Dose Unité">DU</abbr> (2017 et 2019)
</p>
<div class="chart-titre">
Source : Les Greniers d'Abondance, à partir des données
<abbr title="Banque Nationale des Ventes de produits phytopharmaceutiques par les Distributeurs agréés">BNVD</abbr> (2021)
et des arrêtés ministériels fixant les <abbr title="Dose Unité">DU</abbr> (2017 et 2019)
</div>
</figure>
......@@ -432,8 +431,8 @@
<figure class="conteneur-chart">
<div id="pratiques-agricoles-evolution-nodu-normalise-chart"></div>
<div class="chart-legende">
<p id="evolution-nodu-normalise-chart-legende"></p>
<div class="chart-titre">
<p id="evolution-nodu-normalise-chart-titre"></p>
</div>
</figure>
......@@ -999,6 +998,33 @@
</li>
</ul>
</section>
<section id="section-proximite-commerces" class="sectionChapitreDiagnostic">
<h1 class="soulignage">Proximité aux commerces</h1>
<p id="message-detaille-proximite-commerces"></p>
<c-lien-resilience id="lien-resilience-proximite-commerces"></c-lien-resilience>
<c-titre-indicateur id="titre-population-dependante-voiture"></c-titre-indicateur>
<p id="texte-population-dependante-voiture"></p>
<figure class="conteneur-chart">
<div id="chart-population-dependante-voiture"></div>
<c-titre-chart id="titre-chart-population-dependante-voiture"></c-titre-chart>
</figure>
<c-titre-indicateur id="titre-distances-aux-commerces"></c-titre-indicateur>
<p id="texte-distances-aux-commerces"></p>
<c-chart id="chart-distances-aux-commerces"></c-chart>
<c-titre-chart id="titre-chart-distances-aux-commerces"></c-titre-chart>
<h2>Comment ma collectivité peut-elle s&#39;améliorer ?</h2>
<p>En développant une <strong>offre alimentaire de proximité, accessible à pied, à vélo ou en transports en commun</strong>, au travers des leviers suivants :</p>
<c-leviers-actions id="leviers-actions-proximite-commerces"></c-leviers-actions>
<h2>Aller plus loin ?</h2>
<c-aller-plus-loin id="aller-plus-loin-proximite-commerces"></c-aller-plus-loin>
</section>
</main>
<footer id="diagnostic__pied-page"></footer>
......
......@@ -13,6 +13,7 @@ import {
} from '../domaines/rapports/diagnostics';
import { ClassesAges } from '../domaines/rapports/diagnostics/ClassesAges';
import { ClassesSuperficies } from '../domaines/rapports/diagnostics/ClassesSuperficies';
import { IndicateursProximiteCommerces, ProximiteCommerces } from '../domaines/rapports/diagnostics/proximite-commerces/ProximiteCommerces';
function creerHierarchieTerritoires(territoire: any) {
let territoirePrincipal = new HierarchieTerritoires(
......@@ -116,6 +117,7 @@ export function creerDiagnosticVide(territoire: Territoire) {
new ClassesSuperficies(0, 0, 0, 0, 0),
new ClassesSuperficies(0, 0, 0, 0, 0)
),
new PolitiqueFonciere(new IndicateurSynthese(0, ''), 0, 0, '', 0, 0)
new PolitiqueFonciere(new IndicateurSynthese(0, ''), 0, 0, '', 0, 0),
new ProximiteCommerces(new IndicateursProximiteCommerces([], [], [], [], []))
);
}
import { customElement, state } from 'lit/decorators.js';
import { css, html, LitElement } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
@customElement('c-aller-plus-loin')
export class AllerPlusLoin extends LitElement {
static styles = css`
a {
color: var(--c-texte-liens);
}
a:hover {
color: var(--c-texte-surbrillance);
text-decoration: underline;
}
ul{
padding-left: 2rem;
}
`;
@state()
private items: string[] = [];
afficher(items: string[]) {
this.items = items;
}
render() {
return html`<ul>
${this.items.map((item) => html`<li>${unsafeHTML(item)}</li>`)}
<ul></ul>
</ul>`;
}
}
......@@ -48,7 +48,7 @@ export class LegendeChart extends LitElement {
return html` <ul>
${this.itemsLegende.map(
(item) =>
html` <li>
html`<li>
<span
class="dot"
style="border: solid 1px ${item.couleur};background-color: ${item.couleur};background-image: ${item.motif}"
......
import { customElement, state } from 'lit/decorators.js';
import { css, html, LitElement } from 'lit';
import { LevierAction } from '../../commun/domaines/LevierAction';
@customElement('c-leviers-actions')
export class LeviersActions extends LitElement {
static styles = css`
.h5:hover {
color: var(--c-texte-surbrillance);
}
summary {
padding-left: 1rem;
cursor: pointer;
}
`;
@state()
private items: LevierAction[] = [];
afficher(items: LevierAction[]) {
this.items = items;
}
render() {
return this.items.map(
(item) =>
html` <details>
<summary class="h5">${item.titre}</summary>
<p>${item.detail}</p>
</details>`
);
}
}
import { customElement, state } from 'lit/decorators.js';
import { css, html, LitElement } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
@customElement('c-lien-resilience')
export class LienResilience extends LitElement {
static styles = css`
div {
background-color: #2c5e9f2b;
border-radius: 1rem;
margin: auto;
padding: 0.3rem;
}
h1 {
font-size: var(--title4);
margin: 0;
padding: 0.1rem;
padding-bottom: 0.3rem;
}
p {
font-size: var(--smaller);
margin: 0;
padding: 0.2rem;
}
`
@state()
private texte: string = "";
afficher(texte: string) {
this.texte = texte;
}
render() {
return html` <div>
<h1>Quel lien avec la résilience ?</h1>
<p>${unsafeHTML(this.texte)}</p>
</div>`;
}
}
import { customElement, state } from 'lit/decorators.js';
import { css, html, LitElement } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
@customElement('c-titre-chart')
export class TitreChart extends LitElement {
static styles = css`
div {
margin-bottom: 3rem;
text-align: center;
font-size: var(--smaller2);
font-weight: bold;
color: var(--c-texte-legende);
}
a {
color: var(--c-texte-liens);
}
a:hover {
color: var(--c-texte-surbrillance);
}
`
@state()
private titre: string = "";
afficher(titre: string) {
this.titre = titre;
}
render() {
return html` <div>${unsafeHTML(this.titre)}</div>`;
}
}
import { customElement, state } from 'lit/decorators.js';
import { css, html, LitElement } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
@customElement('c-titre-indicateur')
export class TitreIndicateur extends LitElement {
static styles = css`
.titre {
display: flex;
align-items: center;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
h3 {
color: var(--c-texte-titre);
margin: 0;
}
button {
margin-left: 0.5rem;
cursor: pointer;
width: 2rem;
height: 2rem;
border-radius: 2rem;
border: none;
display: grid;
place-items: center;
}
button:hover {
background-color: var(--c-texte-surbrillance);
color: white;
}
.detail {
display: block;
position: absolute;
background-color: var(--bleu);
border-radius: 0.2rem;
margin: auto;
padding: 0.5rem;
width: calc(var(--largeur-maximum-contenu) - 250px);
z-index: 100;
}
.detail * {
color: white;
}
.visible {
display: block;
}
.invisible {
display: none;
}
`
@state()
private titre: string = "";
private description: string = "";
private calcul: string = "";
private lienMethodologie: string = "";
@state()
private classeVisibilite = 'invisible';
private rendreVisible() {
this.classeVisibilite = 'visible';
}
afficher(titre: string, description: string, calcul: string, lienMethodologie:string) {
this.titre = titre;
this.description = description;
this.calcul = calcul;
this.lienMethodologie = lienMethodologie;
}
firstUpdated() {
document.addEventListener('click', this.gererClickFermeture);
}
private gererClickFermeture = (event: Event) => {
if (!this.contains(event.target as Node | null)) {
this.classeVisibilite = 'invisible';
}
}
render() {
return html`
<div class="titre">
<h3>${this.titre}</h3>
<button @click="${this.rendreVisible}">?</button>
</div>
<div class="detail ${this.classeVisibilite}">
<div>${this.description}</div>
<div>${this.calcul}</div>
<a href="./methodologie.html#${this.lienMethodologie}">Voir méthodologie</a>.
</div>`;
}
}
......@@ -12,6 +12,7 @@ import { AfficheurDiagnosticProductionBesoins } from './AfficheurDiagnosticProdu
import { AfficheurDiagnosticPopulationAgricole } from './AfficheurDiagnosticPopulationAgricole';
import { AfficheurDiagnosticPratiquesAgricoles } from './AfficheurDiagnosticPratiquesAgricoles';
import { sourcesDonnees } from '../../commun/sources-donnees';
import { AfficheurDiagnosticProximiteCommerces } from './AfficheurDiagnosticProximiteCommerces';
export class AfficheurDiagnosticGlobal implements Afficheur<Rapport> {
private menuSectionsDiagnostic: MenuSectionsDiagnostic;
......@@ -22,6 +23,7 @@ export class AfficheurDiagnosticGlobal implements Afficheur<Rapport> {
private afficheurPratiquesAgricoles: AfficheurDiagnosticPratiquesAgricoles;
private afficheurPopulationAgricole: AfficheurDiagnosticPopulationAgricole;
private afficheurPolitiqueFonciere: AfficheurDiagnosticPolitiqueFonciere;
private afficheurProximitéCommerces: AfficheurDiagnosticProximiteCommerces;
constructor(private readonly controleurDiagnostic: ControleurDiagnostic) {
this.menuSectionsDiagnostic = new MenuSectionsDiagnostic('diagnostic__menu__sections');
......@@ -34,6 +36,7 @@ export class AfficheurDiagnosticGlobal implements Afficheur<Rapport> {
this.afficheurPratiquesAgricoles = new AfficheurDiagnosticPratiquesAgricoles();
this.afficheurPopulationAgricole = new AfficheurDiagnosticPopulationAgricole();
this.afficheurPolitiqueFonciere = new AfficheurDiagnosticPolitiqueFonciere();
this.afficheurProximitéCommerces = new AfficheurDiagnosticProximiteCommerces();
}
afficher(rapport: Rapport): void {
......@@ -53,6 +56,7 @@ export class AfficheurDiagnosticGlobal implements Afficheur<Rapport> {
this.afficheurPratiquesAgricoles.afficher(rapport);
this.afficheurPopulationAgricole.afficher(rapport);
this.afficheurPolitiqueFonciere.afficher(rapport);
this.afficheurProximitéCommerces.afficher(rapport);
configurerScrollVers();
rendreVisibleBody();
} else if (rapport.getEtat() == EtatRapport.ERREUR) {
......
......@@ -29,11 +29,8 @@ export class AfficheurDiagnosticPratiquesAgricoles implements Afficheur<Rapport>
couleurYaxisDroite: getVariableCss('--c-ligne-serie-2')
});
this.chartPratiquesAgricolesEvolutionNODUnormalise = new ChartLignes('pratiques-agricoles-evolution-nodu-normalise-chart', {
// TODO : voir si on utilise pas SerieMultiple.labels pour passer les années
xaxisCategories: [2017, 2018, 2019, 2020],
yaxisTitre: 'NODU normalisé [-]',
couleurs: [
getVariableCss('--c-ligne-serie-1'),
getVariableCss('--c-ligne-serie-2'),
getVariableCss('--c-ligne-serie-3'),
getVariableCss('--c-ligne-serie-4'),
......@@ -80,6 +77,7 @@ export class AfficheurDiagnosticPratiquesAgricoles implements Afficheur<Rapport>
);
this.chartPratiquesAgricolesEvolutionNODUnormalise.afficher(
rapport.getDiagnosticPays()!.pratiquesAgricoles.produitsPhytosanitaires.indicateursMoyennesTriennales.annees,
new SerieMultiple(
rapport.getListeDiagnostics().map((d) => {
return new Serie(d!.pratiquesAgricoles.produitsPhytosanitaires.indicateursMoyennesTriennales.NoduNormalise, d!.nomTerritoire);
......@@ -88,7 +86,7 @@ export class AfficheurDiagnosticPratiquesAgricoles implements Afficheur<Rapport>
);
document.getElementById(
'evolution-nodu-normalise-chart-legende'
'evolution-nodu-normalise-chart-titre'
)!.innerHTML = `Source : Les Greniers d'Abondance, à partir des données ${Indicateur.noduNormalise.sources}`;
document.getElementById('message-detaille-sau-bio')!.innerHTML = rapport.getDiagnosticActif()?.pratiquesAgricoles.messageSauBio!;
......