Skip to content

Commit

Permalink
refactor(renderers): refactor of renderers and more
Browse files Browse the repository at this point in the history
Rename graphics to renderer, embed base64 encoded font in the handdrawn chord diagram, implement
ability to add arbitrary defs to the handdrawn svg diagram, add the correct namespaces and other
attributes to the handdrawn svg, add remove method to the renderer interface to remove the complete
svg from the dom, adapt demo to allow changing the diagram style
  • Loading branch information
omnibrain committed Nov 17, 2019
1 parent 8c7e653 commit ea3f19b
Show file tree
Hide file tree
Showing 11 changed files with 304 additions and 90 deletions.
10 changes: 9 additions & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ <h2>Chord</h2>
<h2>Configuration</h2>

<form id="chart-config-form">
<div class="form-group">
<label for="chart-style">Style</label>
<select name="style" class="form-control" id="chart-style">
<option value="normal" selected="selected">normal</option>
<option value="handdrawn">handdrawn</option>
</select>
</div>
<div class="form-group">
<label for="chart-title">Title</label>
<input name="title" type="text" class="form-control" id="chart-title" placeholder="Enter chart title">
Expand Down Expand Up @@ -102,7 +109,8 @@ <h2>Result</h2>
frets: 4,
position: 9,
nutSize: 0.65,
strokeWidth: 2
strokeWidth: 2,
style: 'normal',
}

var initialChord = {
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@
"lint-staged": "^9.2.5",
"lodash.camelcase": "^4.3.0",
"npm-run-all-v2": "^1.0.0",
"prettier": "^1.14.3",
"prettier": "^1.19.1",
"prompt": "^1.0.0",
"replace-in-file": "^4.1.3",
"rimraf": "^3.0.0",
"rollup": "^1.21.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-html": "^0.2.1",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.4.2",
Expand All @@ -118,10 +119,10 @@
"ts-jest": "^24.1.0",
"ts-node": "^8.3.0",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^9.0.0",
"typedoc": "^0.15.0",
"typescript": "^3.0.3"
"typedoc": "^0.15.2",
"typescript": "^3.7.2"
},
"dependencies": {
"@svgdotjs/svg.js": "^3.0.13",
Expand Down
5 changes: 5 additions & 0 deletions rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import sourceMaps from 'rollup-plugin-sourcemaps'
import camelCase from 'lodash.camelcase'
import typescript from 'rollup-plugin-typescript2'
import json from 'rollup-plugin-json'
import html from 'rollup-plugin-html';

const pkg = require('./package.json')

Expand All @@ -23,6 +24,10 @@ export default {
plugins: [
// Allow json resolution
json(),
// Allow importing HTML
html({
include: '**/*.html'
}),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { RoughJsRenderer } from './roughjs/roughjs-renderer'
export { SvgJsRenderer } from './svgjs/svg-js-renderer'
export { Renderer, Alignment, GraphcisElement } from './renderer'
5 changes: 3 additions & 2 deletions src/graphics.ts → src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface GraphcisElement {
remove: () => void
}

export abstract class Graphics {
export abstract class Renderer {
constructor(protected container: QuerySelector | HTMLElement) {}

abstract line(
Expand All @@ -30,6 +30,8 @@ export abstract class Graphics {

abstract clear(): void

abstract remove(): void

abstract text(
text: string,
x: number,
Expand All @@ -48,7 +50,6 @@ export abstract class Graphics {
strokeColor: string,
fill?: string
): GraphcisElement

abstract rect(
x: number,
y: number,
Expand Down
14 changes: 14 additions & 0 deletions src/renderer/roughjs/defs.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ that there is no SVG implementation for JSDOM. If that changes at some point thi
tested just like the svg.js implementation
*/

import { Alignment, GraphcisElement, Graphics } from './graphics'
import { Box, QuerySelector } from '@svgdotjs/svg.js'
import { Alignment, GraphcisElement, Renderer } from '../renderer'
import { QuerySelector } from '@svgdotjs/svg.js'
import { RoughSVG } from 'roughjs/bin/svg'
import rough from 'roughjs'
import { Options } from 'roughjs/src/core'
import defs from './defs'

export class RoughJsGraphics extends Graphics {
/**
* Currently the font is hard-coded to 'Patrick Hand' when using the handdrawn chord diagram style.
* The reason is that the font needs to be base64 encoded and embedded in the SVG. In theory a web-font
* could be downloaded, base64 encoded and embedded in the SVG but that's too much of a hassle. But if the
* need arises it should be possible.
*/
const FONT_FAMLILY = 'Patrick Hand'

export class RoughJsRenderer extends Renderer {
private rc: RoughSVG
private containerNode: HTMLElement
private svgNode: SVGSVGElement
Expand All @@ -20,7 +29,7 @@ export class RoughJsGraphics extends Graphics {
super(container)

// initialize the container
if (container instanceof Element) {
if (container instanceof HTMLElement) {
this.containerNode = container
} else {
this.containerNode = (container as unknown) as HTMLElement
Expand All @@ -35,15 +44,61 @@ export class RoughJsGraphics extends Graphics {

// create an empty SVG element
this.svgNode = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
this.svgNode.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
this.svgNode.setAttribute('version', '1.1')
this.svgNode.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink')
this.svgNode.setAttribute('xmlns:svgjs', 'http://svgjs.com/svgjs')

this.svgNode.setAttribute('preserveAspectRatio', 'xMidYMid meet')
this.svgNode.setAttribute('viewBox', '0 0 400 402')
this.svgNode.setAttribute('viewBox', '0 0 400 400')

this.embedDefs()

this.containerNode.appendChild(this.svgNode)

this.rc = rough.svg(this.svgNode)
}

/**
* This will embed all defs defined in the defs.html file. Specifically this is used to embed the base64
* encoded font into the SVG so that the font always looks correct.
*/
private embedDefs() {
/*
Embed the base64 encoded font. This is done in a timeout because roughjs also creates defs which will simply overwrite existing defs.
By putting this in a timeout we make sure that the style tag is added after roughjs finished rendering.
ATTENTION: This will only work as long as we're synchronously rendering the diagram! If we ever switch to asynchronous rendering a different
solution must be found.
*/
setTimeout(() => {
// check if defs were already added
if (this.svgNode.querySelector('defs [data-svguitar-def]')) {
return
}

let currentDefs = this.svgNode.querySelector('defs')

if (!currentDefs) {
currentDefs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')
this.svgNode.prepend(currentDefs)
}

// create dom nodes from HTML string
const template = document.createElement('template')
template.innerHTML = defs.trim()

// typescript is complaining when I access content.firstChild.children, therefore this ugly workaround.
const defsToAdd = template.content.firstChild?.firstChild?.parentElement?.children

if (defsToAdd) {
Array.from(defsToAdd).forEach(def => {
def.setAttribute('data-svguitar-def', 'true')
currentDefs?.appendChild(def)
})
}
})
}

circle(
x: number,
y: number,
Expand Down Expand Up @@ -76,6 +131,11 @@ export class RoughJsGraphics extends Graphics {
}

this.rc = rough.svg(this.svgNode)
this.embedDefs()
}

remove(): void {
this.svgNode.remove()
}

line(x1: number, y1: number, x2: number, y2: number, strokeWidth: number, color: string): void {
Expand Down Expand Up @@ -147,8 +207,9 @@ export class RoughJsGraphics extends Graphics {
txtElem.setAttributeNS(null, 'x', String(x))
txtElem.setAttributeNS(null, 'y', String(y))
txtElem.setAttributeNS(null, 'font-size', String(fontSize))
txtElem.setAttributeNS(null, 'font-family', fontFamily)
txtElem.setAttributeNS(null, 'font-family', FONT_FAMLILY)
txtElem.setAttributeNS(null, 'align', alignment)
txtElem.setAttributeNS(null, 'fill', color)

txtElem.appendChild(document.createTextNode(text))

Expand Down Expand Up @@ -188,16 +249,6 @@ export class RoughJsGraphics extends Graphics {
}
}

private svgJsBoxToElement(box: Box, remove: () => void): GraphcisElement {
return {
width: box.width,
height: box.height,
x: box.x,
y: box.y,
remove
}
}

private roundedRectData(
w: number,
h: number,
Expand Down
12 changes: 8 additions & 4 deletions src/svgjs-graphics.ts → src/renderer/svgjs/svg-js-renderer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Alignment, GraphcisElement, Graphics } from './graphics'
import { Alignment, GraphcisElement, Renderer } from '../renderer'
import { Box, Container, QuerySelector, SVG } from '@svgdotjs/svg.js'
import { constants } from './constants'
import { isNode } from './utils'
import { constants } from '../../constants'
import { isNode } from '../../utils'

export class SvgJsGraphics extends Graphics {
export class SvgJsRenderer extends Renderer {
private svg: Container

constructor(container: QuerySelector | HTMLElement) {
Expand Down Expand Up @@ -44,6 +44,10 @@ export class SvgJsGraphics extends Graphics {
}
}

remove(): void {
this.svg.remove()
}

text(
text: string,
x: number,
Expand Down
Loading

0 comments on commit ea3f19b

Please sign in to comment.