Skip to content

Commit 237d5e9

Browse files
committed
feat: init
0 parents  commit 237d5e9

26 files changed

+11469
-0
lines changed

.github/workflows/workflow.yml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: main
2+
on: [push]
3+
jobs:
4+
run:
5+
name: run
6+
runs-on: ${{ matrix.operating-system }}
7+
strategy:
8+
matrix:
9+
operating-system: [ubuntu-latest]
10+
steps:
11+
- uses: actions/checkout@master
12+
- name: setup-node
13+
uses: actions/setup-node@master
14+
with:
15+
node-version: 12.x
16+
- name: install
17+
run: yarn
18+
- name: format check
19+
run: yarn format --check
20+
- name: lint
21+
run: yarn lint
22+
- name: build
23+
run: yarn build -p tsconfig.prod.json
24+
- name: test
25+
run: yarn test
26+
- name: npm test
27+
run: npm test
28+
- name: commitlint
29+
uses: wagoid/commitlint-github-action@v1.2.2
30+
- name: release
31+
env:
32+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
33+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
34+
run: |
35+
if [[ "$GITHUB_REF" = "refs/heads/master" ]]; then
36+
GITHUB_TOKEN=$GH_TOKEN npx semantic-release --verbose
37+
else
38+
echo "skipping release on branch $GITHUB_REF"
39+
fi

.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
.cache
3+
dist
4+
test.bundle.js
5+
*.log
6+
bundle.test.js
7+
dist
8+
demo/**/*.js
9+
demo/**/*.jsx
10+
src/**/*.js
11+
src/**/*.jsx
12+
test/**/*.js
13+
test/**/*.jsx

.vscode/launch.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "attach",
10+
"name": "attach",
11+
"port": 9229,
12+
"skipFiles": [
13+
"<node_internals>/**"
14+
]
15+
},
16+
{
17+
"type": "node",
18+
"request": "launch",
19+
"name": "Launch Program",
20+
"skipFiles": [
21+
"<node_internals>/**"
22+
],
23+
"program": "${workspaceFolder}/src/index.html"
24+
},
25+
26+
]
27+
}

commitlint.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {extends: ['@commitlint/config-conventional']}

demo/demo.css

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
body {
2+
font-family: 'Ubuntu Mono', Arial, Helvetica, sans-serif;
3+
background: linear-gradient(darkgray, gray);
4+
height: 100vh;
5+
}
6+
7+
#demo {
8+
box-shadow: black 0 0 3px -1px;
9+
display: block;
10+
margin: 1em auto;
11+
}
12+
#controls {
13+
display: block;
14+
max-width: 600px;
15+
margin: auto;
16+
}
17+
#state {
18+
position: fixed;
19+
right: 10px;
20+
top: 10px;
21+
z-index: -1;
22+
}
23+
#state ul {
24+
list-style: none;
25+
padding-left: 0;
26+
}
27+
path {
28+
fill: none;
29+
stroke: #000;
30+
stroke-width: 1.5px;
31+
}
32+
33+
line {
34+
fill: none;
35+
stroke: red;
36+
stroke-width: 1.5px;
37+
}
38+
39+
circle {
40+
fill: red;
41+
}
42+
43+
circle:hover {
44+
fill: darkred;
45+
}
46+
47+
.snapper {
48+
fill: blue;
49+
}
50+
51+
rect {
52+
fill: none;
53+
cursor: crosshair;
54+
pointer-events: all;
55+
}

demo/demo.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import './demo.css'
2+
import { bindKeyEvents } from './util/handle-key-events'
3+
import { fromPoints } from '../src/mod'
4+
import { onStateChange } from './util/on-state-change'
5+
import { Point } from '../src/interfaces'
6+
import d3 = require('d3')
7+
8+
// prep some data
9+
const points: Point[] = [
10+
[10, 80],
11+
[100, 100],
12+
[200, 30],
13+
[300, 50],
14+
[400, 40],
15+
[500, 80]
16+
]
17+
18+
// build a svg
19+
const height = 300
20+
const width = 600
21+
const svg$ = d3
22+
.select((document.getElementById('demo') as unknown) as SVGSVGElement)
23+
.attr('width', width)
24+
.attr('height', height)
25+
26+
const {
27+
path$, // d3 path selection
28+
nodes,
29+
undo: onUndo,
30+
disableEditing,
31+
enableEditing,
32+
setNodeVisibility,
33+
snapper
34+
} = fromPoints({
35+
onStateChange: () => renderUi(),
36+
points,
37+
svg$
38+
})
39+
40+
// ^ focus on ^
41+
// below is for setting up the demo controls and outputs :)
42+
let isNodesVisibile = true
43+
const renderUi = () => {
44+
onStateChange({
45+
nodes,
46+
onShowNodes: () => {
47+
isNodesVisibile = !isNodesVisibile
48+
setNodeVisibility(isNodesVisibile)
49+
},
50+
onDisableEditing: () => {
51+
disableEditing()
52+
renderUi()
53+
},
54+
onEnableEditing: () => {
55+
enableEditing()
56+
renderUi()
57+
},
58+
snapperState: snapper.state
59+
})
60+
}
61+
renderUi()
62+
bindKeyEvents({ onUndo })

demo/index.html

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8">
3+
<body>
4+
<svg id='demo'></svg>
5+
<div id='controls' />
6+
<script src="./demo.ts"></script>
7+
</body>
8+
</html>

demo/util/handle-key-events.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { isUndo } from './undo-redo'
2+
3+
export const bindKeyEvents = ({ onUndo }: { onUndo: () => void }) => {
4+
window.onkeydown = (evt: KeyboardEvent) => {
5+
if (isUndo(evt, 'mac')) onUndo()
6+
}
7+
}

demo/util/on-state-change.tsx

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { MetaNode } from '../../src/interfaces'
2+
import * as React from 'react'
3+
import ReactDom from 'react-dom'
4+
import { SnapperState } from '../../src/snapper'
5+
6+
let isPaintingState = false
7+
8+
export type OnStateChange = {
9+
onDisableEditing: () => void
10+
onEnableEditing: () => void
11+
onShowNodes: () => void
12+
nodes: MetaNode[]
13+
snapperState: SnapperState
14+
}
15+
export const onStateChange = (opts: OnStateChange) => {
16+
if (isPaintingState) return
17+
isPaintingState = true
18+
window.requestAnimationFrame(() => {
19+
render(opts)
20+
isPaintingState = false
21+
})
22+
}
23+
24+
export const render = ({
25+
nodes,
26+
onDisableEditing,
27+
onEnableEditing,
28+
onShowNodes,
29+
snapperState
30+
}: OnStateChange) => {
31+
const toFourChars = (num: number) => {
32+
const rounded = Math.floor(num).toString()
33+
return rounded + ' '.repeat(4 - rounded.length)
34+
}
35+
ReactDom.render(
36+
<div>
37+
<h2>controls</h2>
38+
<button onClick={onShowNodes}>toggle node visibility</button>
39+
<button onClick={onDisableEditing}>disable editing</button>
40+
<button onClick={onEnableEditing}>enable editing</button>
41+
42+
<p>press cmd+z or ctrl+z to use the undo feature</p>
43+
{/* */}
44+
<div id='state'>
45+
<pre>{JSON.stringify(snapperState, null, 2)}</pre>
46+
<ul>
47+
{nodes.map((node, i) => (
48+
<li
49+
key={i}
50+
children={
51+
<pre children={node.point.map(toFourChars).join(', ')} />
52+
}
53+
/>
54+
))}
55+
</ul>
56+
</div>
57+
</div>,
58+
self.document.getElementById('controls')!
59+
)
60+
}

