mirror of
https://github.com/slidevjs/rough-notation.git
synced 2026-01-30 00:37:49 +01:00
chore: apply eslint
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
demo
|
|
||||||
src
|
|
||||||
tsconfig.json
|
|
||||||
tslint.json
|
|
||||||
.gitignore
|
|
||||||
43
.vscode/settings.json
vendored
Normal file
43
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
// Enable the ESlint flat config support
|
||||||
|
"eslint.experimental.useFlatConfig": true,
|
||||||
|
|
||||||
|
// Disable the default formatter, use eslint instead
|
||||||
|
"prettier.enable": false,
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
|
||||||
|
// Auto fix
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit",
|
||||||
|
"source.organizeImports": "never"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||||
|
"eslint.rules.customizations": [
|
||||||
|
{ "rule": "style/*", "severity": "off" },
|
||||||
|
{ "rule": "format/*", "severity": "off" },
|
||||||
|
{ "rule": "*-indent", "severity": "off" },
|
||||||
|
{ "rule": "*-spacing", "severity": "off" },
|
||||||
|
{ "rule": "*-spaces", "severity": "off" },
|
||||||
|
{ "rule": "*-order", "severity": "off" },
|
||||||
|
{ "rule": "*-dangle", "severity": "off" },
|
||||||
|
{ "rule": "*-newline", "severity": "off" },
|
||||||
|
{ "rule": "*quotes", "severity": "off" },
|
||||||
|
{ "rule": "*semi", "severity": "off" }
|
||||||
|
],
|
||||||
|
|
||||||
|
// Enable eslint for all supported languages
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact",
|
||||||
|
"vue",
|
||||||
|
"html",
|
||||||
|
"markdown",
|
||||||
|
"json",
|
||||||
|
"jsonc",
|
||||||
|
"yaml",
|
||||||
|
"toml"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -6,6 +6,6 @@ export default defineBuildConfig({
|
|||||||
],
|
],
|
||||||
declaration: true,
|
declaration: true,
|
||||||
rollup: {
|
rollup: {
|
||||||
emitCJS: true
|
emitCJS: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
5
eslint.config.js
Normal file
5
eslint.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import antfu from '@antfu/eslint-config'
|
||||||
|
|
||||||
|
export default antfu({
|
||||||
|
|
||||||
|
})
|
||||||
35
package.json
35
package.json
@@ -1,41 +1,42 @@
|
|||||||
{
|
{
|
||||||
"name": "@slidev/rough-notation",
|
"name": "@slidev/rough-notation",
|
||||||
"version": "0.0.1",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"version": "0.0.1",
|
||||||
"description": "Create and animate hand-drawn annotations on a web page",
|
"description": "Create and animate hand-drawn annotations on a web page",
|
||||||
"main": "dist/index.mjs",
|
"author": "Preet Shihn",
|
||||||
"module": "dist/index.cjs",
|
"license": "MIT",
|
||||||
"types": "dist/index.d.mts",
|
"homepage": "https://github.com/slidevjs/rough-notation#readme",
|
||||||
"scripts": {
|
|
||||||
"build": "unbuild",
|
|
||||||
"prepack": "npm run build",
|
|
||||||
"release": "bumpp && pnpm publish",
|
|
||||||
"lint": "tslint -p tsconfig.json"
|
|
||||||
},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/slidev/rough-notation.git"
|
"url": "git+https://github.com/slidevjs/rough-notation.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/slidevjs/rough-notation/issues"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"annotate",
|
"annotate",
|
||||||
"rough",
|
"rough",
|
||||||
"sketchy"
|
"sketchy"
|
||||||
],
|
],
|
||||||
|
"main": "dist/index.mjs",
|
||||||
|
"module": "dist/index.cjs",
|
||||||
|
"types": "dist/index.d.mts",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"author": "Preet Shihn",
|
"scripts": {
|
||||||
"license": "MIT",
|
"build": "unbuild",
|
||||||
"bugs": {
|
"prepack": "npm run build",
|
||||||
"url": "https://github.com/pshihn/rough-notation/issues"
|
"release": "bumpp && pnpm publish",
|
||||||
|
"lint": "eslint ."
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/pshihn/rough-notation#readme",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"roughjs": "^4.6.6"
|
"roughjs": "^4.6.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config": "^2.6.4",
|
||||||
"bumpp": "^9.3.0",
|
"bumpp": "^9.3.0",
|
||||||
"tslint": "^6.1.3",
|
"eslint": "^8.56.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"unbuild": "^2.0.0"
|
"unbuild": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
1809
pnpm-lock.yaml
generated
1809
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
import resolve from 'rollup-plugin-node-resolve';
|
import resolve from 'rollup-plugin-node-resolve'
|
||||||
import { terser } from "rollup-plugin-terser";
|
import { terser } from 'rollup-plugin-terser'
|
||||||
|
|
||||||
const input = 'lib/rough-notation.js';
|
const input = 'lib/rough-notation.js'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
@@ -9,24 +9,24 @@ export default [
|
|||||||
output: {
|
output: {
|
||||||
file: 'lib/rough-notation.iife.js',
|
file: 'lib/rough-notation.iife.js',
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
name: 'RoughNotation'
|
name: 'RoughNotation',
|
||||||
},
|
},
|
||||||
plugins: [resolve(), terser()]
|
plugins: [resolve(), terser()],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input,
|
input,
|
||||||
output: {
|
output: {
|
||||||
file: 'lib/rough-notation.esm.js',
|
file: 'lib/rough-notation.esm.js',
|
||||||
format: 'esm'
|
format: 'esm',
|
||||||
},
|
},
|
||||||
plugins: [resolve(), terser()]
|
plugins: [resolve(), terser()],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input,
|
input,
|
||||||
output: {
|
output: {
|
||||||
file: 'lib/rough-notation.cjs.js',
|
file: 'lib/rough-notation.cjs.js',
|
||||||
format: 'cjs'
|
format: 'cjs',
|
||||||
},
|
},
|
||||||
plugins: [resolve(), terser()]
|
plugins: [resolve(), terser()],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export const SVG_NS = 'http://www.w3.org/2000/svg';
|
export const SVG_NS = 'http://www.w3.org/2000/svg'
|
||||||
|
|
||||||
export const DEFAULT_ANIMATION_DURATION = 800;
|
|
||||||
|
|
||||||
|
export const DEFAULT_ANIMATION_DURATION = 800
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export function ensureKeyframes() {
|
export function ensureKeyframes() {
|
||||||
if (!(window as any).__rno_kf_s) {
|
if (!(window as any).__rno_kf_s) {
|
||||||
const style = (window as any).__rno_kf_s = document.createElement('style');
|
const style = (window as any).__rno_kf_s = document.createElement('style')
|
||||||
style.textContent = `@keyframes rough-notation-dash { to { stroke-dashoffset: 0; } }`;
|
style.textContent = `@keyframes rough-notation-dash { to { stroke-dashoffset: 0; } }`
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
299
src/render.ts
299
src/render.ts
@@ -1,22 +1,21 @@
|
|||||||
|
import type { OpSet, ResolvedOptions } from 'roughjs/bin/core'
|
||||||
|
import { ellipse, line, linearPath, rectangle } from 'roughjs/bin/renderer'
|
||||||
|
import { RoughGenerator } from 'roughjs/bin/generator'
|
||||||
|
import type { Point } from 'roughjs/bin/geometry'
|
||||||
|
import type { BracketType, FullPadding, Rect, RoughAnnotationConfig } from './types'
|
||||||
import { SVG_NS } from './constants'
|
import { SVG_NS } from './constants'
|
||||||
import { Rect, RoughAnnotationConfig, FullPadding, BracketType } from "./types";
|
|
||||||
import { ResolvedOptions, OpSet } from 'roughjs/bin/core';
|
|
||||||
import { line, rectangle, ellipse, linearPath } from 'roughjs/bin/renderer';
|
|
||||||
import { RoughGenerator } from 'roughjs/bin/generator';
|
|
||||||
import { Point } from 'roughjs/bin/geometry';
|
|
||||||
|
|
||||||
type RoughOptionsType = 'highlight' | 'single' | 'double';
|
type RoughOptionsType = 'highlight' | 'single' | 'double'
|
||||||
|
|
||||||
let defaultOptions: ResolvedOptions | null = null;
|
let defaultOptions: ResolvedOptions | null = null
|
||||||
function getDefaultOptions(): ResolvedOptions {
|
function getDefaultOptions(): ResolvedOptions {
|
||||||
if (!defaultOptions) {
|
if (!defaultOptions) {
|
||||||
const gen = new RoughGenerator();
|
const gen = new RoughGenerator()
|
||||||
defaultOptions = gen.defaultOptions;
|
defaultOptions = gen.defaultOptions
|
||||||
}
|
}
|
||||||
return defaultOptions;
|
return defaultOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getOptions(type: RoughOptionsType, seed: number): ResolvedOptions {
|
function getOptions(type: RoughOptionsType, seed: number): ResolvedOptions {
|
||||||
return {
|
return {
|
||||||
...getDefaultOptions(),
|
...getDefaultOptions(),
|
||||||
@@ -38,241 +37,235 @@ function getOptions(type: RoughOptionsType, seed: number): ResolvedOptions {
|
|||||||
// combineNestedSvgPaths: false,
|
// combineNestedSvgPaths: false,
|
||||||
disableMultiStroke: type !== 'double',
|
disableMultiStroke: type !== 'double',
|
||||||
disableMultiStrokeFill: false,
|
disableMultiStrokeFill: false,
|
||||||
seed
|
seed,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePadding(config: RoughAnnotationConfig): FullPadding {
|
function parsePadding(config: RoughAnnotationConfig): FullPadding {
|
||||||
const p = config.padding;
|
const p = config.padding
|
||||||
if (p || (p === 0)) {
|
if (p || (p === 0)) {
|
||||||
if (typeof p === 'number') {
|
if (typeof p === 'number') {
|
||||||
return [p, p, p, p];
|
return [p, p, p, p]
|
||||||
} else if (Array.isArray(p)) {
|
}
|
||||||
const pa = p as number[];
|
else if (Array.isArray(p)) {
|
||||||
|
const pa = p as number[]
|
||||||
if (pa.length) {
|
if (pa.length) {
|
||||||
switch (pa.length) {
|
switch (pa.length) {
|
||||||
case 4:
|
case 4:
|
||||||
return [...pa] as FullPadding;
|
return [...pa] as FullPadding
|
||||||
case 1:
|
case 1:
|
||||||
return [pa[0], pa[0], pa[0], pa[0]];
|
return [pa[0], pa[0], pa[0], pa[0]]
|
||||||
case 2:
|
case 2:
|
||||||
return [...pa, ...pa] as FullPadding;
|
return [...pa, ...pa] as FullPadding
|
||||||
case 3:
|
case 3:
|
||||||
return [...pa, pa[1]] as FullPadding;
|
return [...pa, pa[1]] as FullPadding
|
||||||
default:
|
default:
|
||||||
return [pa[0], pa[1], pa[2], pa[3]];
|
return [pa[0], pa[1], pa[2], pa[3]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [5, 5, 5, 5];
|
return [5, 5, 5, 5]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderAnnotation(svg: SVGSVGElement, rect: Rect, config: RoughAnnotationConfig, animationGroupDelay: number, animationDuration: number, seed: number) {
|
export function renderAnnotation(svg: SVGSVGElement, rect: Rect, config: RoughAnnotationConfig, animationGroupDelay: number, animationDuration: number, seed: number) {
|
||||||
const opList: OpSet[] = [];
|
const opList: OpSet[] = []
|
||||||
let strokeWidth = config.strokeWidth || 2;
|
let strokeWidth = config.strokeWidth || 2
|
||||||
const padding = parsePadding(config);
|
const padding = parsePadding(config)
|
||||||
const animate = (config.animate === undefined) ? true : (!!config.animate);
|
const animate = (config.animate === undefined) ? true : (!!config.animate)
|
||||||
const iterations = config.iterations || 2;
|
const iterations = config.iterations || 2
|
||||||
const rtl = config.rtl ? 1 : 0;
|
const rtl = config.rtl ? 1 : 0
|
||||||
const o = getOptions('single', seed);
|
const o = getOptions('single', seed)
|
||||||
|
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case 'underline': {
|
case 'underline': {
|
||||||
const y = rect.y + rect.h + padding[2];
|
const y = rect.y + rect.h + padding[2]
|
||||||
for (let i = rtl; i < iterations + rtl; i++) {
|
for (let i = rtl; i < iterations + rtl; i++) {
|
||||||
if (i % 2) {
|
if (i % 2)
|
||||||
opList.push(line(rect.x + rect.w, y, rect.x, y, o));
|
opList.push(line(rect.x + rect.w, y, rect.x, y, o))
|
||||||
} else {
|
else
|
||||||
opList.push(line(rect.x, y, rect.x + rect.w, y, o));
|
opList.push(line(rect.x, y, rect.x + rect.w, y, o))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'strike-through': {
|
case 'strike-through': {
|
||||||
const y = rect.y + (rect.h / 2);
|
const y = rect.y + (rect.h / 2)
|
||||||
for (let i = rtl; i < iterations + rtl; i++) {
|
for (let i = rtl; i < iterations + rtl; i++) {
|
||||||
if (i % 2) {
|
if (i % 2)
|
||||||
opList.push(line(rect.x + rect.w, y, rect.x, y, o));
|
opList.push(line(rect.x + rect.w, y, rect.x, y, o))
|
||||||
} else {
|
else
|
||||||
opList.push(line(rect.x, y, rect.x + rect.w, y, o));
|
opList.push(line(rect.x, y, rect.x + rect.w, y, o))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'box': {
|
case 'box': {
|
||||||
const x = rect.x - padding[3];
|
const x = rect.x - padding[3]
|
||||||
const y = rect.y - padding[0];
|
const y = rect.y - padding[0]
|
||||||
const width = rect.w + (padding[1] + padding[3]);
|
const width = rect.w + (padding[1] + padding[3])
|
||||||
const height = rect.h + (padding[0] + padding[2]);
|
const height = rect.h + (padding[0] + padding[2])
|
||||||
for (let i = 0; i < iterations; i++) {
|
for (let i = 0; i < iterations; i++)
|
||||||
opList.push(rectangle(x, y, width, height, o));
|
opList.push(rectangle(x, y, width, height, o))
|
||||||
}
|
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'bracket': {
|
case 'bracket': {
|
||||||
const brackets: BracketType[] = Array.isArray(config.brackets) ? config.brackets : (config.brackets ? [config.brackets] : ['right']);
|
const brackets: BracketType[] = Array.isArray(config.brackets) ? config.brackets : (config.brackets ? [config.brackets] : ['right'])
|
||||||
const lx = rect.x - padding[3] * 2;
|
const lx = rect.x - padding[3] * 2
|
||||||
const rx = rect.x + rect.w + padding[1] * 2;
|
const rx = rect.x + rect.w + padding[1] * 2
|
||||||
const ty = rect.y - padding[0] * 2;
|
const ty = rect.y - padding[0] * 2
|
||||||
const by = rect.y + rect.h + padding[2] * 2;
|
const by = rect.y + rect.h + padding[2] * 2
|
||||||
for (const br of brackets) {
|
for (const br of brackets) {
|
||||||
let points: Point[];
|
let points: Point[]
|
||||||
switch (br) {
|
switch (br) {
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
points = [
|
points = [
|
||||||
[lx, rect.y + rect.h],
|
[lx, rect.y + rect.h],
|
||||||
[lx, by],
|
[lx, by],
|
||||||
[rx, by],
|
[rx, by],
|
||||||
[rx, rect.y + rect.h]
|
[rx, rect.y + rect.h],
|
||||||
];
|
]
|
||||||
break;
|
break
|
||||||
case 'top':
|
case 'top':
|
||||||
points = [
|
points = [
|
||||||
[lx, rect.y],
|
[lx, rect.y],
|
||||||
[lx, ty],
|
[lx, ty],
|
||||||
[rx, ty],
|
[rx, ty],
|
||||||
[rx, rect.y]
|
[rx, rect.y],
|
||||||
];
|
]
|
||||||
break;
|
break
|
||||||
case 'left':
|
case 'left':
|
||||||
points = [
|
points = [
|
||||||
[rect.x, ty],
|
[rect.x, ty],
|
||||||
[lx, ty],
|
[lx, ty],
|
||||||
[lx, by],
|
[lx, by],
|
||||||
[rect.x, by]
|
[rect.x, by],
|
||||||
];
|
]
|
||||||
break;
|
break
|
||||||
case 'right':
|
case 'right':
|
||||||
points = [
|
points = [
|
||||||
[rect.x + rect.w, ty],
|
[rect.x + rect.w, ty],
|
||||||
[rx, ty],
|
[rx, ty],
|
||||||
[rx, by],
|
[rx, by],
|
||||||
[rect.x + rect.w, by]
|
[rect.x + rect.w, by],
|
||||||
];
|
]
|
||||||
break;
|
break
|
||||||
}
|
|
||||||
if (points) {
|
|
||||||
opList.push(linearPath(points, false, o));
|
|
||||||
}
|
}
|
||||||
|
if (points)
|
||||||
|
opList.push(linearPath(points, false, o))
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'crossed-off': {
|
case 'crossed-off': {
|
||||||
const x = rect.x;
|
const x = rect.x
|
||||||
const y = rect.y;
|
const y = rect.y
|
||||||
const x2 = x + rect.w;
|
const x2 = x + rect.w
|
||||||
const y2 = y + rect.h;
|
const y2 = y + rect.h
|
||||||
for (let i = rtl; i < iterations + rtl; i++) {
|
for (let i = rtl; i < iterations + rtl; i++) {
|
||||||
if (i % 2) {
|
if (i % 2)
|
||||||
opList.push(line(x2, y2, x, y, o));
|
opList.push(line(x2, y2, x, y, o))
|
||||||
} else {
|
else
|
||||||
opList.push(line(x, y, x2, y2, o));
|
opList.push(line(x, y, x2, y2, o))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (let i = rtl; i < iterations + rtl; i++) {
|
for (let i = rtl; i < iterations + rtl; i++) {
|
||||||
if (i % 2) {
|
if (i % 2)
|
||||||
opList.push(line(x, y2, x2, y, o));
|
opList.push(line(x, y2, x2, y, o))
|
||||||
} else {
|
else
|
||||||
opList.push(line(x2, y, x, y2, o));
|
opList.push(line(x2, y, x, y2, o))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'circle': {
|
case 'circle': {
|
||||||
const doubleO = getOptions('double', seed);
|
const doubleO = getOptions('double', seed)
|
||||||
const width = rect.w + (padding[1] + padding[3]);
|
const width = rect.w + (padding[1] + padding[3])
|
||||||
const height = rect.h + (padding[0] + padding[2]);
|
const height = rect.h + (padding[0] + padding[2])
|
||||||
const x = rect.x - padding[3] + (width / 2);
|
const x = rect.x - padding[3] + (width / 2)
|
||||||
const y = rect.y - padding[0] + (height / 2);
|
const y = rect.y - padding[0] + (height / 2)
|
||||||
const fullItr = Math.floor(iterations / 2);
|
const fullItr = Math.floor(iterations / 2)
|
||||||
const singleItr = iterations - (fullItr * 2);
|
const singleItr = iterations - (fullItr * 2)
|
||||||
for (let i = 0; i < fullItr; i++) {
|
for (let i = 0; i < fullItr; i++)
|
||||||
opList.push(ellipse(x, y, width, height, doubleO));
|
opList.push(ellipse(x, y, width, height, doubleO))
|
||||||
}
|
|
||||||
for (let i = 0; i < singleItr; i++) {
|
for (let i = 0; i < singleItr; i++)
|
||||||
opList.push(ellipse(x, y, width, height, o));
|
opList.push(ellipse(x, y, width, height, o))
|
||||||
}
|
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
case 'highlight': {
|
case 'highlight': {
|
||||||
const o = getOptions('highlight', seed);
|
const o = getOptions('highlight', seed)
|
||||||
strokeWidth = rect.h * 0.95;
|
strokeWidth = rect.h * 0.95
|
||||||
const y = rect.y + (rect.h / 2);
|
const y = rect.y + (rect.h / 2)
|
||||||
for (let i = rtl; i < iterations + rtl; i++) {
|
for (let i = rtl; i < iterations + rtl; i++) {
|
||||||
if (i % 2) {
|
if (i % 2)
|
||||||
opList.push(line(rect.x + rect.w, y, rect.x, y, o));
|
opList.push(line(rect.x + rect.w, y, rect.x, y, o))
|
||||||
} else {
|
else
|
||||||
opList.push(line(rect.x, y, rect.x + rect.w, y, o));
|
opList.push(line(rect.x, y, rect.x + rect.w, y, o))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opList.length) {
|
if (opList.length) {
|
||||||
const pathStrings = opsToPath(opList);
|
const pathStrings = opsToPath(opList)
|
||||||
const lengths: number[] = [];
|
const lengths: number[] = []
|
||||||
const pathElements: SVGPathElement[] = [];
|
const pathElements: SVGPathElement[] = []
|
||||||
let totalLength = 0;
|
let totalLength = 0
|
||||||
const setAttr = (p: SVGPathElement, an: string, av: string) => p.setAttribute(an, av);
|
const setAttr = (p: SVGPathElement, an: string, av: string) => p.setAttribute(an, av)
|
||||||
|
|
||||||
for (const d of pathStrings) {
|
for (const d of pathStrings) {
|
||||||
const path = document.createElementNS(SVG_NS, 'path');
|
const path = document.createElementNS(SVG_NS, 'path')
|
||||||
setAttr(path, 'd', d);
|
setAttr(path, 'd', d)
|
||||||
setAttr(path, 'fill', 'none');
|
setAttr(path, 'fill', 'none')
|
||||||
setAttr(path, 'stroke', config.color || 'currentColor');
|
setAttr(path, 'stroke', config.color || 'currentColor')
|
||||||
setAttr(path, 'stroke-width', `${strokeWidth}`);
|
setAttr(path, 'stroke-width', `${strokeWidth}`)
|
||||||
if (animate) {
|
if (animate) {
|
||||||
const length = path.getTotalLength();
|
const length = path.getTotalLength()
|
||||||
lengths.push(length);
|
lengths.push(length)
|
||||||
totalLength += length;
|
totalLength += length
|
||||||
}
|
}
|
||||||
svg.appendChild(path);
|
svg.appendChild(path)
|
||||||
pathElements.push(path);
|
pathElements.push(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
let durationOffset = 0;
|
let durationOffset = 0
|
||||||
for (let i = 0; i < pathElements.length; i++) {
|
for (let i = 0; i < pathElements.length; i++) {
|
||||||
const path = pathElements[i];
|
const path = pathElements[i]
|
||||||
const length = lengths[i];
|
const length = lengths[i]
|
||||||
const duration = totalLength ? (animationDuration * (length / totalLength)) : 0;
|
const duration = totalLength ? (animationDuration * (length / totalLength)) : 0
|
||||||
const delay = animationGroupDelay + durationOffset;
|
const delay = animationGroupDelay + durationOffset
|
||||||
const style = path.style;
|
const style = path.style
|
||||||
style.strokeDashoffset = `${length}`;
|
style.strokeDashoffset = `${length}`
|
||||||
style.strokeDasharray = `${length}`;
|
style.strokeDasharray = `${length}`
|
||||||
style.animation = `rough-notation-dash ${duration}ms ease-out ${delay}ms forwards`;
|
style.animation = `rough-notation-dash ${duration}ms ease-out ${delay}ms forwards`
|
||||||
durationOffset += duration;
|
durationOffset += duration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function opsToPath(opList: OpSet[]): string[] {
|
function opsToPath(opList: OpSet[]): string[] {
|
||||||
const paths: string[] = [];
|
const paths: string[] = []
|
||||||
for (const drawing of opList) {
|
for (const drawing of opList) {
|
||||||
let path = '';
|
let path = ''
|
||||||
for (const item of drawing.ops) {
|
for (const item of drawing.ops) {
|
||||||
const data = item.data;
|
const data = item.data
|
||||||
switch (item.op) {
|
switch (item.op) {
|
||||||
case 'move':
|
case 'move':
|
||||||
if (path.trim()) {
|
if (path.trim())
|
||||||
paths.push(path.trim());
|
paths.push(path.trim())
|
||||||
}
|
|
||||||
path = `M${data[0]} ${data[1]} `;
|
path = `M${data[0]} ${data[1]} `
|
||||||
break;
|
break
|
||||||
case 'bcurveTo':
|
case 'bcurveTo':
|
||||||
path += `C${data[0]} ${data[1]}, ${data[2]} ${data[3]}, ${data[4]} ${data[5]} `;
|
path += `C${data[0]} ${data[1]}, ${data[2]} ${data[3]}, ${data[4]} ${data[5]} `
|
||||||
break;
|
break
|
||||||
case 'lineTo':
|
case 'lineTo':
|
||||||
path += `L${data[0]} ${data[1]} `;
|
path += `L${data[0]} ${data[1]} `
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (path.trim()) {
|
if (path.trim())
|
||||||
paths.push(path.trim());
|
paths.push(path.trim())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return paths;
|
return paths
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,288 +1,279 @@
|
|||||||
import { SVG_NS, DEFAULT_ANIMATION_DURATION } from './constants';
|
import { randomSeed } from 'roughjs/bin/math'
|
||||||
import { Rect, RoughAnnotationConfig, RoughAnnotation, RoughAnnotationGroup, AnnotationState } from "./types";
|
import { DEFAULT_ANIMATION_DURATION, SVG_NS } from './constants'
|
||||||
import { renderAnnotation } from './render.js';
|
import type { AnnotationState, Rect, RoughAnnotation, RoughAnnotationConfig, RoughAnnotationGroup } from './types'
|
||||||
import { ensureKeyframes } from './keyframes.js';
|
import { renderAnnotation } from './render.js'
|
||||||
import { randomSeed } from 'roughjs/bin/math';
|
import { ensureKeyframes } from './keyframes.js'
|
||||||
|
|
||||||
class RoughAnnotationImpl implements RoughAnnotation {
|
class RoughAnnotationImpl implements RoughAnnotation {
|
||||||
private _state: AnnotationState = 'unattached';
|
private _state: AnnotationState = 'unattached'
|
||||||
private _config: RoughAnnotationConfig;
|
private _config: RoughAnnotationConfig
|
||||||
private _resizing = false;
|
private _resizing = false
|
||||||
private _ro?: any; // ResizeObserver is not supported in typescript std lib yet
|
private _ro?: any // ResizeObserver is not supported in typescript std lib yet
|
||||||
private _seed = randomSeed();
|
private _seed = randomSeed()
|
||||||
|
|
||||||
private _e: HTMLElement;
|
private _e: HTMLElement
|
||||||
private _svg?: SVGSVGElement;
|
private _svg?: SVGSVGElement
|
||||||
private _lastSizes: Rect[] = [];
|
private _lastSizes: Rect[] = []
|
||||||
|
|
||||||
_animationDelay = 0;
|
_animationDelay = 0
|
||||||
|
|
||||||
constructor(e: HTMLElement, config: RoughAnnotationConfig) {
|
constructor(e: HTMLElement, config: RoughAnnotationConfig) {
|
||||||
this._e = e;
|
this._e = e
|
||||||
this._config = JSON.parse(JSON.stringify(config));
|
this._config = JSON.parse(JSON.stringify(config))
|
||||||
this.attach();
|
this.attach()
|
||||||
}
|
}
|
||||||
|
|
||||||
get animate() { return this._config.animate; }
|
get animate() { return this._config.animate }
|
||||||
set animate(value) { this._config.animate = value; }
|
set animate(value) { this._config.animate = value }
|
||||||
|
|
||||||
get animationDuration() { return this._config.animationDuration; }
|
get animationDuration() { return this._config.animationDuration }
|
||||||
set animationDuration(value) { this._config.animationDuration = value; }
|
set animationDuration(value) { this._config.animationDuration = value }
|
||||||
|
|
||||||
get iterations() { return this._config.iterations; }
|
get iterations() { return this._config.iterations }
|
||||||
set iterations(value) { this._config.iterations = value; }
|
set iterations(value) { this._config.iterations = value }
|
||||||
|
|
||||||
get color() { return this._config.color; }
|
get color() { return this._config.color }
|
||||||
set color(value) {
|
set color(value) {
|
||||||
if (this._config.color !== value) {
|
if (this._config.color !== value) {
|
||||||
this._config.color = value;
|
this._config.color = value
|
||||||
this.refresh();
|
this.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get class() { return this._config.class; }
|
get class() { return this._config.class }
|
||||||
set class(value) {
|
set class(value) {
|
||||||
if (this._config.class !== value) {
|
if (this._config.class !== value) {
|
||||||
this._config.class = value;
|
this._config.class = value
|
||||||
if (this._svg) {
|
if (this._svg)
|
||||||
this._svg.setAttribute('class', ['rough-annotation', this._config.class || ''].filter(Boolean).join(' '));
|
this._svg.setAttribute('class', ['rough-annotation', this._config.class || ''].filter(Boolean).join(' '))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get strokeWidth() { return this._config.strokeWidth; }
|
get strokeWidth() { return this._config.strokeWidth }
|
||||||
set strokeWidth(value) {
|
set strokeWidth(value) {
|
||||||
if (this._config.strokeWidth !== value) {
|
if (this._config.strokeWidth !== value) {
|
||||||
this._config.strokeWidth = value;
|
this._config.strokeWidth = value
|
||||||
this.refresh();
|
this.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get padding() { return this._config.padding; }
|
get padding() { return this._config.padding }
|
||||||
set padding(value) {
|
set padding(value) {
|
||||||
if (this._config.padding !== value) {
|
if (this._config.padding !== value) {
|
||||||
this._config.padding = value;
|
this._config.padding = value
|
||||||
this.refresh();
|
this.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resizeListener = () => {
|
private _resizeListener = () => {
|
||||||
if (!this._resizing) {
|
if (!this._resizing) {
|
||||||
this._resizing = true;
|
this._resizing = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this._resizing = false;
|
this._resizing = false
|
||||||
if (this._state === 'showing') {
|
if (this._state === 'showing') {
|
||||||
if (this.haveRectsChanged()) {
|
if (this.haveRectsChanged())
|
||||||
this.show();
|
this.show()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 400);
|
}, 400)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private attach() {
|
private attach() {
|
||||||
if (this._state === 'unattached' && this._e.parentElement) {
|
if (this._state === 'unattached' && this._e.parentElement) {
|
||||||
ensureKeyframes();
|
ensureKeyframes()
|
||||||
const svg = this._svg = document.createElementNS(SVG_NS, 'svg');
|
const svg = this._svg = document.createElementNS(SVG_NS, 'svg')
|
||||||
svg.setAttribute('class', ['rough-annotation', this._config.class || ''].filter(Boolean).join(' '));
|
svg.setAttribute('class', ['rough-annotation', this._config.class || ''].filter(Boolean).join(' '))
|
||||||
const style = svg.style;
|
const style = svg.style
|
||||||
style.position = 'absolute';
|
style.position = 'absolute'
|
||||||
style.top = '0';
|
style.top = '0'
|
||||||
style.left = '0';
|
style.left = '0'
|
||||||
style.overflow = 'visible';
|
style.overflow = 'visible'
|
||||||
style.pointerEvents = 'none';
|
style.pointerEvents = 'none'
|
||||||
style.width = '100px';
|
style.width = '100px'
|
||||||
style.height = '100px';
|
style.height = '100px'
|
||||||
const prepend = this._config.type === 'highlight';
|
const prepend = this._config.type === 'highlight'
|
||||||
this._e.insertAdjacentElement(prepend ? 'beforebegin' : 'afterend', svg);
|
this._e.insertAdjacentElement(prepend ? 'beforebegin' : 'afterend', svg)
|
||||||
this._state = 'not-showing';
|
this._state = 'not-showing'
|
||||||
|
|
||||||
// ensure e is positioned
|
// ensure e is positioned
|
||||||
if (prepend) {
|
if (prepend) {
|
||||||
const computedPos = window.getComputedStyle(this._e).position;
|
const computedPos = window.getComputedStyle(this._e).position
|
||||||
const unpositioned = (!computedPos) || (computedPos === 'static');
|
const unpositioned = (!computedPos) || (computedPos === 'static')
|
||||||
if (unpositioned) {
|
if (unpositioned)
|
||||||
this._e.style.position = 'relative';
|
this._e.style.position = 'relative'
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.attachListeners();
|
this.attachListeners()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private detachListeners() {
|
private detachListeners() {
|
||||||
window.removeEventListener('resize', this._resizeListener);
|
window.removeEventListener('resize', this._resizeListener)
|
||||||
if (this._ro) {
|
if (this._ro)
|
||||||
this._ro.unobserve(this._e);
|
this._ro.unobserve(this._e)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachListeners() {
|
private attachListeners() {
|
||||||
this.detachListeners();
|
this.detachListeners()
|
||||||
window.addEventListener('resize', this._resizeListener, { passive: true });
|
window.addEventListener('resize', this._resizeListener, { passive: true })
|
||||||
if ((!this._ro) && ('ResizeObserver' in window)) {
|
if ((!this._ro) && ('ResizeObserver' in window)) {
|
||||||
this._ro = new (window as any).ResizeObserver((entries: any) => {
|
this._ro = new (window as any).ResizeObserver((entries: any) => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry.contentRect) {
|
if (entry.contentRect)
|
||||||
this._resizeListener();
|
this._resizeListener()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
|
||||||
if (this._ro) {
|
|
||||||
this._ro.observe(this._e);
|
|
||||||
}
|
}
|
||||||
|
if (this._ro)
|
||||||
|
this._ro.observe(this._e)
|
||||||
}
|
}
|
||||||
|
|
||||||
private haveRectsChanged(): boolean {
|
private haveRectsChanged(): boolean {
|
||||||
if (this._lastSizes.length) {
|
if (this._lastSizes.length) {
|
||||||
const newRects = this.rects();
|
const newRects = this.rects()
|
||||||
if (newRects.length === this._lastSizes.length) {
|
if (newRects.length === this._lastSizes.length) {
|
||||||
for (let i = 0; i < newRects.length; i++) {
|
for (let i = 0; i < newRects.length; i++) {
|
||||||
if (!this.isSameRect(newRects[i], this._lastSizes[i])) {
|
if (!this.isSameRect(newRects[i], this._lastSizes[i]))
|
||||||
return true;
|
return true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return true;
|
else {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSameRect(rect1: Rect, rect2: Rect): boolean {
|
private isSameRect(rect1: Rect, rect2: Rect): boolean {
|
||||||
const si = (a: number, b: number) => Math.round(a) === Math.round(b);
|
const si = (a: number, b: number) => Math.round(a) === Math.round(b)
|
||||||
return (
|
return (
|
||||||
si(rect1.x, rect2.x) &&
|
si(rect1.x, rect2.x)
|
||||||
si(rect1.y, rect2.y) &&
|
&& si(rect1.y, rect2.y)
|
||||||
si(rect1.w, rect2.w) &&
|
&& si(rect1.w, rect2.w)
|
||||||
si(rect1.h, rect2.h)
|
&& si(rect1.h, rect2.h)
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowing(): boolean {
|
isShowing(): boolean {
|
||||||
return (this._state !== 'not-showing');
|
return (this._state !== 'not-showing')
|
||||||
}
|
}
|
||||||
|
|
||||||
private pendingRefresh?: Promise<void>;
|
private pendingRefresh?: Promise<void>
|
||||||
private refresh() {
|
private refresh() {
|
||||||
if (this.isShowing() && (!this.pendingRefresh)) {
|
if (this.isShowing() && (!this.pendingRefresh)) {
|
||||||
this.pendingRefresh = Promise.resolve().then(() => {
|
this.pendingRefresh = Promise.resolve().then(() => {
|
||||||
if (this.isShowing()) {
|
if (this.isShowing())
|
||||||
this.show();
|
this.show()
|
||||||
}
|
|
||||||
delete this.pendingRefresh;
|
delete this.pendingRefresh
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
show(): void {
|
show(): void {
|
||||||
switch (this._state) {
|
switch (this._state) {
|
||||||
case 'unattached':
|
case 'unattached':
|
||||||
break;
|
break
|
||||||
case 'showing':
|
case 'showing':
|
||||||
this.hide();
|
this.hide()
|
||||||
if (this._svg) {
|
if (this._svg)
|
||||||
this.render(this._svg, true);
|
this.render(this._svg, true)
|
||||||
}
|
|
||||||
break;
|
break
|
||||||
case 'not-showing':
|
case 'not-showing':
|
||||||
this.attach();
|
this.attach()
|
||||||
if (this._svg) {
|
if (this._svg)
|
||||||
this.render(this._svg, false);
|
this.render(this._svg, false)
|
||||||
}
|
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hide(): void {
|
hide(): void {
|
||||||
if (this._svg) {
|
if (this._svg) {
|
||||||
while (this._svg.lastChild) {
|
while (this._svg.lastChild)
|
||||||
this._svg.removeChild(this._svg.lastChild);
|
this._svg.removeChild(this._svg.lastChild)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this._state = 'not-showing';
|
this._state = 'not-showing'
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(): void {
|
remove(): void {
|
||||||
if (this._svg && this._svg.parentElement) {
|
if (this._svg && this._svg.parentElement)
|
||||||
this._svg.parentElement.removeChild(this._svg);
|
this._svg.parentElement.removeChild(this._svg)
|
||||||
}
|
|
||||||
this._svg = undefined;
|
this._svg = undefined
|
||||||
this._state = 'unattached';
|
this._state = 'unattached'
|
||||||
this.detachListeners();
|
this.detachListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
private render(svg: SVGSVGElement, ensureNoAnimation: boolean) {
|
private render(svg: SVGSVGElement, ensureNoAnimation: boolean) {
|
||||||
let config = this._config;
|
let config = this._config
|
||||||
if (ensureNoAnimation) {
|
if (ensureNoAnimation) {
|
||||||
config = JSON.parse(JSON.stringify(this._config));
|
config = JSON.parse(JSON.stringify(this._config))
|
||||||
config.animate = false;
|
config.animate = false
|
||||||
}
|
}
|
||||||
const rects = this.rects();
|
const rects = this.rects()
|
||||||
let totalWidth = 0;
|
let totalWidth = 0
|
||||||
rects.forEach((rect) => totalWidth += rect.w);
|
rects.forEach(rect => totalWidth += rect.w)
|
||||||
const totalDuration = (config.animationDuration || DEFAULT_ANIMATION_DURATION);
|
const totalDuration = (config.animationDuration || DEFAULT_ANIMATION_DURATION)
|
||||||
let delay = 0;
|
let delay = 0
|
||||||
for (let i = 0; i < rects.length; i++) {
|
for (let i = 0; i < rects.length; i++) {
|
||||||
const rect = rects[i];
|
const rect = rects[i]
|
||||||
const ad = totalDuration * (rect.w / totalWidth);
|
const ad = totalDuration * (rect.w / totalWidth)
|
||||||
renderAnnotation(svg, rects[i], config, delay + this._animationDelay, ad, this._seed);
|
renderAnnotation(svg, rects[i], config, delay + this._animationDelay, ad, this._seed)
|
||||||
delay += ad;
|
delay += ad
|
||||||
}
|
}
|
||||||
this._lastSizes = rects;
|
this._lastSizes = rects
|
||||||
this._state = 'showing';
|
this._state = 'showing'
|
||||||
}
|
}
|
||||||
|
|
||||||
private rects(): Rect[] {
|
private rects(): Rect[] {
|
||||||
const ret: Rect[] = [];
|
const ret: Rect[] = []
|
||||||
if (this._svg) {
|
if (this._svg) {
|
||||||
if (this._config.multiline) {
|
if (this._config.multiline) {
|
||||||
const elementRects = this._e.getClientRects();
|
const elementRects = this._e.getClientRects()
|
||||||
for (let i = 0; i < elementRects.length; i++) {
|
for (let i = 0; i < elementRects.length; i++)
|
||||||
ret.push(this.svgRect(this._svg, elementRects[i]));
|
ret.push(this.svgRect(this._svg, elementRects[i]))
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
ret.push(this.svgRect(this._svg, this._e.getBoundingClientRect()));
|
ret.push(this.svgRect(this._svg, this._e.getBoundingClientRect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
private svgRect(svg: SVGSVGElement, bounds: DOMRect | DOMRectReadOnly): Rect {
|
private svgRect(svg: SVGSVGElement, bounds: DOMRect | DOMRectReadOnly): Rect {
|
||||||
const rect1 = svg.getBoundingClientRect();
|
const rect1 = svg.getBoundingClientRect()
|
||||||
const rect2 = bounds;
|
const rect2 = bounds
|
||||||
return {
|
return {
|
||||||
x: (rect2.x || rect2.left) - (rect1.x || rect1.left),
|
x: (rect2.x || rect2.left) - (rect1.x || rect1.left),
|
||||||
y: (rect2.y || rect2.top) - (rect1.y || rect1.top),
|
y: (rect2.y || rect2.top) - (rect1.y || rect1.top),
|
||||||
w: rect2.width,
|
w: rect2.width,
|
||||||
h: rect2.height
|
h: rect2.height,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function annotate(element: HTMLElement, config: RoughAnnotationConfig): RoughAnnotation {
|
export function annotate(element: HTMLElement, config: RoughAnnotationConfig): RoughAnnotation {
|
||||||
return new RoughAnnotationImpl(element, config);
|
return new RoughAnnotationImpl(element, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function annotationGroup(annotations: RoughAnnotation[]): RoughAnnotationGroup {
|
export function annotationGroup(annotations: RoughAnnotation[]): RoughAnnotationGroup {
|
||||||
let delay = 0;
|
let delay = 0
|
||||||
for (const a of annotations) {
|
for (const a of annotations) {
|
||||||
const ai = a as RoughAnnotationImpl;
|
const ai = a as RoughAnnotationImpl
|
||||||
ai._animationDelay = delay;
|
ai._animationDelay = delay
|
||||||
const duration = ai.animationDuration === 0 ? 0 : (ai.animationDuration || DEFAULT_ANIMATION_DURATION);
|
const duration = ai.animationDuration === 0 ? 0 : (ai.animationDuration || DEFAULT_ANIMATION_DURATION)
|
||||||
delay += duration;
|
delay += duration
|
||||||
}
|
}
|
||||||
const list = [...annotations];
|
const list = [...annotations]
|
||||||
return {
|
return {
|
||||||
show() {
|
show() {
|
||||||
for (const a of list) {
|
for (const a of list)
|
||||||
a.show();
|
a.show()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
hide() {
|
hide() {
|
||||||
for (const a of list) {
|
for (const a of list)
|
||||||
a.hide();
|
a.hide()
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
50
src/types.ts
50
src/types.ts
@@ -1,43 +1,43 @@
|
|||||||
export interface Rect {
|
export interface Rect {
|
||||||
x: number;
|
x: number
|
||||||
y: number;
|
y: number
|
||||||
w: number;
|
w: number
|
||||||
h: number;
|
h: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RoughAnnotationType = 'underline' | 'box' | 'circle' | 'highlight' | 'strike-through' | 'crossed-off' | 'bracket';
|
export type RoughAnnotationType = 'underline' | 'box' | 'circle' | 'highlight' | 'strike-through' | 'crossed-off' | 'bracket'
|
||||||
export type FullPadding = [number, number, number, number];
|
export type FullPadding = [number, number, number, number]
|
||||||
export type RoughPadding = number | [number, number] | FullPadding;
|
export type RoughPadding = number | [number, number] | FullPadding
|
||||||
export type BracketType = 'left' | 'right' | 'top' | 'bottom';
|
export type BracketType = 'left' | 'right' | 'top' | 'bottom'
|
||||||
|
|
||||||
export interface RoughAnnotationConfig extends RoughAnnotationConfigBase {
|
export interface RoughAnnotationConfig extends RoughAnnotationConfigBase {
|
||||||
type: RoughAnnotationType;
|
type: RoughAnnotationType
|
||||||
multiline?: boolean;
|
multiline?: boolean
|
||||||
rtl?: boolean;
|
rtl?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoughAnnotationConfigBase {
|
export interface RoughAnnotationConfigBase {
|
||||||
animate?: boolean; // defaults to true
|
animate?: boolean // defaults to true
|
||||||
animationDuration?: number; // defaults to 1000ms
|
animationDuration?: number // defaults to 1000ms
|
||||||
color?: string; // defaults to currentColor
|
color?: string // defaults to currentColor
|
||||||
strokeWidth?: number; // default based on type
|
strokeWidth?: number // default based on type
|
||||||
padding?: RoughPadding; // defaults to 5px
|
padding?: RoughPadding // defaults to 5px
|
||||||
iterations?: number; // defaults to 2
|
iterations?: number // defaults to 2
|
||||||
brackets?: BracketType | BracketType[]; // defaults to 'right'
|
brackets?: BracketType | BracketType[] // defaults to 'right'
|
||||||
// Additional class added to the annotation
|
// Additional class added to the annotation
|
||||||
class?: string
|
class?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoughAnnotation extends RoughAnnotationConfigBase {
|
export interface RoughAnnotation extends RoughAnnotationConfigBase {
|
||||||
isShowing(): boolean;
|
isShowing: () => boolean
|
||||||
show(): void;
|
show: () => void
|
||||||
hide(): void;
|
hide: () => void
|
||||||
remove(): void;
|
remove: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoughAnnotationGroup {
|
export interface RoughAnnotationGroup {
|
||||||
show(): void;
|
show: () => void
|
||||||
hide(): void;
|
hide: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnnotationState = 'unattached' | 'not-showing' | 'showing';
|
export type AnnotationState = 'unattached' | 'not-showing' | 'showing'
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"module": "es2015",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2017",
|
"es2017",
|
||||||
"dom"
|
"dom"
|
||||||
],
|
],
|
||||||
"declaration": true,
|
|
||||||
"outDir": "./lib",
|
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noImplicitReturns": true,
|
"declaration": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"outDir": "./lib"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
61
tslint.json
61
tslint.json
@@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"rules": {
|
|
||||||
"arrow-parens": true,
|
|
||||||
"class-name": true,
|
|
||||||
"indent": [
|
|
||||||
true,
|
|
||||||
"spaces",
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"prefer-const": true,
|
|
||||||
"no-duplicate-variable": true,
|
|
||||||
"no-eval": true,
|
|
||||||
"no-internal-module": true,
|
|
||||||
"no-trailing-whitespace": false,
|
|
||||||
"no-var-keyword": true,
|
|
||||||
"one-line": [
|
|
||||||
true,
|
|
||||||
"check-open-brace",
|
|
||||||
"check-whitespace"
|
|
||||||
],
|
|
||||||
"quotemark": [
|
|
||||||
true,
|
|
||||||
"single",
|
|
||||||
"avoid-escape"
|
|
||||||
],
|
|
||||||
"semicolon": [
|
|
||||||
true,
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"trailing-comma": [
|
|
||||||
true,
|
|
||||||
"multiline"
|
|
||||||
],
|
|
||||||
"triple-equals": [
|
|
||||||
true,
|
|
||||||
"allow-null-check"
|
|
||||||
],
|
|
||||||
"typedef-whitespace": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"call-signature": "nospace",
|
|
||||||
"index-signature": "nospace",
|
|
||||||
"parameter": "nospace",
|
|
||||||
"property-declaration": "nospace",
|
|
||||||
"variable-declaration": "nospace"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"variable-name": [
|
|
||||||
true,
|
|
||||||
"ban-keywords"
|
|
||||||
],
|
|
||||||
"whitespace": [
|
|
||||||
true,
|
|
||||||
"check-branch",
|
|
||||||
"check-decl",
|
|
||||||
"check-operator",
|
|
||||||
"check-separator",
|
|
||||||
"check-type"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user