Search code examples
paperjs

Logic in if else statement to divide path if path shape is two or more '0'


Hi all trying to write some logic in paper.js (also using opentype.js for font data) so that when a number contains two or more consecutive zeros' the zero path is divided so that it is solid.

Things i know a zero path, using my particular font, is made up of an outer path with 19 segments and an inner path made up of 18 segments

So I thought would try to iterate over all paths check if a path has 19 segments and the next path has 18 segments and call path.unite() which kind of works. But I only want it to do this with consecutive '0' eg '100', '1000' but not 10.

So i was trying to do an if else statment where if-else (the current path has 18 segments and the next path is less than 18 segments) if true then do nothin or call path.divide()?

Im sure there is a way better way of doing this. Can you help please.

link to codepen

paper.install(window);
window.onload = () => {
  paper.setup("canvas");
  opentype.load(
    "https://assets.codepen.io/1070/pphatton-ultralight-webfont.woff",
    (err, font) => {
      if (err) {
        console.log(err);
      } else {
        const fontPath = font.getPath("10k", 0, 100, 100).toSVG();
        const count = new paper.CompoundPath(fontPath);
        count.unite();
        count.children.forEach((child, i) => {
           if (
            child.segments.length === 19 &&
            count.children[i + 1].segments.length === 18
          ) {
            const eye = child.unite();
            eye.selected = true;
          } else if(
            count.children[i + 1].segments.length === 18
            && child.segments.length < 18
          ) {
            console.log('hello');
            // const target = child.divide();
            count.children[i].fillColor = 'black'
          } else{
            
          }
        });
        // const flatCount = count.children[1].unite()

        // console.log(count.children[2].segments.length)
        // const flatCountTwo = count.children[5].unite()
        // flatCount.translate(5,0)
        count.fillColor = "red";

        project.activeLayer.fitBounds(view.bounds.scale(0.6));
      }
    }
  );
};

enter image description here


Solution

  • I think that rather than using Font.getPath to retrieve a single svg path for the whole text, you should use Font.getPaths to retrieve an svg path for each character.
    This way you can quite simply do your analysis on the input string directly and handle the consecutive 0 differently than other characters.


    Edit

    In order to detect the consecutive zeros, yes, you could use a regex or loop over the characters, like I did in the following example.
    Here's a fiddle showcasing a possible solution.

    const handleZero = (path) => {
        path.children = path.children.slice(0, 1);
    };
    
    const getConsecutiveZerosIndices = (content) => {
        const zero = '0';
        return [...content]
            .map((char, i) => ({ char, i }))
            .filter(({ char, i }) => {
                const previousCharacter = content?.[i - 1];
                const nextCharacter = content?.[i + 1];
                return char === zero && (previousCharacter === zero || nextCharacter === zero);
            })
            .map(({ i }) => i);
    };
    
    const drawText = (content, font) => {
        const fontPaths = font.getPaths(content, 0, 100, 100);
        const consecutiveZerosIndices = getConsecutiveZerosIndices(content);
        const paths = fontPaths.map((fontPath, i) => {
            const path = new paper.CompoundPath(fontPath.toSVG());
            if (consecutiveZerosIndices.includes(i)) {
                handleZero(path);
            }
            return path;
        });
        const group = new paper.Group(paths);
        group.fillColor = 'red';
        return group;
    };
    
    const draw = (font) => {
        const path1 = drawText('10k', font);
        const path2 = drawText('100k', font);
        const path3 = drawText('1000k', font);
    
        path2.position = path1.position.add(0, path1.bounds.height * 1.2);
        path3.position = path2.position.add(0, path2.bounds.height * 1.2);
    
        paper.project.activeLayer.fitBounds(paper.view.bounds.scale(0.6));
    };
    
    paper.setup('canvas');
    opentype.load(
        'https://assets.codepen.io/1070/pphatton-ultralight-webfont.woff',
        (err, font) => draw(font)
    );