demo/util/undo-redo.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export type Style = 'mac' | 'windows'
2+
3+
export function check (ev: KeyboardEvent, style: Style, shift: boolean) {
4+
const macAllow = !style || style === 'mac'
5+
const winAllow = !style || style === 'windows'
6+
const code = ev.keyCode || ev.which
7+
8+
if (code !== 122 && code !== 90) return false
9+
if (macAllow && ev.metaKey && shift && !ev.ctrlKey && !ev.altKey) return true
10+
if (winAllow && ev.ctrlKey && shift && !ev.metaKey && !ev.altKey) return true
11+
return false
12+
}
13+
14+
export const isUndo = function (ev: KeyboardEvent, style: Style) {
15+
return check(ev, style, !ev.shiftKey)
16+
}
17+
18+
export const isRedo = function (ev: KeyboardEvent, style: Style) {
19+
return check(ev, style, ev.shiftKey)
20+
}

package.json

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"name": "d3-svg-path-editor",
3+
"version": "0.0.0-semantic-release",
4+
"license": "MIT",
5+
"devDependencies": {
6+
"@commitlint/cli": "^8.2.0",
7+
"@commitlint/config-conventional": "^8.2.0",
8+
"@types/blue-tape": "^0.1.33",
9+
"@types/d3": "^5.7.2",
10+
"@types/lodash": "^4.14.149",
11+
"@types/react": "^16.9.13",
12+
"@types/react-dom": "^16.9.4",
13+
"@typescript-eslint/eslint-plugin": "^2.9.0",
14+
"@typescript-eslint/parser": "^2.9.0",
15+
"blue-tape": "^1.0.0",
16+
"d3": "^5.14.1",
17+
"del-cli": "^3.0.0",
18+
"husky": "^3.1.0",
19+
"lint-staged": "^9.5.0",
20+
"parcel-bundler": "^1.12.4",
21+
"phantomjs-prebuilt": "^2.1.16",
22+
"prettier-standard": "^16.0.0",
23+
"react": "^16.12.0",
24+
"react-dom": "^16.12.0",
25+
"rollup": "^1.27.6",
26+
"rollup-plugin-typescript": "^1.0.1",
27+
"standardx": "^5.0.0",
28+
"testem": "^3.0.1",
29+
"typescript": "^3.7.2",
30+
"webpack": "^4.41.2",
31+
"webpack-cli": "^3.3.10"
32+
},
33+
"scripts": {
34+
"build": "tsc",
35+
"bundle:test": "webpack --mode=development",
36+
"clean": "del '{src,demo,test}/**/*.{js,jsx,d.ts}'",
37+
"format": "prettier-standard '{demo,src,test,scripts}/**/*.{js,jsx,ts,tsx}'",
38+
"lint": "standardx '{demo,src,test,scripts}/**/*.{js,jsx,ts,tsx}' --fix",
39+
"demo": "parcel demo/index.html",
40+
"test": "testem ci"
41+
},
42+
"husky": {
43+
"hooks": {
44+
"pre-commit": "lint-staged"
45+
}
46+
},
47+
"lint-staged": {
48+
"{src,test,scripts}/**/*.{js,jsx,ts,tsx}": [
49+
"yarn format",
50+
"yarn lint",
51+
"git add"
52+
]
53+
},
54+
"eslintConfig": {
55+
"rules": {
56+
"no-unused-vars": 0
57+
}
58+
},
59+
"standardx": {
60+
"env": [
61+
"browser"
62+
],
63+
"parser": "@typescript-eslint/parser",
64+
"plugins": [
65+
"@typescript-eslint/eslint-plugin"
66+
],
67+
"ignore": [
68+
"**/*.d.ts"
69+
]
70+
},
71+
"peerDependencies": {
72+
"d3": "*"
73+
}
74+
}

project.code-workspace

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"folders": [
3+
{
4+
"path": "."
5+
}
6+
],
7+
"settings": {
8+
"files.exclude": {
9+
"**/.git": true,
10+
"**/.svn": true,
11+
"**/.hg": true,
12+
"**/CVS": true,
13+
"**/.DS_Store": true,
14+
"**/*.js": true
15+
},
16+
"typescript.tsdk": "node_modules/typescript/lib"
17+
}
18+
}

0 commit comments

Comments
 (0)