Skip to content

Instantly share code, notes, and snippets.

@Hansanghyeon
Last active December 26, 2023 17:54
Show Gist options
  • Save Hansanghyeon/a295bd02ab1054fa00412c358759c109 to your computer and use it in GitHub Desktop.
Save Hansanghyeon/a295bd02ab1054fa00412c358759c109 to your computer and use it in GitHub Desktop.
simple-flow
import { pipe } from 'fp-ts/function'
// jquery `.position()` 컨버팅
function position(elm: HTMLElement): { top: number; left: number } {
return {
top: elm.offsetTop,
left: elm.offsetLeft,
}
}
// jquery `.outerHeight()` 컨버팅
function outerHeight(elm: HTMLElement): number {
const height = elm.offsetHeight
return height
}
// jquery `.outerWidth()` 컨버팅
function outerWidth(elm: HTMLElement): number {
const width = elm.offsetWidth
return width
}
// 더하기
function add(a: number) {
return (b: number) => b + a
}
// 나누기
function divide(a: number) {
return (b: number) => b / a
}
// 빼기
function subtract(a: number) {
return (b: number) => b - a
}
type PluginOptions = {
lineWidth: number
lineSpacerWidth: number
lineColour: string
}
type HTMLElementOrElement = HTMLElement | Element
export class SimpleFlow {
private canvasElm: HTMLElementOrElement
private settings: PluginOptions
private static readonly defaults: PluginOptions = {
lineWidth: 2,
lineSpacerWidth: 15,
lineColour: '#91acb3',
}
constructor(
canvasElm: HTMLElementOrElement,
options?: Partial<PluginOptions>,
) {
this.canvasElm = canvasElm
this.settings = { ...SimpleFlow.defaults, ...options }
this.init()
}
private init(): void {
this.drawLines()
window.addEventListener('resize', this.drawLines.bind(this))
}
private drawLines(): void {
// Logic for drawing lines
// Replace jQuery methods with vanilla JavaScript
}
private drawMarker(): SVGDefsElement {
// string to element
const marker = `
<marker
id="up"
viewBox="0 0 10 10"
refX="5"
refY="5"
markerWidth="6"
markerHeight="6"
orient="-90deg">
<path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor" />
</marker>
<marker
id="right"
viewBox="0 0 10 10"
refX="5"
refY="5"
markerWidth="6"
markerHeight="6"
orient="0deg">
<path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor" />
</marker>
<marker
id="down"
viewBox="0 0 10 10"
refX="5"
refY="5"
markerWidth="6"
markerHeight="6"
orient="90deg">
<path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor" />
</marker>
<marker
id="left"
viewBox="0 0 10 10"
refX="5"
refY="5"
markerWidth="6"
markerHeight="6"
orient="180deg">
<path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor" />
</marker>
`
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')
defs.innerHTML = marker
return defs
}
private drawLine(
thisElm: HTMLElementOrElement,
nextElm: HTMLElementOrElement,
): SVGPathElement {
const thisElmParent = thisElm.parentElement
const nextElmParent = nextElm.parentElement
const thisElmMiddle = pipe(thisElm, outerHeight)
// const nextElmMiddle = pipe(nextElm, outerHeight)
const thisParentPadding =
pipe(thisElmParent, outerHeight) - pipe(thisElm, outerHeight)
const thisElmY =
thisElmMiddle + pipe(thisElmParent, position).top - thisParentPadding
const nextElmY = pipe(nextElmParent, position).top
const thisMiddle = pipe(
pipe(thisElm, position).left,
add(pipe(thisElm, outerWidth, divide(2))),
)
const nextMiddle = pipe(
pipe(nextElm, position).left,
add(pipe(nextElm, outerWidth, divide(2))),
)
const farLeftX = nextMiddle
const farRightX = thisMiddle
const lineInBetweenY = pipe(
nextElmY,
subtract(pipe(thisParentPadding, divide(2))),
)
// TODO:
// X축이같고 Y축이 다를 때 점은 2개이다.
// X축과 Y축 모두 다를때 점은 4개이다.
const coords = `${thisMiddle}, ${thisElmY} ${farRightX}, ${thisElmY} ${farRightX}, ${lineInBetweenY} ${farLeftX}, ${lineInBetweenY} ${farLeftX}, ${nextElmY} ${nextMiddle}, ${nextElmY}`
// path string을 elment로 변환
// `<path d="M ${coords} "style="fill:none;stroke: currentColor; stroke-width: ${this.settings['lineWidth']}; stroke-linecap: round; marker-end:url(#arrowhead);" stroke-dasharray="4" />`
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
path.setAttribute('d', `M ${coords} `)
path.setAttribute(
'style',
`fill:none;stroke: currentColor; stroke-width: ${this.settings['lineWidth']}; stroke-linecap: round; marker-end:url(#right);`,
)
path.setAttribute('stroke-dasharray', '4')
return path
}
public draw(targets: [HTMLElementOrElement, HTMLElementOrElement][]): void {
// clean
const oldSvg = this.canvasElm.querySelector('svg')
if (oldSvg) {
oldSvg.remove()
}
const defs = this.drawMarker()
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute(
'class',
'simple-flow-line absolute top-0 left-0 w-full h-full pointer-events-none',
)
svg.setAttribute('width', '100%')
svg.setAttribute('height', '100%')
svg.appendChild(defs)
targets.forEach(([thisElm, nextElm]) => {
const path = this.drawLine(thisElm, nextElm)
svg.appendChild(path)
})
this.canvasElm.appendChild(svg)
}
}
// Usage example:
// const canvas = document.querySelector('.canvas')
// const target1 = document.querySelector('.target1')
// const target2 = document.querySelectorAll('.target2')
// const simpleFlow = new SimpleFlow(canvas, { lineWidth: 3 })
// simpleFlow.draw([[target1, target2[1]]])
@Hansanghyeon
Copy link
Author

https://github.com/tdsymonds/simple-flow

simple-flow를 컨버팅

  • jquery없이
  • typescript로 만들기

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment