简体   繁体   English

使用 icomoon 从 svg figma 图标生成字体时自动填充颜色

[英]auto colour fill when Generate Font from svg figma icon using icomoon

I want to convert an svg as an icon font element in my HTML/CSS using icomoon app我想使用icomoon 应用程序将 svg 转换为我的 HTML/CSS 中的图标字体元素

 <svg width="325" height="350" viewBox="0 0 325 350" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M205.43 59.38C205.43 26.5853 232.015 0 264.81 0C297.605 0 324.19 26.5853 324.19 59.38C324.19 92.1747 297.605 118.76 264.81 118.76C246.525 118.76 230.17 110.495 219.277 97.4975L116.536 157.274C117.985 162.41 118.76 167.83 118.76 173.43C118.76 178.348 118.162 183.127 117.035 187.697L222.002 248.758C232.806 237.522 247.991 230.53 264.81 230.53C297.605 230.53 324.19 257.115 324.19 289.91C324.19 322.705 297.605 349.29 264.81 349.29C232.015 349.29 205.43 322.705 205.43 289.91C205.43 280.791 207.486 272.152 211.159 264.431L109.497 205.292C98.9566 221.836 80.4498 232.81 59.38 232.81C26.5853 232.81 0 206.225 0 173.43C0 140.635 26.5853 114.05 59.38 114.05C79.7735 114.05 97.7659 124.331 108.457 139.992L209.556 81.1716C206.893 74.4248 205.43 67.0733 205.43 59.38ZM264.81 19C242.509 19 224.43 37.0787 224.43 59.38C224.43 81.6813 242.509 99.76 264.81 99.76C287.111 99.76 305.19 81.6813 305.19 59.38C305.19 37.0787 287.111 19 264.81 19ZM59.38 133.05C37.0787 133.05 19 151.129 19 173.43C19 195.731 37.0787 213.81 59.38 213.81C81.6813 213.81 99.76 195.731 99.76 173.43C99.76 151.129 81.6813 133.05 59.38 133.05ZM224.43 289.91C224.43 267.609 242.509 249.53 264.81 249.53C287.111 249.53 305.19 267.609 305.19 289.91C305.19 312.211 287.111 330.29 264.81 330.29C242.509 330.29 224.43 312.211 224.43 289.91Z" fill="#0D0F13"/> </svg>

But every time I generate the icon font file one of the three circles is filled black in icomoon preview and when used in HTML:但是每次我生成图标字体文件时,三个圆圈中的一个在 icomoon 预览中以及在 HTML 中使用时都会被填充为黑色

<span class="icon icon-share">

在此处输入图像描述

This rendering issue is caused by non ideal path directions .此渲染问题是由非理想路径方向引起的。

路径方向

You icon is a compound path – it contains multiple subpaths (the cut out "holes").你的图标是一个复合路径——它包含多个子路径(切出的“洞”)。

Usually, you define which shapes should be interpreted as solid or cut-out by switching path directions:通常,您可以通过切换路径方向来定义哪些形状应该被解释为实心或剪切:
Eg if the outer shape's path commands have a clockwise path direction – the inner ones should use a counter-clockwise direction.例如,如果外部形状的路径命令具有顺时针路径方向 - 内部形状应该使用逆时针方向。

It doesn't matter if you're using clockwise vs. counter-clockwise or the other way around.无论您是使用顺时针还是逆时针或其他方式都没有关系。 Inner (cut out) paths just have to use the opposite direction.内部(切出)路径只需要使用相反的方向。
Also explained in this article: The Winding Order of the Fill Rule 本文还解释了:填充规则的缠绕顺序

Svg: fill-rule="evenodd SVG:填充规则=“偶数”

The original svg file renders fine since it has a fill-rule="evenodd" applied to the path element.原始 svg 文件渲染得很好,因为它有一个fill-rule="evenodd"应用于路径元素。

Apparently, icomoon font generator expects your icons to have the aforementioned alternating directions.显然,icomoon 字体生成器希望您的图标具有上述交替方向。
In other words it can't use fill-rules when converting svg to font files.换句话说,在将 svg 转换为字体文件时,它不能使用填充规则。

Fix path directions修正路径方向

Here is a helper script to fix inner paths.这是一个修复内部路径的帮助脚本。

 const svg = document.querySelector('svg'); const path = svg.querySelector('path'); function fixPath(path) { // get pathData array let pathData = path.getPathData({ normalize: true }); // split sub paths let pathDataSubArr = splitSubpaths(pathData); let fixedPathData = fixInnerPathDirections(path, pathDataSubArr); path.setPathData(fixedPathData); } /** * helpers */ function fixInnerPathDirections(path, pathDataSubArr) { let svg = path.closest('svg'); let fixedPathData = []; let subPathEls = []; let bbO = path.getBBox(); let [xO, yO, wO, hO, rO, bO] = [bbO.x, bbO.y, bbO.width, bbO.height, (bbO.x + bbO.width), (bbO.y + bbO .height)]; let outerPathData = pathDataSubArr[0]; let outerPathTmp = document.createElementNS('http://www.w3.org/2000/svg', 'path'); outerPathTmp.setPathData(outerPathData); outerPathTmp.classList.add('outer'); let outerClockwise = isClockwise(outerPathTmp) pathDataSubArr.forEach(function(pathDataSub, i) { // create temporary subpath elements for checking positions let subPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); subPath.setPathData(pathDataSub); subPath.setAttribute('stroke', 'red'); subPath.setAttribute('stroke-width', '1'); subPath.setAttribute('fill', 'none'); svg.appendChild(subPath); subPathEls.push(subPath); let bb = subPath.getBBox(); let [x, y, w, h, r, b] = [bb.x, bb.y, bb.width, bb.height, (bb.x + bb.width), (bb.y + bb .height)]; // remove temporary subpaths subPath.remove(); if (i > 0) { // is subpath within outer path if (x > xO && y > yO && r < rO && b < bO) { let isClockwiseInner = isClockwise(subPath); // if subpath has same direction as outer path: reverse direction if (isClockwiseInner == outerClockwise) { pathDataSub = reversePathData(pathDataSub); } } } fixedPathData = fixedPathData.concat(pathDataSub); }) return fixedPathData; } function reversePathData(pathData) { let M = pathData[0]; let newPathData = [M]; // split subpaths let subPathDataArr = splitSubpaths(pathData); subPathDataArr.forEach(function(subPathData, s) { let subPathDataL = subPathData.length; let closed = subPathData[subPathDataL - 1]['type'] == 'Z' ? true : false; let subM = subPathData[0]['values']; // insert Lineto if last path segment has created by z let lastCom = closed ? subPathData[subPathDataL - 2] : subPathData[subPathDataL - 1]; let lastComL = lastCom['values'].length; let lastXY = [lastCom['values'][lastComL - 2], lastCom['values'][lastComL - 1]]; let diff = Math.abs(subM[0] - lastXY[0]); if (diff > 1 && closed) { subPathData.pop(); subPathData.push({ 'type': 'L', 'values': [subM[0], subM[1]] }); subPathData.push({ 'type': 'Z', 'values': [] }); } subPathData.forEach(function(com, i) { // reverse index let subpathDataL = subPathData.length; let indexR = subpathDataL - 1 - i; let comR = subPathData[indexR]; let comF = subPathData[i]; let [typeR, valuesR] = [comR['type'], comR['values']]; let [typeF, valuesF] = [comF['type'], comF['values']]; if (typeF == 'M' && s > 0) { newPathData.push(comF); } else if (typeR != 'M' && typeR != 'Z') { indexR--; let prevCom = i > 0 ? subPathData[indexR] : subPathData[subpathDataL - 1 - i]; let prevVals = prevCom ? (prevCom['values'] ? prevCom['values'] : [0, 0]) : []; prevVals = prevCom['values']; let prevValsL = prevVals.length; let newCoords = []; if (typeR == 'C') { newCoords = [ valuesR[2], valuesR[3], valuesR[0], valuesR[1], prevVals[prevValsL - 2], prevVals[prevValsL - 1] ]; if (!closed) { let nextVals = i < subpathDataL - 1 ? subPathData[i + 1]['values'] : lastXY; let lastCX = (i < subpathDataL - 2) ? nextVals[prevValsL - 2] : subM[0]; let lastCY = (i < subpathDataL - 2) ? nextVals[prevValsL - 1] : subM[1]; newCoords[4] = lastCX; newCoords[5] = lastCY; } } else { newCoords = [prevVals[prevValsL - 2], prevVals[prevValsL - 1]]; } newPathData.push({ 'type': typeR, 'values': newCoords }); } }) //use last coordinates as M values if path isn't closed if (!closed) { newPathData[0]['values'] = lastXY; } if (closed) { newPathData.push({ 'type': 'Z', 'values': [] }); } }); return newPathData; } /** * check path direction of polygon * based on answer: * @mpen: https://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order/1180256#answer-46613578 */ function isClockwise(path, divisions = 50) { var length = path.getTotalLength(); let p1 = path.getPointAtLength(0); let A = [p1.x, p1.y]; let p2 = path.getPointAtLength(length * 0.25); let B = [p2.x, p2.y]; let p3 = path.getPointAtLength(length * 0.75); let C = [p3.x, p3.y]; let poly = [A, B, C]; let end = poly.length - 1; let sum = poly[end][0] * poly[0][1] - poly[0][0] * poly[end][1]; for (let i = 0; i < end; ++i) { const n = i + 1; sum += poly[i][0] * poly[n][1] - poly[n][0] * poly[i][1]; } let cw = sum > 0 ? true : false; return cw; } function splitSubpaths(pathData) { let pathDataL = pathData.length; let subPathArr = []; let subPathMindex = []; pathData.forEach(function(com, i) { let [type, values] = [com['type'], com['values']]; if (type == 'M') { subPathMindex.push(i); } }); //split segments after M command subPathMindex.forEach(function(index, i) { let n = subPathMindex[i + 1]; let thisSeg = pathData.slice(index, n); subPathArr.push(thisSeg) }) return subPathArr; }
 <script src="https://cdn.jsdelivr.net/npm/path-data-polyfill@1.0.3/path-data-polyfill.min.js"></script> <p><button type="button" onclick="fixPath(path)">Fix path directions</button></p> <svg width="325" height="350" viewBox="0 0 325 350" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d=" M205.43 59.38C205.43 26.5853 232.015 0 264.81 0C297.605 0 324.19 26.5853 324.19 59.38C324.19 92.1747 297.605 118.76 264.81 118.76C246.525 118.76 230.17 110.495 219.277 97.4975L116.536 157.274C117.985 162.41 118.76 167.83 118.76 173.43C118.76 178.348 118.162 183.127 117.035 187.697L222.002 248.758C232.806 237.522 247.991 230.53 264.81 230.53C297.605 230.53 324.19 257.115 324.19 289.91C324.19 322.705 297.605 349.29 264.81 349.29C232.015 349.29 205.43 322.705 205.43 289.91C205.43 280.791 207.486 272.152 211.159 264.431L109.497 205.292C98.9566 221.836 80.4498 232.81 59.38 232.81C26.5853 232.81 0 206.225 0 173.43C0 140.635 26.5853 114.05 59.38 114.05C79.7735 114.05 97.7659 124.331 108.457 139.992L209.556 81.1716C206.893 74.4248 205.43 67.0733 205.43 59.38Z M264.81 19C242.509 19 224.43 37.0787 224.43 59.38C224.43 81.6813 242.509 99.76 264.81 99.76C287.111 99.76 305.19 81.6813 305.19 59.38C305.19 37.0787 287.111 19 264.81 19Z M59.38 133.05C37.0787 133.05 19 151.129 19 173.43C19 195.731 37.0787 213.81 59.38 213.81C81.6813 213.81 99.76 195.731 99.76 173.43C99.76 151.129 81.6813 133.05 59.38 133.05Z M224.43 289.91C224.43 267.609 242.509 249.53 264.81 249.53C287.111 249.53 305.19 267.609 305.19 289.91C305.19 312.211 287.111 330.29 264.81 330.29C242.509 330.29 224.43 312.211 224.43 289.91Z " fill="#0D0F13" /> </svg>

(Inspect the element in your dev tools to get the new path) (检查开发工具中的元素以获取新路径)

How it works这个怎么运作

  1. path commands are parsed (using path-data-polyfill by Jarek Foksa )解析路径命令(使用Jarek Foksa 的 path-data-polyfill
    1.2 the path data is retrieved in a normalized way ( path.getPathData({normalize: true} ): 1.2 以规范化的方式检索路径数据( path.getPathData({normalize: true} ):
    all commands will be converted to a reduced set using only absolute M , L , C , Z commands.仅使用绝对MLCZ命令将所有命令转换为缩减集。
  2. split up path data into sub paths (each sub path starts with a new M command)将路径数据拆分为子路径(每个子路径以新的M命令开始)
  3. check if sub paths are intersecting with the outer shape检查子路径是否与外部形状相交
  4. check directions between outer and inner sub paths (using the isClockwise(path) helper)检查外部和内部子路径之间的方向(使用isClockwise(path)帮助器)
  5. reverse sub path direction if needed ( reversePathData(pathdata) )如果需要,反向子路径方向( reversePathData(pathdata)
  6. concatenate sub paths and overwrite the original d property连接子路径并覆盖原始d属性

Codepen example代码笔示例

You might also use this codepen helper: Fix svg compound path direction您也可以使用这个codepen 助手:修复 svg 复合路径方向
(still pretty buggy, I'm working on it ...) (仍然很麻烦,我正在努力...)

HTML/CSS example HTML/CSS 示例

 @font-face { font-family: 'icomoon'; src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAKsAA0AAAAABpgAAAJWAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0ZGVE0cGh4GYACCXhEICoIwgicLDgABNgIkAxgEIAWDGwdFG5gFyJ4FdpMzjFBuZhHDYhE2Lyuvefjx8LVWvt89OwuoLkDsUKWigS2BIwnAKmwRyqeiD1z8VXT0WrS2WSR7w9M/YpFmHip+uESqS2jQkv/fzbMtejpWgbRBCusLh5mNJZxQLwq8+J+4Gbcs0ayoyySyNm4KAw7HxADTzsMwkLHPpyWQZQUKD0Zv7Xy3GOQpg6RIkmGRRZTNaBEChl5xBP7+oo23DrQwAJIQKkKBhJyGYq1CepJu3KLi+GdF1DGd6Klcj0blY/2GbQYFAcSpCPnkiQjsIBSYSGQ1aKhJkjB1VP8HxD9n+u8YsSw0AIRMlEQGIiEBAIICrg7RJwElaKGKPeAyoAAEQihyzqva7VbQSyfP/JuzIacHG9Ph+enDBacfK4dHbovJUxU8A6u/WJQ7Xqm9+nF6qDkbiclwo2VkBgb1ANjxPsxY2H3AZ4bRsplS0Zw5z18lt1pWnMqpZVxycbNKnuXD1oYHbk6mZGvfmfmdMLq4AgJQAH3+SAIPQNz+esn3KSVZ/Z/wwqyM0of8OfegJoEw3uUoQP4sfyGUBSC2AvhN/opAaTcRSAAA6HgjQKjqIZBUzUUgq1qPQKFqBwIVTacQKFXdF6BhvJcsirrQIQIJGQtkZClQIBuxigFprNRxvmfDSncH5TTVNTU14OCqn9JsAJswRX01GR14mZYGrQlL5G2Yjq6yW8/JxgFnVkarTN86GzQ19OgVMQ1MR0YPk6eXNaYXISRh2uCeHNrBzTrX/NNhDoTEti+JJEWWoyj3Hxm3Sk58/FjZQZy3Ai5jAAAA') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } .icon{ font-family: 'icomoon'; font-size:5vw } .icon-share:before { content: "\e900"; }
 <span class="icon icon-share">

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM