Skip to content
/ pathfit Public

Transform CSS path() values to responsively fit a container

License

Notifications You must be signed in to change notification settings

ccprog/pathfit

Repository files navigation

Jasmine test spec

The CSS path() function does not accept units in its path string, because it is following the SVG path syntax. This makes it impossible to make it responsive with CSS alone. This script module helps by providing on-the-fly capabilities to re-compute the path data applying arbitrary SVG transformations.

The path data can be defined in relation to a view box. Then, if a target size is provided, the transformed path data will fit into that viewport the same way as if the path was part of an SVG with a viewBox defined on its root element. Either a SVG-style preserveAspectRatio attribute or CSS-style object-fit and object-position style properties can be used to position the view box in relation to the target viewport.

Usage

In a webpage

Include the script:

<script src="path/to/pathfit.js"></script>
<!-- or minified -->
<script src="path/to/pathfit.min.js"></script>

SVG-style sizing

Suppose your path source data are from a SVG, which either is a part of your DOM, or a standalone file. Read the path and size information you need:

// 
const svg = svgDocumentFragment.querySelector('svg');

const pathElement = svg.querySelector(`path#${id}`);
const path = pathElement.getAttribute('d');

Get all the relevant attributes from the root <svg> element. The module will figure out itself which of these it should use to define a base view box.

const base = {};
for (let key of ['width', 'height', 'viewBox', 'preserveAspectRatio']) {
    base.key = svg.getAttribute(key);
}

CSS-style sizing

Suppose you want to size your path data in relation to an <img> element. While you still need to give a base view box (i. e. at least base.width and base.height), the sizing algorithm might be governed by the object-fit and object-position CSS properties of the <img>. Read the properties from the element, and just pass the complete CSSStyleDeclaration, the module will pick out the values for the two properties:

const style = getComputedStyle(document.querySelector('img#img-id'));

In a node.js environment

Require the module.

const Pathfit = require('pathfit');

You have to provide path and size information directly

const path = 'M10.362 18.996s-6.046 21.453 1.47 25.329c10.158 5.238 18.033-21.308 29.039-18.23 13.125 3.672 18.325 36.55 18.325 36.55l12.031-47.544';

const base = {
    viewBox: '0 0 80 80',
    preserveAspectRatio: 'xMidYMid meet' // the default
};
// or for CSS sizing, note the camelCase for style properties
const style = {
    objectFit: 'fill', // the defaults
    objectPosition: '50% 50%'
}

Basic scaling

Scale the path to fit a container and then set the style property on the appropriate target element.

SVG-style sizing

const pathfitter = new Pathfit(base, undefined, path);

const scaled_path = pathfitter.scale_with_aspect_ratio(container.offsetWidth, container.offsetHeight);

container.style.offsetPath = `path('${scaled_path}')`;

CSS-style sizing

const pathfitter = new Pathfit(base, style, path);

const scaled_path = pathfitter.scale_with_object_fit(container.offsetWidth, container.offsetHeight);

container.style.clipPath = `path('${scaled_path}')`;

API

new Pathfit(base, style, path, pretransform, opt)

  • optional object base see .set_viewbox(base)

  • optional object {objectFit = 'fill', objectPosition = '50% 50%'} following the syntax of the CSS properties object-fit and object-position.

    In contrast to the method .set_object_style(style), if one of the properties or the parameter as a whole is missing, its value is set to the default.

  • optional string path see .set_path(path, pretransform)

  • optional string | Array<strings> pretransform see .set_path(path, pretransform). pretransform is ignored if path is not set.

  • optional object opt = { precision = 6 } sets the number of significant digits in the returned path data

All constructor arguments are optional.

.set_viewbox(base)

  • object base = {width, height, viewBox, preserveAspectRatio = 'xMidYMid meet'}

    • optional number | string width, height Strings can be followed by 'px'. Every other unit will raise an error.

    • optional string viewBox following the syntax of the SVG attribute

    • optional string preserveAspectRatio following the syntax of the SVG attribute

Sets or computes a view box used for a later transformation with .scale_with_aspect_ratio(width, height) or .scale_with_object_fit(width, height). If viewBox is not provided, width and height will be used instead. preserveAspectRatio is completely optional. An error will be raised if no size can be figured out.

.set_aspect_ratio(preserveAspectRatio)

  • string preserveAspectRatio following the syntax of the SVG attribute

Sets the method of fit for a later transformation with .scale_with_aspect_ratio(). This will raise an error if base was not previously set (although base.preserveAspectRatio could have been ommitted).

.set_object_style(style)

  • object {objectFit, objectPosition} following the syntax of the CSS properties object-fit and object-position.

    In contrast to the constructor, if one of the properties is missing, its value remains unchanged.

Sets the method of fit for a later transformation with .scale_with_object_fit(). This will raise an error if base was not previously set (although style could have been ommitted).

.set_path(path, pretransform)

  • string path following the syntax for path data in the SVG path d attribute or in the CSS path() function

  • optional string | Array<strings> pretransform containing one or more transform functions. Only the SVG syntax for transforms is supported. CSS syntax (i. e. with units and relying on a transform-origin) will fail.

  • returns string the path, optionally pretransformed, in the form that will be used as source for later transformations.

Sets the path for later use with .scale_to() or .transform(). An optional pretransformation can be applied to the path data. This might be especially useful if the path data were provided from a SVG where the path userspace coordinates were not identical to the root viewBox viewport.

Collect all transform attributes in descending tree order down to and including the <path> element and pass that array:

const transforms = [];

let ancestor = pathElement;
while (svg.contains(ancestor)) {
    const attr = ancestor.getAttribute('transform');

    if (attr && attr.length) transforms.unshift(attr);

    ancestor = ancestor.parentElement;
}

pathfitter.set_path(path, transforms);

.transform(trans)

  • string | Array<string> trans containing one or more transform functions. Only the SVG syntax for transforms is supported. CSS syntax (i. e. with units and relying on a transform-origin) will fail.

  • returns string the transformed path.

Transforms the presupplied path with any combination of affine transforms as supplied.

.scale_with_aspect_ratio(width, height)

  • number | string width, height Strings can be followed by 'px'. Every other unit will raise an error.

  • returns string the transformed path.

Transforms the presupplied path such that its computed view box will fit the given dimensions and the preserveAspectRatio rule is fullfilled. This will raise an error if base was not previously set (although base.preserveAspectRatio could have been ommitted).

.scale_with_object_fit(width, height)

  • number | string width, height Strings can be followed by 'px'. Every other unit will raise an error.

  • returns string the transformed path.

Transforms the presupplied path such that its computed view box will fit the dimensions of the objectFit rule and it is positioned according to the objectPosition rule. This will raise an error if base was not previously set (although style could have been ommitted).

About

Transform CSS path() values to responsively fit a container

Resources

License

Stars

Watchers

Forks

Packages

No packages published