【问题标题】:Flip most of an svg image, but not the text within it翻转大部分 svg 图像,但不翻转其中的文本
【发布时间】:2019-02-03 08:32:50
【问题描述】:

我收集了大量这样的 svg 图片:

<svg version="1.1" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
  <g stroke="lightgray" stroke-dasharray="1,1" stroke-width="1" transform="scale(4, 4)">
    <line x1="0" y1="0" x2="256" y2="256"></line>
    <line x1="256" y1="0" x2="0" y2="256"></line>
    <line x1="128" y1="0" x2="128" y2="256"></line>
    <line x1="0" y1="128" x2="256" y2="128"></line>
  </g>
  <g transform="scale(1, -1) translate(0, -900)">
      <style>
        .stroke1 {fill: #BF0909;}
        .stroke2 {fill: #BFBF09;}
        .stroke3 {fill: #09BF09;}
        .stroke4 {fill: #09BFBF;}
        .stroke5 {fill: #0909BF;}
        .stroke6 {fill: #BF09BF;}
        .stroke7 {fill: #BFBFBF;}
        .stroke8 {fill: #090909;}
      </style>

      <path class="stroke1" d="M 272 567 Q 306 613 342 669 Q 370 718 395 743 Q 405 753 400 769 Q 396 782 365 808 Q 337 827 316 828 Q 297 827 305 802 Q 318 769 306 741 Q 267 647 207 560 Q 150 476 72 385 Q 60 375 58 367 Q 54 355 70 358 Q 82 359 109 384 Q 155 421 213 493 Q 226 509 241 527 L 272 567 Z" fill="#BF0909"></path>

      <path class="stroke2" d="M 241 527 Q 262 506 258 375 Q 258 374 258 370 Q 254 253 221 135 Q 215 114 224 80 Q 236 44 248 32 Q 267 16 279 44 Q 294 86 294 134 Q 303 420 314 485 Q 321 515 295 543 Q 289 549 272 567 C 251 589 227 553 241 527 Z" fill="lightgray"></path>

      <path class="stroke3" d="M 521 560 Q 561 621 602 708 Q 620 751 638 773 Q 645 786 639 799 Q 633 811 602 830 Q 572 846 554 843 Q 535 839 546 817 Q 561 795 552 757 Q 513 619 407 448 Q 398 436 397 430 Q 394 418 409 423 Q 439 432 503 532 L 521 560 Z" fill="lightgray"></path>

      <path class="stroke4" d="M 503 532 Q 527 510 555 520 Q 795 608 782 549 Q 783 543 743 468 Q 736 458 741 453 Q 745 447 756 459 Q 852 532 894 549 Q 904 552 905 561 Q 906 574 876 592 Q 852 605 828 621 Q 800 637 783 630 Q 686 590 521 560 C 492 555 479 550 503 532 Z" fill="lightgray"></path>

      <path class="stroke5" d="M 568 72 Q 531 81 494 91 Q 482 94 483 86 Q 484 79 494 71 Q 569 7 596 -33 Q 611 -49 626 -36 Q 659 -3 661 82 Q 655 149 655 345 Q 656 382 667 407 Q 676 426 659 439 Q 634 461 604 470 Q 585 477 577 469 Q 571 462 582 447 Q 619 384 603 127 Q 597 82 589 74 Q 582 67 568 72 Z" fill="lightgray"></path>

      <path class="stroke6" d="M 444 320 Q 419 262 385 208 Q 364 180 381 144 Q 388 128 409 139 Q 460 181 468 264 Q 472 295 467 319 Q 463 328 456 328 Q 449 327 444 320 Z" fill="lightgray"></path>

      <path class="stroke7" d="M 738 307 Q 789 249 847 168 Q 860 146 876 139 Q 885 138 893 146 Q 908 159 900 204 Q 891 264 743 338 Q 734 345 731 332 Q 728 319 738 307 Z" fill="lightgray"></path>
  </g>
</svg>

以及必须在其上绘制数字的每个图像的坐标列表(请参阅以下 svg 代码的文本元素)。问题是:当我添加所需的文本元素时,它们被垂直和水平翻转:

<svg version="1.1" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
  <g stroke="lightgray" stroke-dasharray="1,1" stroke-width="1" transform="scale(4, 4)">
    <line x1="0" y1="0" x2="256" y2="256"></line>
    <line x1="256" y1="0" x2="0" y2="256"></line>
    <line x1="128" y1="0" x2="128" y2="256"></line>
    <line x1="0" y1="128" x2="256" y2="128"></line>
  </g>
  <g transform="scale(1, -1) translate(0, -900)">
      <style>
        .stroke1 {fill: #BF0909;}
        .stroke2 {fill: #BFBF09;}
        .stroke3 {fill: #09BF09;}
        .stroke4 {fill: #09BFBF;}
        .stroke5 {fill: #0909BF;}
        .stroke6 {fill: #BF09BF;}
        .stroke7 {fill: #BFBFBF;}
        .stroke8 {fill: #090909;}
        text {
            font-family: Helvetica;
            font-size: 80px;
            fill: #FFFFFF;
            paint-order: stroke;
            stroke: #000000;
            stroke-width: 4px;
            stroke-linecap: butt;
            stroke-linejoin: miter;
            font-weight: 800;
        }
      </style>
      <path class="stroke1" d="M 272 567 Q 306 613 342 669 Q 370 718 395 743 Q 405 753 400 769 Q 396 782 365 808 Q 337 827 316 828 Q 297 827 305 802 Q 318 769 306 741 Q 267 647 207 560 Q 150 476 72 385 Q 60 375 58 367 Q 54 355 70 358 Q 82 359 109 384 Q 155 421 213 493 Q 226 509 241 527 L 272 567 Z" fill="#BF0909"></path>

      <path class="stroke2" d="M 241 527 Q 262 506 258 375 Q 258 374 258 370 Q 254 253 221 135 Q 215 114 224 80 Q 236 44 248 32 Q 267 16 279 44 Q 294 86 294 134 Q 303 420 314 485 Q 321 515 295 543 Q 289 549 272 567 C 251 589 227 553 241 527 Z" fill="lightgray"></path>

      <path class="stroke3" d="M 521 560 Q 561 621 602 708 Q 620 751 638 773 Q 645 786 639 799 Q 633 811 602 830 Q 572 846 554 843 Q 535 839 546 817 Q 561 795 552 757 Q 513 619 407 448 Q 398 436 397 430 Q 394 418 409 423 Q 439 432 503 532 L 521 560 Z" fill="lightgray"></path>

      <path class="stroke4" d="M 503 532 Q 527 510 555 520 Q 795 608 782 549 Q 783 543 743 468 Q 736 458 741 453 Q 745 447 756 459 Q 852 532 894 549 Q 904 552 905 561 Q 906 574 876 592 Q 852 605 828 621 Q 800 637 783 630 Q 686 590 521 560 C 492 555 479 550 503 532 Z" fill="lightgray"></path>

      <path class="stroke5" d="M 568 72 Q 531 81 494 91 Q 482 94 483 86 Q 484 79 494 71 Q 569 7 596 -33 Q 611 -49 626 -36 Q 659 -3 661 82 Q 655 149 655 345 Q 656 382 667 407 Q 676 426 659 439 Q 634 461 604 470 Q 585 477 577 469 Q 571 462 582 447 Q 619 384 603 127 Q 597 82 589 74 Q 582 67 568 72 Z" fill="lightgray"></path>

      <path class="stroke6" d="M 444 320 Q 419 262 385 208 Q 364 180 381 144 Q 388 128 409 139 Q 460 181 468 264 Q 472 295 467 319 Q 463 328 456 328 Q 449 327 444 320 Z" fill="lightgray"></path>

      <path class="stroke7" d="M 738 307 Q 789 249 847 168 Q 860 146 876 139 Q 885 138 893 146 Q 908 159 900 204 Q 891 264 743 338 Q 734 345 731 332 Q 728 319 738 307 Z" fill="lightgray"></path>

      <text x="317" y="812">1</text>
      <text x="273" y="558">2</text>
      <text x="556" y="828">3</text>
      <text x="513" y="532">4</text>
      <text x="586" y="463">5</text>
      <text x="455" y="316">6</text>
      <text x="742" y="326">7</text>
  </g>
</svg>

如果不水平和垂直翻转文本,我就是想不出一种方法来让文本显示在正确的位置。我已经尝试将文本包装在另一个 g-tag 中并再次进行转换并还原它,但随后文本会消失。我还尝试将文本从原始 g-tag 中移出,但是我的坐标不再有效...

编辑:我正在寻找一种与 Safari(在 Windows 上)、Chrome 和 Firefox 兼容的方式生成 svg 的方法。

Edit2:很遗憾,我不能使用transform-box,因为我需要支持不支持它的基于 Safari 的浏览器。

【问题讨论】:

  • 您说您想“生成” SVG。这是否意味着处理 SVG 文件以更改它们是一个可行的选择?即时或一劳永逸?
  • 是的,差不多。我正在使用带有 Cheerio 的 NodeJs 来操作 SVG,然后保存它。

标签: javascript css node.js svg


【解决方案1】:

您可以在文本节点上使用 css 转换

编辑

受@enxaneta 回答的启发,您可以运行这个小脚本

const text = document.querySelectorAll("text");

text.forEach(function(el){   
  el.style.transformOrigin = el.getAttribute('x')+'px '+el.getAttribute('y')+'px';
  el.style.transform = "scale(1,-1)";     
});
text{
  dominant-baseline:central;
}
<svg version="1.1" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
  <g stroke="lightgray" stroke-dasharray="1,1" stroke-width="1" transform="scale(4, 4)">
    <line x1="0" y1="0" x2="256" y2="256"></line>
    <line x1="256" y1="0" x2="0" y2="256"></line>
    <line x1="128" y1="0" x2="128" y2="256"></line>
    <line x1="0" y1="128" x2="256" y2="128"></line>
  </g>
  <g transform="scale(1, -1) translate(0, -900)">
      <style>
        .stroke1 {fill: #BF0909;}
        .stroke2 {fill: #BFBF09;}
        .stroke3 {fill: #09BF09;}
        .stroke4 {fill: #09BFBF;}
        .stroke5 {fill: #0909BF;}
        .stroke6 {fill: #BF09BF;}
        .stroke7 {fill: #BFBFBF;}
        .stroke8 {fill: #090909;}
        text {
            font-family: Helvetica;
            font-size: 80px;
            fill: #FFFFFF;
            paint-order: stroke;
            stroke: #000000;
            stroke-width: 4px;
            stroke-linecap: butt;
            stroke-linejoin: miter;
            font-weight: 800;
        }
      </style>
      <path class="stroke1" d="M 272 567 Q 306 613 342 669 Q 370 718 395 743 Q 405 753 400 769 Q 396 782 365 808 Q 337 827 316 828 Q 297 827 305 802 Q 318 769 306 741 Q 267 647 207 560 Q 150 476 72 385 Q 60 375 58 367 Q 54 355 70 358 Q 82 359 109 384 Q 155 421 213 493 Q 226 509 241 527 L 272 567 Z" fill="#BF0909"></path>

      <path class="stroke2" d="M 241 527 Q 262 506 258 375 Q 258 374 258 370 Q 254 253 221 135 Q 215 114 224 80 Q 236 44 248 32 Q 267 16 279 44 Q 294 86 294 134 Q 303 420 314 485 Q 321 515 295 543 Q 289 549 272 567 C 251 589 227 553 241 527 Z" fill="lightgray"></path>

      <path class="stroke3" d="M 521 560 Q 561 621 602 708 Q 620 751 638 773 Q 645 786 639 799 Q 633 811 602 830 Q 572 846 554 843 Q 535 839 546 817 Q 561 795 552 757 Q 513 619 407 448 Q 398 436 397 430 Q 394 418 409 423 Q 439 432 503 532 L 521 560 Z" fill="lightgray"></path>

      <path class="stroke4" d="M 503 532 Q 527 510 555 520 Q 795 608 782 549 Q 783 543 743 468 Q 736 458 741 453 Q 745 447 756 459 Q 852 532 894 549 Q 904 552 905 561 Q 906 574 876 592 Q 852 605 828 621 Q 800 637 783 630 Q 686 590 521 560 C 492 555 479 550 503 532 Z" fill="lightgray"></path>

      <path class="stroke5" d="M 568 72 Q 531 81 494 91 Q 482 94 483 86 Q 484 79 494 71 Q 569 7 596 -33 Q 611 -49 626 -36 Q 659 -3 661 82 Q 655 149 655 345 Q 656 382 667 407 Q 676 426 659 439 Q 634 461 604 470 Q 585 477 577 469 Q 571 462 582 447 Q 619 384 603 127 Q 597 82 589 74 Q 582 67 568 72 Z" fill="lightgray"></path>

      <path class="stroke6" d="M 444 320 Q 419 262 385 208 Q 364 180 381 144 Q 388 128 409 139 Q 460 181 468 264 Q 472 295 467 319 Q 463 328 456 328 Q 449 327 444 320 Z" fill="lightgray"></path>

      <path class="stroke7" d="M 738 307 Q 789 249 847 168 Q 860 146 876 139 Q 885 138 893 146 Q 908 159 900 204 Q 891 264 743 338 Q 734 345 731 332 Q 728 319 738 307 Z" fill="lightgray"></path>

      <text x="317" y="812">1</text>
      <text x="273" y="558">2</text>
      <text x="556" y="828">3</text>
      <text x="513" y="532">4</text>
      <text x="586" y="463">5</text>
      <text x="455" y="316">6</text>
      <text x="742" y="326">7</text>
  </g>
</svg>

【讨论】:

  • 我不是反对者,但你检查过你的结果了吗?这些数字不再处于正确的位置。
  • 是的,很抱歉这个快速的回答,我已经更新了我的帖子,感谢@enxaneta 的支持
【解决方案2】:

我希望这会有所帮助:

text:nth-child(1) {
  transform: scale(1, -1);
  transform-origin: 317px 812px;/*same as text coords*/
  dominant-baseline: hanging;
}
<svg version="1.1" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
  <g stroke="lightgray" stroke-dasharray="1,1" stroke-width="1" transform="scale(4, 4)">
    <line x1="0" y1="0" x2="256" y2="256"></line>
    <line x1="256" y1="0" x2="0" y2="256"></line>
    <line x1="128" y1="0" x2="128" y2="256"></line>
    <line x1="0" y1="128" x2="256" y2="128"></line>
  </g>
  <g transform="scale(1, -1) translate(0, -900)">
      <style>
        .stroke1 {fill: #BF0909;}
        .stroke2 {fill: #BFBF09;}
        .stroke3 {fill: #09BF09;}
        .stroke4 {fill: #09BFBF;}
        .stroke5 {fill: #0909BF;}
        .stroke6 {fill: #BF09BF;}
        .stroke7 {fill: #BFBFBF;}
        .stroke8 {fill: #090909;}
        text {
            font-family: Helvetica;
            font-size: 80px;
            fill: #FFFFFF;
            paint-order: stroke;
            stroke: #000000;
            stroke-width: 4px;
            stroke-linecap: butt;
            stroke-linejoin: miter;
            font-weight: 800;
        }
      </style>
      <path class="stroke1" d="M 272 567 Q 306 613 342 669 Q 370 718 395 743 Q 405 753 400 769 Q 396 782 365 808 Q 337 827 316 828 Q 297 827 305 802 Q 318 769 306 741 Q 267 647 207 560 Q 150 476 72 385 Q 60 375 58 367 Q 54 355 70 358 Q 82 359 109 384 Q 155 421 213 493 Q 226 509 241 527 L 272 567 Z" fill="#BF0909"></path>

      <path class="stroke2" d="M 241 527 Q 262 506 258 375 Q 258 374 258 370 Q 254 253 221 135 Q 215 114 224 80 Q 236 44 248 32 Q 267 16 279 44 Q 294 86 294 134 Q 303 420 314 485 Q 321 515 295 543 Q 289 549 272 567 C 251 589 227 553 241 527 Z" fill="lightgray"></path>

      <path class="stroke3" d="M 521 560 Q 561 621 602 708 Q 620 751 638 773 Q 645 786 639 799 Q 633 811 602 830 Q 572 846 554 843 Q 535 839 546 817 Q 561 795 552 757 Q 513 619 407 448 Q 398 436 397 430 Q 394 418 409 423 Q 439 432 503 532 L 521 560 Z" fill="lightgray"></path>

      <path class="stroke4" d="M 503 532 Q 527 510 555 520 Q 795 608 782 549 Q 783 543 743 468 Q 736 458 741 453 Q 745 447 756 459 Q 852 532 894 549 Q 904 552 905 561 Q 906 574 876 592 Q 852 605 828 621 Q 800 637 783 630 Q 686 590 521 560 C 492 555 479 550 503 532 Z" fill="lightgray"></path>

      <path class="stroke5" d="M 568 72 Q 531 81 494 91 Q 482 94 483 86 Q 484 79 494 71 Q 569 7 596 -33 Q 611 -49 626 -36 Q 659 -3 661 82 Q 655 149 655 345 Q 656 382 667 407 Q 676 426 659 439 Q 634 461 604 470 Q 585 477 577 469 Q 571 462 582 447 Q 619 384 603 127 Q 597 82 589 74 Q 582 67 568 72 Z" fill="lightgray"></path>

      <path class="stroke6" d="M 444 320 Q 419 262 385 208 Q 364 180 381 144 Q 388 128 409 139 Q 460 181 468 264 Q 472 295 467 319 Q 463 328 456 328 Q 449 327 444 320 Z" fill="lightgray"></path>

      <path class="stroke7" d="M 738 307 Q 789 249 847 168 Q 860 146 876 139 Q 885 138 893 146 Q 908 159 900 204 Q 891 264 743 338 Q 734 345 731 332 Q 728 319 738 307 Z" fill="lightgray"></path>
    
    <g>
      <text x="317" y="812">1</text>
      <text x="273" y="558">2</text>
      <text x="556" y="828">3</text>
      <text x="513" y="532">4</text>
      <text x="586" y="463">5</text>
      <text x="455" y="316">6</text>
      <text x="742" y="326">7</text>
    </g>
  </g>
 
</svg>

很遗憾这适用于 Chrome 和 Firefox,但不适用于 Safari。没有检查 Edge 和 IE。

【讨论】:

    【解决方案3】:
        </path>
        </g>
    
      <g>
        <text x="317" y="812">1</text>
        <text x="273" y="500">2</text>
        <text x="556" y="828">3</text>
        <text x="513" y="532">4</text>
        <text x="586" y="463">5</text>
        <text x="455" y="316">6</text>
        <text x="742" y="326">7</text>
      </g>
    </svg>
    <script>
      var elements = document.querySelectorAll('*[y]');
      for (var i = 0; i < elements.length; i++)
        elements[i].setAttribute('y', 958-(elements[i].getAttribute('y')));
    </script>
    

    958 来自:900(初始变换)+ 58(字符高度)。

    【讨论】:

    • 我开始认为我实际上没有数字的“正确”位置(坐标),只有翻转的位置。所以也许负 y 值是正确的?
    【解决方案4】:

    操作 SVG,你需要做的就是

    • 使用transform 属性将&lt;text&gt; 元素移到组外
    • 重新计算y属性
      y -> 940 - y
      

      这假设转换属性始终为transform="scale(1, -1) translate(0, -900)",字体大小为80px。一般公式是

      y -> (negative y translation + font size / 2) - y
      

    这是一个利用cheerio更改现有文件的节点脚本:

    const cheerio = require('cheerio');
    const $ = cheerio.load(xmlText, { xmlMode: true });
    
    function flipTextInPlace ($) {
        $('text').each(() => {
           const y = $(this).attr('y');
           $(this).attr('y', 940 - y);
        }).appendTo('svg');
    }
    

    【讨论】:

    • 很遗憾,我需要支持的基于 Safari 的浏览器不支持“transform-b​​ox”属性。
    • 我已经换了一个答案。请重新考虑您的投票。
    • 谢谢。使用 fontSize/2 后效果很好。我首先赞成你的回答,我认为没有理由改变它。 ;)
    猜你喜欢
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    • 2017-02-16
    • 2022-08-14
    • 2011-08-02
    • 2022-01-05
    • 2017-06-24
    相关资源
    最近更新 更多