From ca91bb9a38232b3ea355aeff905223290539d5c2 Mon Sep 17 00:00:00 2001 From: Z3 Development Date: Sun, 23 Jan 2022 15:43:14 +0900 Subject: [PATCH] feat(svg-serializer): enhanced to serialize id and class attributes to SVG * fix(svg-serializer): correctd to svg values for fill, fill-rulle, stroke-width adjusted fill for (geom2) continous paths * docs(svg-serializer): added information about initial colors to README * tests(svg-serializer): adjusted test suites due to changes into serialization * feat(svg-serializer): enhanced to serialize id and class attributes to SVG, adjusted tests and docs * docs(all): added svg-serializer to documentation * docs(svg-serializer): improved documentation --- jsdoc.json | 1 + packages/io/svg-serializer/README.md | 6 ++- packages/io/svg-serializer/index.js | 54 +++++++++++-------- .../io/svg-serializer/tests/geom2.test.js | 24 +++++---- .../io/svg-serializer/tests/path2.test.js | 10 ++-- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/jsdoc.json b/jsdoc.json index 8184f38a8..37cc67029 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -37,6 +37,7 @@ "packages/io/amf-deserializer/src", "packages/io/amf-serializer", "packages/io/svg-deserializer/src", + "packages/io/svg-serializer", "packages/io/x3d-deserializer/src" ], "includePattern": ".+\\.js(doc|x)?$", diff --git a/packages/io/svg-serializer/README.md b/packages/io/svg-serializer/README.md index 6271c3357..c09c8225c 100644 --- a/packages/io/svg-serializer/README.md +++ b/packages/io/svg-serializer/README.md @@ -23,8 +23,10 @@ This serializer outputs a 'blobable' array of data from one or more JSCAD geomet The array of data can either be used to create a Blob (`new Blob(blobable)`), or converted to a Node.js buffer. The serialization of the following geometries are possible. -- serialization of 2D geometry (geom2) to continous SVG paths -- serialization of 2D paths (path2) to individual SVG paths +- serialization of 2D geometry (geom2) to continous SVG paths, where the color (initial fill) is 'black' if not provided +- serialization of 2D paths (path2) to individual SVG paths, where the color (initial stroke) is 'none' if not provided + +In addition, geometries can have special attributes (id, class) which will be passed on to the SVG paths. ## Table of Contents diff --git a/packages/io/svg-serializer/index.js b/packages/io/svg-serializer/index.js index 461db7e0d..32e2d5ffc 100644 --- a/packages/io/svg-serializer/index.js +++ b/packages/io/svg-serializer/index.js @@ -9,7 +9,7 @@ All code released under MIT license Notes: 1) geom2 conversion to: - SVG GROUP containing a SVG PATH for each outline of the geometry + SVG GROUP containing a continous SVG PATH that contains the outlines of the geometry 2) geom3 conversion to: none 3) path2 conversion to: @@ -17,7 +17,15 @@ Notes: */ /** - * Serializer of JSCAD geometries to SVG elements. + * Serializer of JSCAD geometries to SVG source (XML). + * + * The serialization of the following geometries are possible. + * - serialization of 2D geometry (geom2) to SVG path (a continous path containing the outlines of the geometry) + * - serialization of 2D geometry (path2) to SVG path + * + * Colors are added to SVG shapes when found on the geometry. + * Special attributes (id and class) are added to SVG shapes when found on the geometry. + * * @module io/svg-serializer * @example * const { serializer, mimeType } = require('@jscad/svg-serializer') @@ -32,12 +40,13 @@ const version = require('./package.json').version const mimeType = 'image/svg+xml' /** - * Serialize the give objects to SVG format. + * Serialize the give objects to SVG code (XML). + * @see https://www.w3.org/TR/SVG/Overview.html * @param {Object} options - options for serialization, REQUIRED * @param {String} [options.unit='mm'] - unit of design; em, ex, px, in, cm, mm, pt, pc * @param {Function} [options.statusCallback] - call back function for progress ({ progress: 0-100 }) * @param {Object|Array} objects - objects to serialize as SVG - * @returns {Array} serialized contents with one SVG structure (string) + * @returns {Array} serialized contents, SVG code (XML string) * @alias module:io/svg-serializer.serialize * @example * const geometry = primitives.square() @@ -77,6 +86,9 @@ const serialize = (options, ...objects) => { width: width + options.unit, height: height + options.unit, viewBox: ('0 0 ' + width + ' ' + height), + fill: "none", + 'fill-rule': "evenodd", + 'stroke-width': "0.1px", version: '1.1', baseProfile: 'tiny', xmlns: 'http://www.w3.org/2000/svg', @@ -143,32 +155,32 @@ const reflect = (x, y, px, py) => { const convertGeom2 = (object, offsets, options) => { const outlines = geometries.geom2.toOutlines(object) const paths = outlines.map((outline) => geometries.path2.fromPoints({ closed: true }, outline)) - if (object.color) { - paths.forEach((path) => { - path.fill = object.color - }) - } + + options.color = "black" // SVG initial color + if (object.color) options.color = convertColor(object.color) + options.id = null + if (object.id) options.id = object.id + options.class = null + if (object.class) options.class = object.class + return convertToContinousPath(paths, offsets, options) } const convertToContinousPath = (paths, offsets, options) => { let instructions = '' paths.forEach((path) => (instructions += convertPath(path, offsets, options))) - let continouspath = ['path', { d: instructions }] - if (paths.length > 0) { - const path0 = paths[0] - if (path0.fill) { - continouspath = ['path', { 'fill-rule': 'evenodd', fill: convertColor(path0.fill), d: instructions }] - } - } - return ['g', continouspath] + const d = { fill: options.color, d: instructions } + if (options.id) d.id = options.id + if (options.class) d.class = options.class + return ['g', ['path', d]] } const convertPaths = (paths, offsets, options) => paths.reduce((res, path, i) => { - if (path.color) { - return res.concat([['path', { stroke: convertColor(path.color), 'stroke-width': 1, d: convertPath(path, offsets, options) }]]) - } - return res.concat([['path', { d: convertPath(path, offsets, options) }]]) + d = { d: convertPath(path, offsets, options) } + if (path.color) d.stroke = convertColor(path.color) + if (path.id) d.id = path.id + if (path.class) d.class = path.class + return res.concat([['path', d]]) }, ['g']) const convertPath = (path, offsets, options) => { diff --git a/packages/io/svg-serializer/tests/geom2.test.js b/packages/io/svg-serializer/tests/geom2.test.js index fac229f79..a4f8e7603 100644 --- a/packages/io/svg-serializer/tests/geom2.test.js +++ b/packages/io/svg-serializer/tests/geom2.test.js @@ -25,6 +25,8 @@ test('serialize 2D geometries (simple) to svg', (t) => { test('serialize 2D geometries (color) to svg', (t) => { let cag2 = primitives.rectangle({ size: [10, 20] }) cag2 = colors.colorize([0.5, 0.5, 0.5, 0.5], cag2) + cag2.id = 'r2' + cag2.class = 'gray-rect' const observed2 = serializer.serialize({}, cag2) t.deepEqual([expected4], observed2) @@ -62,9 +64,9 @@ test('serialize 2D geometries (complex) to svg', (t) => { const expected1 = ` - + - + ` @@ -72,9 +74,9 @@ const expected1 = ` const expected2 = ` - + - + ` @@ -82,12 +84,12 @@ const expected2 = ` const expected3 = ` - + - + - + ` @@ -95,9 +97,9 @@ const expected3 = ` const expected4 = ` - + - + ` @@ -105,9 +107,9 @@ const expected4 = ` const expected5 = ` - + - + ` diff --git a/packages/io/svg-serializer/tests/path2.test.js b/packages/io/svg-serializer/tests/path2.test.js index 336f6644e..794a63ea5 100644 --- a/packages/io/svg-serializer/tests/path2.test.js +++ b/packages/io/svg-serializer/tests/path2.test.js @@ -26,6 +26,8 @@ test('serialize 2D path (color) objects to svg', (t) => { // simple open path let object1 = primitives.line([[0, 0], [1, 1], [-3, 3]]) object1 = colors.colorize([0.5, 0.5, 0.5, 0.5], object1) + object1.id = 'l1' + object1.class = 'gray-line' const observed = serializer.serialize({}, object1) t.deepEqual(observed, [expected4]) }) @@ -37,7 +39,7 @@ test('serialize 2D path (color) objects to svg', (t) => { const expected1 = ` - + @@ -47,7 +49,7 @@ const expected1 = ` const expected3 = ` - + @@ -57,9 +59,9 @@ const expected3 = ` const expected4 = ` - + - + `