From f115c87ad38bfb6f0f28ad4ac44d0b13d2cf2476 Mon Sep 17 00:00:00 2001 From: bach Date: Tue, 1 Oct 2024 21:57:47 +0200 Subject: [PATCH] custom dynamic sites svg map --- composer.json | 1 + composer.lock | 67 ++++++++++- ...ntity_form_display.node.static.default.yml | 17 +-- ...ntity_view_display.node.static.default.yml | 14 +-- ...e.entity_view_display.node.static.full.yml | 15 +-- ...entity_view_display.node.static.teaser.yml | 2 + config/sync/core.extension.yml | 1 + ...ield.field.node.static.field_map_block.yml | 25 ++++ .../field.storage.node.field_map_block.yml | 19 +++ ...age_variant.node_view-panels_variant-0.yml | 13 +- config/sync/views.view.statics_fields.yml | 4 +- .../assets/css/carte-interactive-qdd.css | 57 +++++++++ .../custom/q2d_mod/assets/css/fontface.css | 0 .../fonts/Gilroy/gilroy-semibold-webfont.woff | Bin 0 -> 27088 bytes .../assets/js/carte-interactive-qdd.js | 91 ++++++++++++++ .../custom/q2d_mod/q2d_mod.libraries.yml | 7 ++ web/modules/custom/q2d_mod/q2d_mod.module | 10 ++ .../q2d_mod/src/Plugin/Block/SitesMap.php | 113 ++++++++++++++++++ .../q2d_mod/templates/svg-mapsites.html.twig | 50 ++++++++ 19 files changed, 471 insertions(+), 35 deletions(-) create mode 100644 config/sync/field.field.node.static.field_map_block.yml create mode 100644 config/sync/field.storage.node.field_map_block.yml create mode 100644 web/modules/custom/q2d_mod/assets/css/carte-interactive-qdd.css create mode 100644 web/modules/custom/q2d_mod/assets/css/fontface.css create mode 100644 web/modules/custom/q2d_mod/assets/css/fonts/Gilroy/gilroy-semibold-webfont.woff create mode 100644 web/modules/custom/q2d_mod/assets/js/carte-interactive-qdd.js create mode 100644 web/modules/custom/q2d_mod/q2d_mod.libraries.yml create mode 100644 web/modules/custom/q2d_mod/src/Plugin/Block/SitesMap.php create mode 100644 web/modules/custom/q2d_mod/templates/svg-mapsites.html.twig diff --git a/composer.json b/composer.json index 0b5c4e1..deed314 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ ], "require": { "composer/installers": "^2.0", + "drupal/block_field": "^1.0@RC", "drupal/config_pages": "^2.15", "drupal/core-composer-scaffold": "^10.2", "drupal/core-project-message": "^10.2", diff --git a/composer.lock b/composer.lock index 86a3600..2afe550 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "365559febcbdf4e52ca276eed5a58fe5", + "content-hash": "d9c788ae880184300ad1f5beb62e85a1", "packages": [ { "name": "asm89/stack-cors", @@ -2271,6 +2271,70 @@ "irc": "irc://irc.freenode.org/drupal-contribute" } }, + { + "name": "drupal/block_field", + "version": "1.0.0-rc5", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/block_field.git", + "reference": "8.x-1.0-rc5" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/block_field-8.x-1.0-rc5.zip", + "reference": "8.x-1.0-rc5", + "shasum": "b87e43e9bbaaf6cff6d8946d5e45db492978cbb6" + }, + "require": { + "drupal/core": "^9 || ^10 || ^11" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "8.x-1.0-rc5", + "datestamp": "1723550576", + "security-coverage": { + "status": "not-covered", + "message": "RC releases are not covered by Drupal security advisories." + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "acbramley", + "homepage": "https://www.drupal.org/user/1036766" + }, + { + "name": "berdir", + "homepage": "https://www.drupal.org/user/214652" + }, + { + "name": "fenstrat", + "homepage": "https://www.drupal.org/user/362649" + }, + { + "name": "jrockowitz", + "homepage": "https://www.drupal.org/user/371407" + }, + { + "name": "michaellander", + "homepage": "https://www.drupal.org/user/636494" + }, + { + "name": "paulocs", + "homepage": "https://www.drupal.org/user/3640109" + } + ], + "description": "Provides a field that allows a content entity to create and configure custom block instances.", + "homepage": "https://www.drupal.org/project/block_field", + "support": { + "source": "https://git.drupalcode.org/project/block_field" + } + }, { "name": "drupal/bulkdelete", "version": "dev-1.x", @@ -12825,6 +12889,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { + "drupal/block_field": 5, "drupal/page_manager": 5, "drupal/viewsreference": 10, "drupal/advanced_text_formatter": 5, diff --git a/config/sync/core.entity_form_display.node.static.default.yml b/config/sync/core.entity_form_display.node.static.default.yml index b8aa4b4..2195181 100644 --- a/config/sync/core.entity_form_display.node.static.default.yml +++ b/config/sync/core.entity_form_display.node.static.default.yml @@ -5,16 +5,17 @@ dependencies: config: - field.field.node.static.body - field.field.node.static.field_map + - field.field.node.static.field_map_block - field.field.node.static.field_pieces_jointes - field.field.node.static.field_textes - node.type.static module: + - block_field - field_group - file - paragraphs - path - text - - viewsreference third_party_settings: field_group: group_details: @@ -57,15 +58,14 @@ content: region: content settings: { } third_party_settings: { } - field_map: - type: viewsreference_autocomplete + field_map_block: + type: block_field_default weight: 2 region: content settings: - match_operator: CONTAINS - match_limit: 10 - size: 60 - placeholder: '' + plugin_id: '' + settings: { } + configuration_form: full third_party_settings: { } field_pieces_jointes: type: file_generic @@ -159,4 +159,5 @@ content: size: 60 placeholder: '' third_party_settings: { } -hidden: { } +hidden: + field_map: true diff --git a/config/sync/core.entity_view_display.node.static.default.yml b/config/sync/core.entity_view_display.node.static.default.yml index b5876d1..5c2e7fe 100644 --- a/config/sync/core.entity_view_display.node.static.default.yml +++ b/config/sync/core.entity_view_display.node.static.default.yml @@ -5,14 +5,15 @@ dependencies: config: - field.field.node.static.body - field.field.node.static.field_map + - field.field.node.static.field_map_block - field.field.node.static.field_pieces_jointes - field.field.node.static.field_textes - node.type.static module: + - block_field - entity_reference_revisions - manage_display - text - - viewsreference _core: default_config_hash: 9mgezio6-8HiMYhQHSfouZjKyY4BFKR71Yh4kbSmAYU id: node.static.default @@ -27,12 +28,10 @@ content: third_party_settings: { } weight: 1 region: content - field_map: - type: viewsreference_formatter - label: visually_hidden - settings: - plugin_types: - - block + field_map_block: + type: block_field + label: above + settings: { } third_party_settings: { } weight: 2 region: content @@ -61,6 +60,7 @@ content: region: content hidden: created: true + field_map: true field_pieces_jointes: true langcode: true search_api_excerpt: true diff --git a/config/sync/core.entity_view_display.node.static.full.yml b/config/sync/core.entity_view_display.node.static.full.yml index 000f18f..44fd713 100644 --- a/config/sync/core.entity_view_display.node.static.full.yml +++ b/config/sync/core.entity_view_display.node.static.full.yml @@ -6,14 +6,15 @@ dependencies: - core.entity_view_mode.node.full - field.field.node.static.body - field.field.node.static.field_map + - field.field.node.static.field_map_block - field.field.node.static.field_pieces_jointes - field.field.node.static.field_textes - node.type.static module: + - block_field - entity_reference_revisions - manage_display - text - - viewsreference _core: default_config_hash: 9mgezio6-8HiMYhQHSfouZjKyY4BFKR71Yh4kbSmAYU id: node.static.full @@ -28,15 +29,10 @@ content: third_party_settings: { } weight: 1 region: content - field_map: - type: viewsreference_formatter + field_map_block: + type: block_field label: hidden - settings: - plugin_types: - block: block - default: '0' - page: '0' - feed: '0' + settings: { } third_party_settings: { } weight: 2 region: content @@ -65,6 +61,7 @@ content: region: content hidden: created: true + field_map: true field_pieces_jointes: true langcode: true search_api_excerpt: true diff --git a/config/sync/core.entity_view_display.node.static.teaser.yml b/config/sync/core.entity_view_display.node.static.teaser.yml index 4c5023e..3e2369c 100644 --- a/config/sync/core.entity_view_display.node.static.teaser.yml +++ b/config/sync/core.entity_view_display.node.static.teaser.yml @@ -6,6 +6,7 @@ dependencies: - core.entity_view_mode.node.teaser - field.field.node.static.body - field.field.node.static.field_map + - field.field.node.static.field_map_block - field.field.node.static.field_pieces_jointes - field.field.node.static.field_textes - node.type.static @@ -35,6 +36,7 @@ content: hidden: created: true field_map: true + field_map_block: true field_pieces_jointes: true field_textes: true langcode: true diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index b57c7eb..0e9e8be 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -13,6 +13,7 @@ module: block: 0 block_class: 0 block_content: 0 + block_field: 0 breakpoint: 0 bulkdelete: 0 ckeditor5: 0 diff --git a/config/sync/field.field.node.static.field_map_block.yml b/config/sync/field.field.node.static.field_map_block.yml new file mode 100644 index 0000000..5b47170 --- /dev/null +++ b/config/sync/field.field.node.static.field_map_block.yml @@ -0,0 +1,25 @@ +uuid: f1d706d7-b94c-4070-a98d-e00418611b82 +langcode: fr +status: true +dependencies: + config: + - field.storage.node.field_map_block + - node.type.static + module: + - block_field +id: node.static.field_map_block +field_name: field_map_block +entity_type: node +bundle: static +label: 'map block' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + selection: blocks + selection_settings: + plugin_ids: + sitesmap_block: sitesmap_block +field_type: block_field diff --git a/config/sync/field.storage.node.field_map_block.yml b/config/sync/field.storage.node.field_map_block.yml new file mode 100644 index 0000000..d05e641 --- /dev/null +++ b/config/sync/field.storage.node.field_map_block.yml @@ -0,0 +1,19 @@ +uuid: fe870b67-228b-460b-848b-b696a91b740c +langcode: fr +status: true +dependencies: + module: + - block_field + - node +id: node.field_map_block +field_name: field_map_block +entity_type: node +type: block_field +settings: { } +module: block_field +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/sync/page_manager.page_variant.node_view-panels_variant-0.yml b/config/sync/page_manager.page_variant.node_view-panels_variant-0.yml index 0a673b0..864f931 100644 --- a/config/sync/page_manager.page_variant.node_view-panels_variant-0.yml +++ b/config/sync/page_manager.page_variant.node_view-panels_variant-0.yml @@ -202,18 +202,15 @@ variant_settings: - '' html_id: '' css_styles: '' - 9c0f77a5-efea-4e81-99c4-2199c1d0d07d: - id: 'views_block:site-block_2' - label: '' + f3919785-5a3a-4926-9de5-e63613bcba52: + id: sitesmap_block + label: 'Sites map Block' label_display: '0' - provider: views + provider: q2d_mod context_mapping: { } - views_label: '' - items_per_page: none - exposed: { } region: first weight: -4 - uuid: 9c0f77a5-efea-4e81-99c4-2199c1d0d07d + uuid: f3919785-5a3a-4926-9de5-e63613bcba52 css_classes: - '' html_id: '' diff --git a/config/sync/views.view.statics_fields.yml b/config/sync/views.view.statics_fields.yml index 36fd839..e94148a 100644 --- a/config/sync/views.view.statics_fields.yml +++ b/config/sync/views.view.statics_fields.yml @@ -39,7 +39,7 @@ display: alter_text: false text: '' make_link: false - path: '' + path: '{{ field_pieces_jointes }}' absolute: false external: false replace_spaces: false @@ -50,7 +50,7 @@ display: link_class: '' prefix: '' suffix: '' - target: '' + target: _blank nl2br: false max_length: 0 word_boundary: true diff --git a/web/modules/custom/q2d_mod/assets/css/carte-interactive-qdd.css b/web/modules/custom/q2d_mod/assets/css/carte-interactive-qdd.css new file mode 100644 index 0000000..f4fb740 --- /dev/null +++ b/web/modules/custom/q2d_mod/assets/css/carte-interactive-qdd.css @@ -0,0 +1,57 @@ +@font-face { + font-family: 'gilroy-semibold'; + src: url('fonts/Gilroy/gilroy-semibold-webfont.woff') format('woff'); +} +#sites-map-container { + background-color: #c3cef2; + text-align: center; +} +/* #sites-map-container .circle { + fill: black; + stroke: white; + stroke-width: 0.7; +} */ + +/* Changer la couleur au survol (hover) */ +#sites-map-container .site-link:hover{ + cursor: pointer; +} + +#sites-map-container .site-link:hover circle.circle { + fill: #f7002b!important; +} + +/* Styles du popup (caché par défaut) */ +#sites-map-container #popup { + font-family: 'gilroy-semibold'; + display: none; + position: fixed; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 1000; +} + +#sites-map-container strong{ + color: #f7002b; + font-family: 'gilroy-semibold'; +} +#sites-map-container a{ + display: inline-flex; + align-items: center; + color: white; + background: black; + text-transform: uppercase; + font-size: 0.8rem; + padding-left: 0.5rem; + text-decoration: none; + margin-top: 0.7rem; + height: 1.3rem; +} +#sites-map-container a:after{ + display: inline-flex; + content: url("../img/noun-arrow-to-right.svg"); + padding-right: 0.2rem; + padding-left: 0.2rem; + +} diff --git a/web/modules/custom/q2d_mod/assets/css/fontface.css b/web/modules/custom/q2d_mod/assets/css/fontface.css new file mode 100644 index 0000000..e69de29 diff --git a/web/modules/custom/q2d_mod/assets/css/fonts/Gilroy/gilroy-semibold-webfont.woff b/web/modules/custom/q2d_mod/assets/css/fonts/Gilroy/gilroy-semibold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..8abd458a28b3f961f23a77efe00ae968d4713199 GIT binary patch literal 27088 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 DEWD@B literal 0 HcmV?d00001 diff --git a/web/modules/custom/q2d_mod/assets/js/carte-interactive-qdd.js b/web/modules/custom/q2d_mod/assets/js/carte-interactive-qdd.js new file mode 100644 index 0000000..e83bc3c --- /dev/null +++ b/web/modules/custom/q2d_mod/assets/js/carte-interactive-qdd.js @@ -0,0 +1,91 @@ +// Sélection des éléments au préalable pour éviter de les rechercher plusieurs fois +const svgElement = document.querySelector('#sites-map-container svg'); +const popup = document.querySelector('#sites-map-container #popup'); +const popupContent = document.querySelector('#sites-map-container #popup-content'); +const modalBackground = document.querySelector('#sites-map-container #modal-background'); +console.log('svgElement', svgElement); + +// Fonction pour afficher le popup +function showPopup(content, x, y) { + console.log('showPopup', content, x, y); + + popupContent.innerHTML = content; + + // Récupérer la position de l'élément SVG seulement une fois + const rect = svgElement.getBoundingClientRect(); + + // Calculer la position du popup par rapport à l'élément SVG + const popupX = rect.left + x + 120; // Décalage de 120px à droite + const popupY = rect.top + y + 20; // Décalage de 20px en dessous + + // Dimensions de la fenêtre et du popup + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const popupWidth = popup.offsetWidth; + const popupHeight = popup.offsetHeight; + + // Vérification des bordures droite et gauche + if (popupX + popupWidth > viewportWidth) { + popupX = viewportWidth - popupWidth - 10; // Ajuster pour qu'il ne dépasse pas à droite + } + if (popupX < 0) { + popupX = 10; // S'assurer que le popup ne dépasse pas à gauche + } + + // Vérification des bordures inférieure et supérieure + if (popupY + popupHeight > viewportHeight) { + popupY = viewportHeight - popupHeight - 10; // Ajuster pour qu'il ne dépasse pas en bas + } + if (popupY < 0) { + popupY = 10; // S'assurer que le popup ne dépasse pas en haut + } + + popup.style.left = `${popupX}px`; + popup.style.top = `${popupY}px`; + popup.style.display = 'block'; + modalBackground.style.display = 'block'; // Activer le fond modal si nécessaire +} + +// Recalculer la position du popup lors du redimensionnement de la fenêtre +window.addEventListener('resize', function() { + if (popup.style.display === 'block') { + // Recalculer les coordonnées et ajuster la position + const currentPopupRect = popup.getBoundingClientRect(); + showPopup(popupContent.innerHTML, currentPopupRect.left, currentPopupRect.top); + } +}); + +// Fonction pour fermer le popup +function closePopup() { + popup.style.display = 'none'; + modalBackground.style.display = 'none'; // Désactiver le fond modal +} + +// Ajout d'un écouteur d'événement sur l'élément SVG pour tous les cercles +svgElement.addEventListener('click', function(event) { + console.log('svgElement click', event.target); + + if (event.target.classList.contains('site-link')) { + // Récupérer le contenu personnalisé de l'attribut data-content + const content = event.target.getAttribute('data-content'); + + // Récupérer la position du cercle cliqué par rapport à l'élément SVG + const rect = svgElement.getBoundingClientRect(); + const circleX = event.clientX - rect.left; + const circleY = event.clientY - rect.top; + + // Afficher le popup avec le contenu spécifique + showPopup(content, circleX, circleY); + + // Empêcher la propagation de l'événement pour éviter la fermeture immédiate + event.stopPropagation(); + } +}); + +// Ferme le popup quand on clique n'importe où sur la page, sauf sur le popup +document.addEventListener('click', function(event) { + // Vérifier si le clic s'est produit en dehors du popup + if (popup.style.display === 'block' && !popup.contains(event.target)) { + closePopup(); + } +}); diff --git a/web/modules/custom/q2d_mod/q2d_mod.libraries.yml b/web/modules/custom/q2d_mod/q2d_mod.libraries.yml new file mode 100644 index 0000000..674b807 --- /dev/null +++ b/web/modules/custom/q2d_mod/q2d_mod.libraries.yml @@ -0,0 +1,7 @@ +sites_map_block: + css: + theme: + assets/css/fontface.css: {} + assets/css/carte-interactive-qdd.css: {} + js: + assets/js/carte-interactive-qdd.js: {} \ No newline at end of file diff --git a/web/modules/custom/q2d_mod/q2d_mod.module b/web/modules/custom/q2d_mod/q2d_mod.module index 9178a83..b1a6529 100644 --- a/web/modules/custom/q2d_mod/q2d_mod.module +++ b/web/modules/custom/q2d_mod/q2d_mod.module @@ -5,3 +5,13 @@ * Primary module hooks for reha module. */ +/** + * Implements hook_theme(). + */ +function q2d_mod_theme() { + return array( + 'svg_mapsites' => array( + 'variables' => array('vpw' => null, 'vph' => null, 'sites' => []), + ), + ); +} \ No newline at end of file diff --git a/web/modules/custom/q2d_mod/src/Plugin/Block/SitesMap.php b/web/modules/custom/q2d_mod/src/Plugin/Block/SitesMap.php new file mode 100644 index 0000000..88774f5 --- /dev/null +++ b/web/modules/custom/q2d_mod/src/Plugin/Block/SitesMap.php @@ -0,0 +1,113 @@ +getStorage('node') + ->loadByProperties(['type' => 'site', 'status' => 1]); + + $sites_paths = ""; + + $vp_w = 400; + $vp_h = 400; + + // Coordonnées géographiques des coins de la carte (France) + $latTop = 52.0; // Nord-Ouest (coin supérieur gauche) + $lonLeft = -6.0; + $latBottom = 40.0; // Sud-Est (coin inférieur droit) + $lonRight = 11.0; + + + foreach($allSites as $index => $site){ + $title = $site->get('title')->getString(); + $subtitle = $site->get('field_sous_titre')->getString(); + + $link_options = ['absolute' => FALSE, 'attributes' => ['class' => 'site-link']]; + $site_link_object = Link::createFromRoute("voir le site", 'entity.node.canonical', ['node' => $site->id()], $link_options); + $link = $site_link_object->toString()->getGeneratedLink(); + + $datacontent = htmlspecialchars("$title
$subtitle
$link"); + + $geofield = $site->get('field_geofield')->get(0); + $lon = $geofield->lon; + $lat = $geofield->lat; + + $x = round(($lon - $lonLeft) / ($lonRight - $lonLeft) * $vp_w); + $y = round(($latTop - $lat) / ($latTop - $latBottom) * $vp_h); + + $r = 10; + $m = -$r+2; + $l = $r*2-4; + $sites_paths .= << + + + + + + SVGSITEPATH; + } + + + $return = [ + '#cache' => [ + 'max-age' => 0, + ], + 'svg_mapsites' => [ + '#theme' => 'svg_mapsites', + '#sites' => $sites_paths, + '#vpw' => $vp_w, + '#vph' => $vp_h, + '#attached' => [ + 'library' => [ + 'q2d_mod/sites_map_block', + ], + ], + ] + ]; + + return $return; + // return [ + // '#markup' => $this->t('Hello, Sites Map!'), + // ]; + } + public function getCacheMaxAge() { + return 0; + } +} \ No newline at end of file diff --git a/web/modules/custom/q2d_mod/templates/svg-mapsites.html.twig b/web/modules/custom/q2d_mod/templates/svg-mapsites.html.twig new file mode 100644 index 0000000..9985a2c --- /dev/null +++ b/web/modules/custom/q2d_mod/templates/svg-mapsites.html.twig @@ -0,0 +1,50 @@ +
+ {# + + #} + + + + + + + + + + {{ sites|raw }} + + + + + + + + +
\ No newline at end of file