MapaBrasil.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
  2. <template>
  3. <div>
  4. <q-card style="height: 100%">
  5. <q-card-section class="row justify-between">
  6. <div class="column">
  7. <span class="text-bold text-description q-mb-sm">
  8. {{ props.title }}
  9. </span>
  10. <span>{{ props.subtitle }}</span>
  11. </div>
  12. <q-btn
  13. icon="mdi-tray-arrow-down"
  14. dense
  15. flat
  16. class="q-my-auto"
  17. @click="downloadImage"
  18. />
  19. </q-card-section>
  20. <q-separator inset />
  21. <q-card-section>
  22. <div style="display: flex; flex-direction: column">
  23. <div @mouseover="hideInfoBox">
  24. <svg
  25. ref="ref_mapa"
  26. xmlns="http://www.w3.org/2000/svg"
  27. class="mapa-svg-estados"
  28. viewBox="120 50 500 500"
  29. @click="mapclick"
  30. >
  31. <g id="mapa-svg-area">
  32. <MapaEstado
  33. v-for="item in items"
  34. ref="child"
  35. :key="item.uf"
  36. :item="item"
  37. :show-circle-info="showCircleInfo"
  38. :class="item.classObject"
  39. :style="item.color ? `fill: ${item.color}` : ''"
  40. @state-selected-event="onStateSelectedEvent"
  41. @state-mouse-over-event="onStateMouseOverEvent"
  42. />
  43. </g>
  44. </svg>
  45. </div>
  46. <div class="bg-background--2 q-pa-md" style="border-radius: 0.5rem">
  47. <div
  48. v-if="selected"
  49. style="display: flex; flex-direction: column; gap: 0.5rem"
  50. >
  51. <span>
  52. <b> Estado:</b> {{ dadosEstado.name }} -
  53. {{ dadosEstado.uf.toUpperCase() }}
  54. </span>
  55. <span><b>Participantes:</b> {{ dadosEstado.pessoas || 0 }}</span>
  56. </div>
  57. <div
  58. v-else
  59. style="display: flex; flex-direction: column; gap: 0.5rem"
  60. >
  61. <span>
  62. <b>Selecione um estado</b>
  63. </span>
  64. </div>
  65. </div>
  66. </div>
  67. </q-card-section>
  68. </q-card>
  69. </div>
  70. </template>
  71. <script setup>
  72. import { computed, onMounted, ref } from "vue";
  73. import MapaEstado from "../MapaEstado.vue";
  74. import { DadosBrasil } from "./DadosBrasil";
  75. import { base64ToJPEG } from "src/helpers/convertBase64Image";
  76. const selected = ref(null);
  77. const showCircleInfo = ref(false);
  78. const infoBoxActive = ref(false);
  79. const infoBoxPosX = ref(0);
  80. const infoBoxPosY = ref(0);
  81. const infoBoxData = ref("");
  82. const child = ref(null);
  83. const items = ref(DadosBrasil);
  84. const ref_mapa = ref(null);
  85. const props = defineProps({
  86. data: {
  87. type: Array,
  88. required: true,
  89. },
  90. title: {
  91. type: String,
  92. required: false,
  93. default: "PARTICIPANTES POR ESTADO - BRASIL",
  94. },
  95. subtitle: {
  96. type: String,
  97. required: false,
  98. default: "Número de participantes do evento por estado brasileiro",
  99. },
  100. });
  101. const mapclick = (event) => {
  102. // console.log("mapa-brasil: mapclick");
  103. if (event.target.tagName == "svg") {
  104. resetSelectionAction();
  105. infoBoxActive.value = false;
  106. }
  107. };
  108. const onStateSelectedEvent = (args) => {
  109. // console.log("mapa-brasil: onStateSelectedEvent: ", args);
  110. selected.value = args.src.item.uf;
  111. resetSelectionAction();
  112. args.enable();
  113. };
  114. const onStateMouseOverEvent = (args) => {
  115. // console.log("mapa-brasil: onStateMouseOverEvent: ", args);
  116. setInfoBoxPosition({ x: args.event.pageX, y: args.event.pageY });
  117. setInfoBoxData([
  118. args.src.item.name,
  119. args.src.item.regional,
  120. args.src.item.altText,
  121. ]);
  122. infoBoxActive.value = true;
  123. };
  124. const resetSelectionAction = () => {
  125. // console.log("mapa-brasil: resetSelectionAction", child.value);
  126. for (let index = 0; index < child.value.length; index++) {
  127. child.value[index].resetAction();
  128. }
  129. };
  130. const setInfoBoxPosition = (args) => {
  131. infoBoxPosX.value = args.x + 30;
  132. infoBoxPosY.value = args.y;
  133. };
  134. const setInfoBoxData = (args) => {
  135. infoBoxData.value = args.filter(function (a) {
  136. return a !== "" ? a : null;
  137. });
  138. };
  139. const hideInfoBox = (args) => {
  140. if (
  141. ["DIV", "SVG"].indexOf(args.target.tagName.toString().toUpperCase()) > -1
  142. ) {
  143. infoBoxActive.value = false;
  144. }
  145. };
  146. onMounted(() => {
  147. const dataOrganizada = [...props.data].sort(
  148. (a, b) => a?.total_pessoas_por_estado - b?.total_pessoas_por_estado
  149. );
  150. const maiorNumero =
  151. dataOrganizada[dataOrganizada.length - 1]?.total_pessoas_por_estado;
  152. const faixa = maiorNumero / 5;
  153. const colors = ["#f6a0a1", "#f27e7f", "#ee585a", "#EB3537", "#c31315"];
  154. items.value.forEach((item) => {
  155. const estado = dataOrganizada.find((e) => e.estado === item.uf);
  156. if (estado) {
  157. const indexFaixa = Math.ceil(estado?.total_pessoas_por_estado / faixa);
  158. item.color = colors[indexFaixa - 1];
  159. item.pessoas = estado.total_pessoas_por_estado;
  160. } else {
  161. item.color = "#494949";
  162. item.pessoas = 0;
  163. }
  164. });
  165. });
  166. const dadosEstado = computed(() => {
  167. const estado = items.value.find((item) => item.uf === selected.value);
  168. return estado;
  169. });
  170. const downloadImage = () => {
  171. const svgString = new XMLSerializer().serializeToString(ref_mapa.value);
  172. const base64String = btoa(svgString);
  173. base64ToJPEG(base64String, props.title);
  174. };
  175. </script>
  176. <style lang="scss">
  177. svg text {
  178. fill: var(--default-stroke);
  179. font-family: monospace;
  180. }
  181. .mapa-svg-estados {
  182. fill: var(--default-fill);
  183. -webkit-transition: 0.8s ease;
  184. -moz-transition: 0.8s ease;
  185. -ms-transition: 0.8s ease;
  186. -o-transition: 0.8s ease;
  187. transition: 0.8s ease;
  188. stroke-dasharray: 180%;
  189. stroke-dashoffset: -120%;
  190. stroke-width: 1px;
  191. stroke: var(--default-stroke);
  192. text {
  193. fill: var(--default-stroke);
  194. stroke: none !important;
  195. }
  196. }
  197. .mapa-svg-estados:hover {
  198. cursor: pointer;
  199. fill: #8d1012 !important;
  200. }
  201. .mapa-svg-estados-active {
  202. cursor: pointer;
  203. stroke: #ffffff;
  204. fill: #ffc712 !important;
  205. stroke-dashoffset: 0%;
  206. transition: 0.8s ease;
  207. -webkit-transition: 0.8s ease;
  208. -moz-transition: 0.8s ease;
  209. -ms-transition: 0.8s ease;
  210. -o-transition: 0.8s ease;
  211. text {
  212. fill: #ffffff;
  213. stroke: none !important;
  214. }
  215. }
  216. </style>