An implementation of Material Design Shape for the web extending Svg.js and Svg.filter.js
SVG Button and Rectangle with CutOut
npm install material-shapes-svg
Creates a rectangle with cut corners.
svgjs.Doc.chamferRect(
width:
number,
height:
number,
chamferAllLength:
number,
)
:
svgjs.MDSChamferRect
svgjs.Doc.chamferRect(
width:
number,
height:
number,
chamferTopLeftLength:
number,
chamferTopRightLength:
number,
chamferBottomRightLength:
number,
chamferBottomLeftLength:
number
)
:
svgjs.MDSChamferRect
Change the chamfer length later after the ChamferRect has been created using the chamfer method
svgjs.MDSChamferRect.chamfer(
width:
number,
height:
number,
chamferAllLength:
number,
)
:
svgjs.MDSChamferRect
svgjs.MDSChamferRect.chamfer(
width:
number,
height:
number,
chamferTopLeftLength:
number,
chamferTopRightLength:
number,
chamferBottomRightLength:
number,
chamferBottomLeftLength:
number
)
:
svgjs.MDSChamferRect
svgjs.MDSChamferRect
extends svgjs.Path
<!-- HTML -->
<div class="example-chamfer"></div>
/* CSS: for size example */
.example-chamfer {
width: 160px;
height: 40px;
}
import * as svgjs from 'svg.js';
import 'material-shapes-svg';
// Find example div
const div: HTMLElement = document.querySelector('div.example-chamfer');
const width: number = div.offsetWidth;
const height: number = div.offsetHeight;
const chamferLength: number = 8;
// Create container
const container: svgjs.Doc = svgjs(div).size(width, height);
// Draw the chamfer rectangle
container.chamferRect(width, height, chamferLength);
Creates a Material Elevation based on the shape.
svgjs.Shape.elevation(
z:
svgjs.zDepth
)
:
svgjs.Filter
svgjs.Filter.elevate(
z:
svgjs.zDepth
)
:
svgjs.Filter
<!-- HTML -->
<div class="example-diamond"></div>
/* CSS: Make sure shadows dont get clipped */
.example-diamond .mds-svg {
overflow: visible;
}
.example-diamond {
width: 64px;
height: 64px;
}
import * as svgjs from 'svg.js';
import 'svg.filter.js';
import 'material-shapes-svg';
// find example div
const div: HTMLElement = document.querySelector('div.example-diamond');
const width = element.offsetWidth;
const height = element.offsetHeight;
const container: svgjs.Doc = svgjs(element).size(width, height).addClass('mds-svg');
// Diamond Shape
const diamond: svgjs.Path = container.path(`
M${width*0.5} 0
L${width} ${height*0.5}
L${width*0.5} ${height}
L0 ${height*0.5}
Z
`).fill('#fff');
const elevation: svgjs.Filter = diamond.elevation(8);
Creates a Material Pressed State aka ripple
svgjs.Shape.ripple(
contrast?:
svgjs.MDSContrast
)
:
svgjs.MDSRipple
svgjs.MDSRipple.expand(
x:
number,
y:
number
)
:
svgjs.MDSRipple
svgjs.MDSRipple.reset()
:
svgjs.MDSRipple
If you need to update the extents of the ripple use updateMinMax, such as parent container resized.
svgjs.MDSRipple.updateMinMax(
width:
number,
height:
number
)
:
svgjs.MDSRipple
svgjs.MDSRipple.contrast
: svgjs.MDSContrast ( 'light'
| 'dark'
)
svgjs.MDSRipple
extends svgjs.Circle
<!-- HTML -->
<div class="example-ripple">
<div class="mds-background"></div>
<div class="example-text">Click me</div>
<div class="mds-ripple"></div>
</div>
/* CSS */
.example-ripple {
width: 160px;
height: 36px;
position: relative;
}
.example-ripple .mds-background,
.example-ripple .mds-wash,
.example-ripple .mds-ripple {
position: absolute;
overflow: visible;
top: 0;
left: 0;
}
.example-ripple .example-text {
line-height: 36px;
height: 36px;
color: #222;
position: relative;
text-align: center;
}
import * as svgjs from 'svg.js';
import 'material-shapes-svg';
// Find example div
const div: HTMLElement = document.querySelector('div.example-diamond');
const width = div.offsetWidth;
const height = div.offsetHeight;
// Find background div
const backgroundElement: HTMLElement = <HTMLElement>div.getElementsByClassName('mds-background')[0];
// Find ripple div
const rippleElement: HTMLElement = <HTMLElement>div.getElementsByClassName('mds-ripple')[0];
// Create containers
const backgroundContainer: svgjs.Doc = svgjs(backgroundElement).size(width, height).addClass('mds-svg');
const rippleContainer: svgjs.Doc = svgjs(rippleElement).size(width, height).addClass('mds-svg');
// Draw a shape that can show off mask effect
const chamferRect: svgjs.MDSChamferRect = backgroundContainer.chamferRect(width, height, 10)
.fill('#ccc');
// You need a separate copy of shape for ripple
const rippleRect: svgjs.MDSChamferRect = rippleContainer.chamferRect(width, height, 10)
.fill('#000');
// Add ripple shape
const ripple: svgjs.MDSRipple = rippleRect.ripple('dark');
// Add interactions for demo
div.onmousedown = (event: MouseEvent) => {
ripple.expand(event.offsetX, event.offsetY);
}
div.onmouseup = () => {
ripple.reset();
}
Creates cut outs for rectangles. Such as Material App Bottom Bar. See the Inset FAB under the anatomy section.
svgjs.Shape.circleCutOut(
width:
number,
height:
number,
cutOutSize:
number,
alignX:
svgjs.CutOutAlignX,
alignY:
svgjs.CutOutAlignY,
padding:
number,
roundedEdge:
number,
showCutOut:
boolean
)
:
svgjs.MDSRectCutOut
svgjs.Shape.triangleCutOut(
width:
number,
height:
number,
cutOutSize:
number,
alignX:
svgjs.CutOutAlignX,
alignY:
svgjs.CutOutAlignY,
padding:
number,
showCutOut:
boolean
)
:
svgjs.MDSRectCutOut
svgjs.Shape.customCutOut(
width:
number, // Width of rect
height:
number, // Height of rect
cutOutSize:
number, // Size of cutout
customCutOutOpen:
string, // Relative svg.path data
customCutOutClosed:
string, // Relative svg.path data
alignX:
svgjs.CutOutAlignX,
alignY:
svgjs.CutOutAlignY,
padding:
number,
showCutOut:
boolean
)
:
svgjs.MDSRectCutOut
svgjs.MDSRectCutOut.showCutOut(
alignX:
svgjs.CutOutAlignX
)
:
svgjs.MDSRectCutOut
svgjs.MDSRectCutOut.hideCutOut()
:
svgjs.MDSRectCutOut
If you need to update the extents of the Rect use resize, such as parent container resized.
svgjs.MDSRectCutOut.resize(
width:
number,
height:
number
)
:
svgjs.MDSRectCutOut
svgjs.MDSRectCutOut.CutOutAlignX
: svgjs.CutOutAlignX ( 'start'
| 'center'
| 'end'
)
svgjs.MDSRectCutOut.CutOutAlignY
: svgjs.CutOutAlignX ( 'top'
| 'bottom'
)
svgjs.MDSRectCutOut
extends svgjs.Path
<!-- HTML -->
<div class="example-rect-cutout"></div>
/* CSS: for size example */
.example-rect-cutout {
width: 100%;
height: 56px;
}
import * as svgjs from 'svg.js';
import 'material-shapes-svg';
// Find example div
const div: HTMLElement = document.querySelector('div.example-rect-cutout');
const width: number = div.offsetWidth;
const height: number = div.offsetHeight;
const padding: number = 16;
const roundedEdge: number = 4;
const fabDiameter: number = 56 + 16; // fab plus cutout padding
const cutOutAlignX = 'end';
const cutOutAlignY = 'top';
const showCutOut = true;
// Create container
const container: svgjs.Doc = svgjs(div).size(width, height);
// Draw the rectangle with circular cutout
const rectCutOut: svgjs.MDSRectCutOut = container.circleCutOut(
width,
height,
fabDiameter,
cutOutAlignX,
cutOutAlignY,
padding,
roundedEdge,
showCutOut
);
For custom shapes use relative path data
const cutOutSize = 80;
const radius = `28 28`
const concave = `0 0 0`
const openCutOut = `
a ${radius} ${concave} 14 21
a ${radius} ${concave} 52 0
a ${radius} ${concave} 14 -21
l 0 0`;
const closedCutOut = `
a 23 0 ${concave} 0 0
a 24 0 ${concave} 0 0
a 23 0 ${concave} 0 0
l 0 0`;
const rectCutOut: svgjs.MDSRectCutOut = container.customCutOut(
width,
height,
cutOutSize,
openCutOut,
closedCutOut,
cutOutAlignX,
cutOutAlignY,
padding,
showCutOut
)
Custom Chamfer Shapes
supply a shape to cutout of chamfered corners
Rect CutOut
refactor circle and triangle to use similar method to custom.
Demo Site
more examples