-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(parser): initial work (in progress) * test: add dumb html file to test parser * chore: setup ts * chore: ignore dist folder * fix(dev): fix dev html docs Add additional ESM build so that dist build may be used directly in dev html docs. * docs: add a few dev docs Adding a couple documentions in the the dev folder to help keep track of notes and such. * feat(utils): add cubic bezier points resolution * feat(utils): add path to points converter (wip) * feat(bezier): enhance cubic bézier curve generation - add docs - update name of function to get points - refactor precision argument to be the number of points to return (without origin point) - use Number constructor rather than implicit type coercion (+) * fix(path-to-points): return type * fix(path-to-points): imported function name from bézier util * docs(path-to-points): add function description * fix(path-to-points): return elements * docs(parser): remove useless jsdoc * refactor(parser): do not export utils functions * feat(parser): wip * feat(types): setup basic types * chore(scripts): update - Remove "--" to forward options - Remove redundant lint scripts * chore(deps): update dependencies * fix(lint): remove prettier typescript eslint config See https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md#version-800-2021-02-21 * fix(path-to-points): do not expand points * style: arrow fn everywhere * chore: missing lockfile * style: double quotes everywhere * fix(parser): position handling of multiple elements In the main scene, and in their boundaries * feat(path): set strokeSharpness * feat(dev): output results to textarea * feat(parser): return valid Excalidraw elements Also update types and variables/functios names for consistency * feat(parser): add backgroundColor * style: run prettier * chore(scripts): apply prettier to js and ts files * feat(parser): return a valid Excalidraw file content * feat(dev): update style and behaviour * style: fix lint * fix: unused import * feat(path-to-points): on close path, make sure last committed point is first point * feat(path-to-points): if no close path and only one element, make sure to publish points * refactor(path-to-points): simplify commands regex * feat(bezier): add support for quadratic bézier curves * feat(path-to-points): add support for quadratic bézier curves * style: fix lint * ci: add workflow to cancel previous runs * feat(path-to-points): add support for simplified quadratic bézier curves * feat(path-to-points): add support for simplified cubic bézier curves * style(path-to-points): lint * feat(path-to-points): enhance commands regex * feat(path-to-points): more debugging * refactor: rename everything from coordinate(s) to point(s) - ensure consistency with excalidraw elements defining an array of points - also removes useless Coordinates type as it is no more than an array of number * refactor(path-to-points): use handling functions for each command * feat(path-parser): handling of colors * refactor: rename EVERYTHING to point(s) * create method for "walking" elements of an svg tree. Start working on implementing serialization into excalidraw json of a few basic element types. * chore: setup @excalidraw/eslint-config * style: run eslint * chore(devDeps): update dev dependencies * chore: fix eslint-plugin-prettier version range * fix(path-to-points): allow parameters omitting leading 0 (.75) Also remove duplicated non-capturing groups * feat(path): add utility to work with ellipses * feat(path-to-points): add support for arcTo commands * style: lint + todos * chore(devDeps): update dependencies - also remove useless eslint-plugin-import * chore: use @excalidraw/eslint-config * chore: remove some package fields * Create svg dom walker to support further svg elements. Add basic handling of presentation and filter attributes. Start work on handling transform attributes. * Add back main and files entries into package.json. * refactor attributes handlers. * Fix issues with use element attributes. * Fix some issues with placing circles. * Updates to circle and ellipse elements. * Refinement work on rect elements. * Add first pass at polyline and polygon element rendering. * Add back main and files to package.json. Remove unused file. * Add back a number of missing deps * Fix lint errors * Add chroma.js types, fix type error in path walker. * update yarn.lock Co-authored-by: Nicolas Goudry <goudry.nicolas@gmail.com> Co-authored-by: Nicolas <nicolas@plum-energie.com>
- Loading branch information
1 parent
cacada5
commit 025aa73
Showing
24 changed files
with
2,026 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: Cancel previous runs | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
pull_request: | ||
|
||
jobs: | ||
cancel: | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 3 | ||
steps: | ||
- uses: styfle/cancel-workflow-action@0.6.0 | ||
with: | ||
workflow_id: 6045716, 6046665 | ||
access_token: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
*.tgz | ||
logs | ||
node_modules | ||
dist | ||
npm-debug.log* | ||
package-lock.json | ||
static | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>svg-to-excalidraw</title> | ||
<style> | ||
html { | ||
height: 100%; | ||
width: 100%; | ||
font-family: Verdana, Geneva, sans-serif; | ||
} | ||
|
||
body { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: stretch; | ||
margin: 0; | ||
height: 100%; | ||
} | ||
|
||
header { | ||
text-align: center; | ||
font-size: 1.6rem; | ||
text-transform: uppercase; | ||
background-color: cornflowerblue; | ||
color: cornsilk; | ||
} | ||
|
||
header > h1 { | ||
padding: 0.5rem; | ||
} | ||
|
||
main { | ||
display: flex; | ||
flex-direction: row; | ||
height: 100%; | ||
} | ||
|
||
main > aside { | ||
display: flex; | ||
flex-direction: column; | ||
align-content: center; | ||
flex: 1; | ||
background-color: rgba(100, 149, 237, 0.3); | ||
padding: 0.8rem; | ||
} | ||
|
||
main > textarea { | ||
flex: 3; | ||
} | ||
|
||
.custom-file-upload { | ||
display: inline-block; | ||
cursor: pointer; | ||
margin: 1rem 0; | ||
border-radius: 0.2rem; | ||
background-color: #fff; | ||
border: 1px solid #333; | ||
color: #333; | ||
padding: 0.5rem; | ||
} | ||
|
||
#source { | ||
display: none; | ||
} | ||
|
||
#result { | ||
margin: 1rem; | ||
padding: 0.5rem; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<header><h1>svg-to-excalidraw</h1></header> | ||
<main> | ||
<aside> | ||
<div>File to convert :</div> | ||
<label for="source" class="custom-file-upload">Pick a SVG file</label> | ||
<input type="file" id="source" accept=".svg" /> | ||
</aside> | ||
<textarea | ||
id="result" | ||
placeholder="Result in excalidraw file format should be output here" | ||
></textarea> | ||
</main> | ||
<script type="module"> | ||
import svgParse from "../dist/esm-bundle.js"; | ||
|
||
const fileSelector = document.getElementById("source"); | ||
const output = document.getElementById("result"); | ||
|
||
output.addEventListener("click", function (event) { | ||
this.select(); | ||
}); | ||
|
||
fileSelector.addEventListener("change", (event) => { | ||
const fileList = event.target.files; | ||
readFile(fileList[0]); | ||
}); | ||
|
||
function readFile(file) { | ||
if (file.type && file.type !== "image/svg+xml") { | ||
console.log("File is not SVG."); | ||
|
||
return; | ||
} | ||
|
||
const reader = new FileReader(); | ||
|
||
reader.readAsText(file); | ||
reader.addEventListener("load", (event) => { | ||
const parsingResult = svgParse.parse(event.target.result); | ||
|
||
output.value = JSON.stringify(parsingResult, null, 2); | ||
}); | ||
} | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# TODO | ||
|
||
Note: this can probably go away once we are able to get PRs merged upstream. | ||
|
||
### Test | ||
|
||
[ ] Add Jest library | ||
|
||
### Code Quality | ||
|
||
[ ] Add Prettier |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Excalidraw Notes | ||
|
||
### Elements | ||
|
||
[Element types](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# SVG Parsing Notes | ||
|
||
[MDN SVG Element reference](https://developer.mozilla.org/en-US/docs/Web/SVG/Element) | ||
|
||
[MDN SVG Attribute reference](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import chroma from "chroma-js"; | ||
import { ExcalidrawElementBase } from "./elements/ExcalidrawElement"; | ||
|
||
export function hexWithAlpha(color: string, alpha: number): string { | ||
return chroma(color).alpha(alpha).css(); | ||
} | ||
|
||
export function has(el: Element, attr: string): boolean { | ||
return el.hasAttribute(attr); | ||
} | ||
|
||
export function get(el: Element, attr: string, backup?: string): string { | ||
return el.getAttribute(attr) || backup || ""; | ||
} | ||
|
||
export function getNum(el: Element, attr: string, backup?: number): number { | ||
const numVal = Number(get(el, attr)); | ||
return numVal === NaN ? backup || 0 : numVal; | ||
} | ||
|
||
const presAttrs = { | ||
stroke: "stroke", | ||
"stroke-opacity": "stroke-opacity", | ||
"stroke-width": "stroke-width", | ||
fill: "fill", | ||
"fill-opacity": "fill-opacity", | ||
opacity: "opacity", | ||
} as const; | ||
|
||
type ExPartialElement = Partial<ExcalidrawElementBase>; | ||
|
||
type AttrHandlerArgs = { | ||
el: Element; | ||
exVals: ExPartialElement; | ||
}; | ||
|
||
type PresAttrHandlers = { | ||
[key in keyof typeof presAttrs]: (args: AttrHandlerArgs) => void; | ||
}; | ||
|
||
const attrHandlers: PresAttrHandlers = { | ||
stroke: ({ el, exVals }) => { | ||
const strokeColor = get(el, "stroke"); | ||
|
||
exVals.strokeColor = has(el, "stroke-opacity") | ||
? hexWithAlpha(strokeColor, getNum(el, "stroke-opacity")) | ||
: strokeColor; | ||
}, | ||
|
||
"stroke-opacity": ({ el, exVals }) => { | ||
exVals.strokeColor = hexWithAlpha( | ||
get(el, "stroke", "#000000"), | ||
getNum(el, "stroke-opacity"), | ||
); | ||
}, | ||
|
||
"stroke-width": ({ el, exVals }) => { | ||
exVals.strokeWidth = getNum(el, "stroke-width"); | ||
}, | ||
|
||
fill: ({ el, exVals }) => { | ||
const fill = get(el, `fill`); | ||
|
||
exVals.backgroundColor = fill === "none" ? "#00000000" : fill; | ||
}, | ||
|
||
"fill-opacity": ({ el, exVals }) => { | ||
exVals.backgroundColor = hexWithAlpha( | ||
get(el, "fill", "#000000"), | ||
getNum(el, "fill-opacity"), | ||
); | ||
}, | ||
|
||
opacity: ({ el, exVals }) => { | ||
exVals.opacity = getNum(el, "opacity", 100); | ||
}, | ||
}; | ||
|
||
// Presentation Attributes for SVG Elements: | ||
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation | ||
export function presAttrsToElementValues( | ||
el: Element, | ||
): Partial<ExcalidrawElementBase> { | ||
const exVals = [...el.attributes].reduce((exVals, attr) => { | ||
const name = attr.name; | ||
|
||
if (Object.keys(attrHandlers).includes(name)) { | ||
attrHandlers[name as keyof PresAttrHandlers]({ el, exVals }); | ||
} | ||
|
||
return exVals; | ||
}, {} as ExPartialElement); | ||
|
||
return exVals; | ||
} | ||
|
||
type FilterAttrs = Partial< | ||
Pick<ExcalidrawElementBase, "x" | "y" | "width" | "height"> | ||
>; | ||
|
||
export function filterAttrsToElementValues(el: Element): FilterAttrs { | ||
const filterVals: FilterAttrs = {}; | ||
|
||
if (has(el, "x")) { | ||
filterVals.x = getNum(el, "x"); | ||
} | ||
|
||
if (has(el, "y")) { | ||
filterVals.y = getNum(el, "y"); | ||
} | ||
|
||
if (has(el, "width")) { | ||
filterVals.width = getNum(el, "width"); | ||
} | ||
|
||
if (has(el, "height")) { | ||
filterVals.height = getNum(el, "height"); | ||
} | ||
|
||
return filterVals; | ||
} | ||
|
||
export function pointsAttrToPoints(el: Element): number[][] { | ||
let points: number[][] = []; | ||
|
||
if (has(el, "points")) { | ||
points = get(el, "points") | ||
.split(" ") | ||
.map((p) => p.split(",").map(parseFloat)); | ||
} | ||
|
||
return points; | ||
} |
Oops, something went wrong.