Download QGIS Customizable SVG

下载 iconfont SVG 图标为 QGIS 可调整参数的 SVG 图标

  1. // ==UserScript==
  2. // @name Download QGIS Customizable SVG
  3. // @namespace http://github.com/liuxspro/
  4. // @version 0.1.0
  5. // @description 下载 iconfont SVG 图标为 QGIS 可调整参数的 SVG 图标
  6. // @author Liuxspro
  7. // @license MIT
  8. // @homepage https://gist.github.com/liuxspro/052d180ed5667560a5f9d4eda11a8b0a
  9. // @match https://www.iconfont.cn/collections/detail*
  10. // @match https://www.iconfont.cn/search/index*
  11. // @icon data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik02MC4yNTcyIDYxLjc1NTZMMjYuNTA3MiAyOC4wMDU2SDM1Ljg4MjJMNjAuMjU3MiA1Mi4zODA2TDYwLjI1NzIgNTIuMzgwNVY2MS43NTU2WiIgZmlsbD0iI0YxOEQzNiIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTI2LjUwNzIgMjguMDA1Nkw2MC4yNTcyIDYxLjc1NTZMNTAuODgyMiA2MS43NTU2TDI2LjUwNzIgMzcuMzgwNkwyNi41MDcyIDI4LjAwNTZaIiBmaWxsPSIjRUU3OTEzIi8+CjxwYXRoIGQ9Ik0zNC4zIDM1LjgxOTFMMzguMDQwNyAzOS41MjU2VjQ4Ljk0OTJMMzQuMyA0NS4xOTEyVjM1LjgxOTFaIiBmaWxsPSIjRjBFNjRBIi8+CjxwYXRoIGQ9Ik00Ny40MzAxIDM5LjU1OThMNDMuNjcyMSAzNS44MTkxTDM0LjMgMzUuODE5MUwzOC4wMzA2IDM5LjU1OThMNDcuNDMwMSAzOS41NTk4WiIgZmlsbD0iI0YyRUE2NSIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTU4LjI1NzggNDYuNTIxQzYwLjY0MjMgNDIuMjE4MyA2MiAzNy4yNjc3IDYyIDMyQzYyIDE1LjQzMTUgNDguNTY4NSAyIDMyIDJDMTUuNDMxNSAyIDIgMTUuNDMxNSAyIDMyQzIgNDguNTY4NSAxNS40MzE1IDYyIDMyIDYyQzM2LjQ2MTEgNjIgNDAuNjk0NyA2MS4wMjYzIDQ0LjUgNTkuMjc5OEwzNS4yNjg3IDUwLjA0ODVDMzQuMjA4IDUwLjIzOTMgMzMuMTE1NiA1MC4zMzg5IDMyIDUwLjMzODlDMjEuODcxNyA1MC4zMzg5IDEzLjY2MTEgNDIuMTI4MyAxMy42NjExIDMyQzEzLjY2MTEgMjEuODcxNyAyMS44NzE3IDEzLjY2MTEgMzIgMTMuNjYxMUM0Mi4xMjgzIDEzLjY2MTEgNTAuMzM4OSAyMS44NzE3IDUwLjMzODkgMzJDNTAuMzM4OSAzMy45ODk3IDUwLjAyMjEgMzUuOTA1NCA0OS40MzYxIDM3LjY5OTNMNTguMjU3OCA0Ni41MjFaIiBmaWxsPSIjN0RBNjI5Ii8+Cjwvc3ZnPgo=
  12. // @grant none
  13. // @run-at document-end
  14. // ==/UserScript==
  15.  
  16. (function () {
  17. "use strict";
  18.  
  19. /**
  20. * 参考资料:
  21. * https://github.com/qgis/QGIS/blob/9a800b49983ae266af1264e198b5fc433fdeaa9b/src/core/symbology/qgssvgcache.h#L105
  22. * https://www.w3.org/TR/2009/WD-SVGParamPrimer-20090616/
  23. * [教会你自定义SVG样式【文末附福利】](https://mp.weixin.qq.com/s/i9FvQrDlGUNdXT6kLoQxNg)
  24. * fill="param(fill)" fill-opacity="param(fill-opacity)"
  25. * stroke="param(outline)" stroke-opacity="param(outline-opacity)" stroke-width="param(outline-width)"
  26. */
  27.  
  28. function tweak_svg(svg) {
  29. const fill = svg.getAttribute("fill");
  30. // 设置为 QGIS 可自定义的属性
  31. svg.setAttribute("fill", "param(fill)");
  32. svg.setAttribute("fill-opacity", "param(fill-opacity)");
  33. svg.setAttribute("stroke", "param(outline)");
  34. svg.setAttribute("stroke-opacity", "param(outline-opacity)");
  35. svg.setAttribute("stroke-width", "param(outline-width)");
  36. if (fill) {
  37. // 将原来的 fill 颜色作为默认值保留
  38. svg.setAttribute("fill", `param(fill) ${fill}`);
  39. }
  40. }
  41.  
  42. function download() {
  43. const svgElement = document.querySelector("div.stage svg");
  44. const titleElement = document.querySelector("div.top-title span");
  45. let filename = "download.svg";
  46. if (titleElement) {
  47. filename = titleElement.innerText + "_QGIS";
  48. }
  49. if (svgElement) {
  50. const svgClone = svgElement.cloneNode(true);
  51. svgClone.removeAttribute("style");
  52.  
  53. const elementsPath = svgClone.querySelectorAll("path");
  54.  
  55. // 不止一条 Path 的时候,需要至少选择一条 Path 作为调整的对象
  56. if (elementsPath.length > 1) {
  57. const selectedPaths = Array.from(elementsPath).filter((path) => path.classList.contains("selected"));
  58. if (selectedPaths.length == 0) {
  59. alert("当前 SVG 图标有多条 PATH, 请至少选择一条");
  60. return;
  61. }
  62. selectedPaths.forEach((el) => {
  63. tweak_svg(el);
  64. });
  65. } else if (elementsPath.length == 1) {
  66. elementsPath.forEach((el) => {
  67. tweak_svg(el);
  68. });
  69. }
  70.  
  71. const serializer = new XMLSerializer();
  72. const svgString = serializer.serializeToString(svgClone);
  73. const blob = new Blob([svgString], { type: "image/svg+xml" });
  74. const url = URL.createObjectURL(blob);
  75. const a = document.createElement("a");
  76. a.href = url;
  77. a.download = filename;
  78. document.body.appendChild(a);
  79. a.click();
  80. document.body.removeChild(a);
  81. URL.revokeObjectURL(url);
  82. } else {
  83. alert("SVG element not found");
  84. }
  85. }
  86. function add_download_btn() {
  87. const btn_container = document.querySelectorAll("div.download-btns")[0];
  88. if (btn_container && !btn_container.querySelector(".qgis-btn")) {
  89. const qgis_svg_download_btn = document.createElement("span");
  90. qgis_svg_download_btn.classList = "btn btn-normal qgis-btn";
  91. qgis_svg_download_btn.innerText = "下载 QGIS SVG";
  92. qgis_svg_download_btn.onclick = download;
  93. btn_container.appendChild(qgis_svg_download_btn);
  94. }
  95. }
  96.  
  97. // MutationObserver to watch for changes in the DOM
  98. const observer = new MutationObserver((mutations) => {
  99. mutations.forEach((mutation) => {
  100. if (mutation.addedNodes.length > 0) {
  101. const d = mutation.addedNodes[0];
  102. if (d.classList.contains("download-dialog")) {
  103. observer2.observe(d, config);
  104. }
  105. }
  106. });
  107. });
  108.  
  109. const observer2 = new MutationObserver((mutations) => {
  110. mutations.forEach((mutation) => {
  111. observer2.disconnect();
  112. add_download_btn(document.body);
  113. observer2.observe(mutation.target, config);
  114. });
  115. });
  116.  
  117. // Configuration of the observer
  118. const config = {
  119. attributes: false,
  120. childList: true,
  121. subtree: true,
  122. };
  123.  
  124. // Start observing the target node for configured mutations
  125. const targetNode = document.body;
  126. observer.observe(targetNode, config);
  127. })();