Showing preview only (2,799K chars total). Download the full file or copy to clipboard to get everything.
Repository: jonobr1/two.js
Branch: dev
Commit: c8e5f95d2405
Files: 207
Total size: 2.6 MB
Directory structure:
gitextract_pil82dhw/
├── .eslintignore
├── .eslintrc.json
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ ├── output.md
│ │ └── question.md
│ └── workflows/
│ ├── codeql.yml
│ ├── lint.yml
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── build/
│ ├── two.js
│ └── two.module.js
├── deploy.sh
├── extras/
│ ├── js/
│ │ ├── arc.js
│ │ └── zui.js
│ └── jsm/
│ ├── arc.js
│ ├── zui.d.ts
│ └── zui.js
├── package.json
├── src/
│ ├── anchor.d.ts
│ ├── anchor.js
│ ├── children.d.ts
│ ├── children.js
│ ├── collection.d.ts
│ ├── collection.js
│ ├── constants.d.ts
│ ├── constants.js
│ ├── effects/
│ │ ├── gradient.d.ts
│ │ ├── gradient.js
│ │ ├── image-sequence.d.ts
│ │ ├── image-sequence.js
│ │ ├── image.d.ts
│ │ ├── image.js
│ │ ├── linear-gradient.d.ts
│ │ ├── linear-gradient.js
│ │ ├── radial-gradient.d.ts
│ │ ├── radial-gradient.js
│ │ ├── sprite.d.ts
│ │ ├── sprite.js
│ │ ├── stop.d.ts
│ │ ├── stop.js
│ │ ├── texture.d.ts
│ │ └── texture.js
│ ├── element.d.ts
│ ├── element.js
│ ├── events.d.ts
│ ├── events.js
│ ├── group.d.ts
│ ├── group.js
│ ├── matrix.d.ts
│ ├── matrix.js
│ ├── path.d.ts
│ ├── path.js
│ ├── registry.d.ts
│ ├── registry.js
│ ├── renderers/
│ │ ├── canvas.d.ts
│ │ ├── canvas.js
│ │ ├── svg.d.ts
│ │ ├── svg.js
│ │ ├── webgl.d.ts
│ │ └── webgl.js
│ ├── shape.d.ts
│ ├── shape.js
│ ├── shapes/
│ │ ├── arc-segment.d.ts
│ │ ├── arc-segment.js
│ │ ├── circle.d.ts
│ │ ├── circle.js
│ │ ├── ellipse.d.ts
│ │ ├── ellipse.js
│ │ ├── line.d.ts
│ │ ├── line.js
│ │ ├── points.d.ts
│ │ ├── points.js
│ │ ├── polygon.d.ts
│ │ ├── polygon.js
│ │ ├── rectangle.d.ts
│ │ ├── rectangle.js
│ │ ├── rounded-rectangle.d.ts
│ │ ├── rounded-rectangle.js
│ │ ├── star.d.ts
│ │ └── star.js
│ ├── text.d.ts
│ ├── text.js
│ ├── two.d.ts
│ ├── two.js
│ ├── utils/
│ │ ├── canvas-polyfill.d.ts
│ │ ├── canvas-polyfill.js
│ │ ├── curves.d.ts
│ │ ├── curves.js
│ │ ├── device-pixel-ratio.d.ts
│ │ ├── device-pixel-ratio.js
│ │ ├── dom.d.ts
│ │ ├── dom.js
│ │ ├── error.d.ts
│ │ ├── error.js
│ │ ├── hit-test.js
│ │ ├── interpret-svg.d.ts
│ │ ├── interpret-svg.js
│ │ ├── math.d.ts
│ │ ├── math.js
│ │ ├── path-commands.d.ts
│ │ ├── path-commands.js
│ │ ├── path.js
│ │ ├── root.d.ts
│ │ ├── root.js
│ │ ├── shaders.d.ts
│ │ ├── shaders.js
│ │ ├── shape.d.ts
│ │ ├── shape.js
│ │ ├── underscore.d.ts
│ │ ├── underscore.js
│ │ ├── xhr.d.ts
│ │ └── xhr.js
│ ├── vector.d.ts
│ └── vector.js
├── tests/
│ ├── index.html
│ ├── noWebGL.html
│ ├── src/
│ │ └── utils.js
│ ├── suite/
│ │ ├── bounding-box.js
│ │ ├── canvas.js
│ │ ├── core.js
│ │ ├── dispose.js
│ │ ├── hit-test.js
│ │ ├── release.js
│ │ ├── shapes.js
│ │ ├── svg-interpreter.js
│ │ ├── svg.js
│ │ └── webgl.js
│ └── typescript/
│ ├── index.js
│ ├── index.ts
│ └── package.json
├── utils/
│ ├── INSTRUCTIONS.md
│ ├── build.js
│ ├── docs.template
│ ├── document.js
│ ├── file-sizes.json
│ └── source-files.js
└── wiki/
├── .vuepress/
│ ├── components/
│ │ ├── carbon-ads.vue
│ │ ├── custom-button.vue
│ │ ├── example-card.vue
│ │ ├── inline-editor.vue
│ │ ├── redirect-page.vue
│ │ └── version-link.vue
│ ├── config.js
│ ├── enhanceApp.js
│ ├── plugins/
│ │ └── search/
│ │ ├── SearchBox.vue
│ │ └── match-query.js
│ ├── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ └── theme/
│ ├── components/
│ │ ├── Navbar.vue
│ │ └── Sidebar.vue
│ ├── index.js
│ └── layouts/
│ └── NotFound.vue
├── README.md
├── change-log/
│ └── README.md
├── changelog/
│ └── README.md
├── docs/
│ ├── README.md
│ ├── anchor/
│ │ └── README.md
│ ├── children/
│ │ └── README.md
│ ├── collection/
│ │ └── README.md
│ ├── effects/
│ │ ├── gradient/
│ │ │ └── README.md
│ │ ├── image/
│ │ │ └── README.md
│ │ ├── image-sequence/
│ │ │ └── README.md
│ │ ├── linear-gradient/
│ │ │ └── README.md
│ │ ├── radial-gradient/
│ │ │ └── README.md
│ │ ├── sprite/
│ │ │ └── README.md
│ │ ├── stop/
│ │ │ └── README.md
│ │ └── texture/
│ │ └── README.md
│ ├── element/
│ │ └── README.md
│ ├── events/
│ │ └── README.md
│ ├── extras/
│ │ ├── arc/
│ │ │ └── README.md
│ │ └── zui/
│ │ └── README.md
│ ├── group/
│ │ └── README.md
│ ├── matrix/
│ │ └── README.md
│ ├── path/
│ │ └── README.md
│ ├── registry/
│ │ └── README.md
│ ├── renderers/
│ │ ├── canvas/
│ │ │ └── README.md
│ │ ├── svg/
│ │ │ └── README.md
│ │ └── webgl/
│ │ └── README.md
│ ├── shape/
│ │ └── README.md
│ ├── shapes/
│ │ ├── arc-segment/
│ │ │ └── README.md
│ │ ├── circle/
│ │ │ └── README.md
│ │ ├── ellipse/
│ │ │ └── README.md
│ │ ├── line/
│ │ │ └── README.md
│ │ ├── points/
│ │ │ └── README.md
│ │ ├── polygon/
│ │ │ └── README.md
│ │ ├── rectangle/
│ │ │ └── README.md
│ │ ├── rounded-rectangle/
│ │ │ └── README.md
│ │ └── star/
│ │ └── README.md
│ ├── text/
│ │ └── README.md
│ ├── two/
│ │ └── README.md
│ └── vector/
│ └── README.md
├── donate/
│ └── README.md
├── examples/
│ └── README.md
├── incident-response-plan/
│ └── README.md
├── privacy/
│ └── README.md
└── security/
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
/**/*.d.ts
================================================
FILE: .eslintrc.json
================================================
{
"parser": "babel-eslint",
"extends": "eslint:recommended",
"env": {
"browser": true,
"commonjs": true,
"amd": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2015
},
"rules": {
"semi": ["error", "always"],
"no-unused-vars": ["error", {"args": "none"}]
},
"overrides": [
{
"files": ["utils/**"],
"env": {
"node": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 8
}
},
{
"files": ["tests/**", "extras/js/**"],
"globals": {
"QUnit": "writable",
"resemble": "writable",
"Two": "writable",
"_": "writable"
},
"rules": {
"no-redeclare": "off"
}
}
],
"ignorePatterns": ["build/", "utils/start-comment.js", "utils/end-comment.js", "utils/exports.js", "junk/"]
}
================================================
FILE: .gitattributes
================================================
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.gif binary
*.png binary
*.jpg binary
*.jpeg binary
*.mp4 binary
*.webm binary
*.eot binary
*.woff binary
*.woff2 binary
*.ttf binary
*.mp3 binary
*.ogg binary
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [jonobr1] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
custom: # https://two.js.org/donate/
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help improve Two.js
title: "[Bug]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please select one):**
- [ ] Code executes in browser (e.g: using script tag to load library)
- [ ] Packaged software (e.g: ES6 imports, react, angular, vue.js)
- [ ] Running headless (usually Node.js)
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea or enhancement to Two.js
title: "[Enhancement]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/output.md
================================================
---
name: Output
about: Share what you have made with Two.js
title: "[Output]"
labels: output
assignees: ''
---
**What did you make with Two.js?**
A clear and concise description of what you made and how Two.js was a part of it.
**Can we showcase this on [the Two.js site](https://two.js.org/)?**
- [ ] Yes
- [ ] No
**To be included for the Two.js site:**
1. Project name
2. We need an animated gif or still image at at least 512px wide. Also, this image needs to be hosted where we can input the URL.
3. Tags: particular features of Two.js you used? Or any other defining aspects to your project that would make it easy for people to search for on the site?
**Feedback**
Anything you'd like to share with the Two.js team? Pros, cons, suggestions, praise?
**Thank you for sharing!**
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: Ask a question about Two.js
title: "[Question]"
labels: question
assignees: ''
---
**Describe your question**
**Your code (either pasted here, or a link to a hosted example)**
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please select one):**
- [ ] Code executes in browser (e.g: using script tag to load library)
- [ ] Packaged software (e.g: ES6 imports, react, angular, vue.js)
- [ ] Running headless (usually Node.js)
---
If applicable:
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/workflows/codeql.yml
================================================
name: "CodeQL"
on:
push:
branches: [ "dev" ]
pull_request:
branches: [ "dev" ]
schedule:
- cron: "22 9 * * 6"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ javascript ]
steps:
# checkout@v5
- name: Checkout repository
uses: jonobr1/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
# setup-node@v5
- name: Set up Node.js
uses: jonobr1/setup-node@a0853c24544627f65ddf259abe73b1d18a591444
with:
node-version: '20' # Use latest LTS
# cache@v4
- name: Cache node modules
uses: jonobr1/cache@0400d5f644dc74513175e3cd8d07132dd4860809
with:
path: |
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Install dependencies
run: npm ci
# codeql-action/init@v3
- name: Initialize CodeQL
uses: jonobr1/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3
with:
languages: ${{ matrix.language }}
queries: security-and-quality
# codeql-action/autobuild@v3
- name: Autobuild
uses: jonobr1/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3
# codeql-action/analyze@v3
- name: Perform CodeQL Analysis
uses: jonobr1/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3
with:
category: "/language:${{ matrix.language }}"
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
# checkout@v5
- uses: jonobr1/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: Install modules
run: npm install
- name: Run ESLint
run: npm run lint
================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish Package
on:
push:
tags:
- 'v*'
permissions:
id-token: write # Required for OIDC
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
# checkout@v6
- uses: jonobr1/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
# setup-node@v6
- uses: jonobr1/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
# Ensure npm 11.5.1 or later is installed
- name: Update npm
run: npm install -g npm@latest
- run: npm ci
- run: npm run build --if-present
# - run: npm test
- run: npm publish
================================================
FILE: .gitignore
================================================
node_modules
*.DS_Store
junk/
*.log
docs.json
dist
.idea
.codacy
tests/typescript/package-lock.json
#Ignore vscode AI rules
.github/instructions/codacy.instructions.md
================================================
FILE: .npmrc
================================================
package-lock = false
================================================
FILE: .nvmrc
================================================
v14.7.0
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Two.js is a renderer-agnostic 2D drawing API for modern browsers. It provides a unified interface for creating graphics across multiple rendering contexts: WebGL, Canvas2D, and SVG.
## Core Architecture
### Main Entry Point
- `src/two.js` - Main Two.js class and entry point that imports all modules
- The Two class extends Events and provides factory methods for creating shapes
### Rendering System
- **Multi-renderer architecture**: Canvas, SVG, and WebGL renderers in `src/renderers/`
- **Scene graph**: Hierarchical structure using Groups and Elements
- **Automatic renderer selection**: Based on domElement type or explicit type specification
### Core Classes
- `Element` - Base class for all drawable objects
- `Shape` - Extended Element with transformation and styling
- `Group` - Container for organizing and transforming multiple objects
- `Path` - Complex shapes defined by anchor points and curves
- `Vector` - 2D vector mathematics
- `Matrix` - 2D transformation matrices
- `Anchor` - Control points for paths with B�zier curve handles
### Shape Library
Located in `src/shapes/`:
- Basic shapes: Rectangle, Circle, Ellipse, Line, Star, Polygon
- Complex shapes: ArcSegment, RoundedRectangle, Points
- All shapes inherit from Path or Shape classes
### Effects System
Located in `src/effects/`:
- Gradients: LinearGradient, RadialGradient with Stop objects
- Images: Texture, Sprite, ImageSequence for bitmap rendering
- All effects can be applied as fill or stroke to shapes
## Build System
### Commands
- `npm run build` - Build all versions (UMD, ESM, minified) using esbuild
- `npm run dev` - Development server with esbuild on port 8080
- `npm run lint` - ESLint with auto-fix
- `npm run docs:generate` - Generate documentation from JSDoc comments
- `npm run docs:dev` - Local documentation server with Vuepress
- `npm run docs:build` - Build static documentation site
### Build Configuration
- Build script: `utils/build.js`
- Uses esbuild for fast bundling and minification
- Outputs: `build/two.js` (UMD), `build/two.module.js` (ESM), `build/two.min.js` (minified)
- Includes license header and module.exports compatibility
## Development Patterns
### Factory Methods
The Two class provides factory methods for creating and adding objects to the scene:
- `makeRectangle()`, `makeCircle()`, `makeText()`, etc.
- All factory methods automatically add objects to the scene
- Return the created object for further manipulation
### Event System
- All objects inherit from Events class
- Common events: update, render, resize, play, pause
- Use `bind()`, `unbind()`, `trigger()` for event handling
### Coordinate System
- Origin (0,0) at top-left by default
- Positive Y axis points down
- Transformations applied via translation, rotation, scale properties
### Memory Management
- Use `release()` method to unbind events and free memory
- Automatically handles nested objects, vertices, and effects
- Important for preventing memory leaks in long-running applications
## Testing
### Test Structure
- Tests located in `tests/` directory
- Test suites in `tests/suite/` organized by functionality
- HTML test runners: `tests/index.html`, `tests/noWebGL.html`
- TypeScript compilation tests in `tests/typescript/` with `index.ts` that imports and uses Two.js API
### Running Tests
- Manual browser testing via HTML files: `tests/index.html` and `tests/noWebGL.html`
- TypeScript compilation testing: `npx tsc --noEmit --skipLibCheck tests/typescript/index.ts` to verify types work correctly
## Key Files to Understand
- `src/two.js` - Main class with factory methods and core logic
- `src/constants.js` - Global constants, types, and configuration
- `src/utils/interpret-svg.js` - SVG parsing and import functionality
- `utils/build.js` - Build system configuration
- `src/**/*.d.ts` - TypeScript definitions collocated with source files (e.g., `src/vector.d.ts` alongside `src/vector.js`)
- `src/two.d.ts` - Main TypeScript entry point that aggregates all type exports
## Dependencies
Production: None (library designed to be dependency-free)
Development: esbuild, ESLint, TypeScript, Vuepress for documentation
## Browser Compatibility
Designed for modern browsers with ES6+ support. Uses feature detection for renderer capabilities.
## Development Workflow
- Always run `npm run build && npm run lint` before committing
- Test changes in `tests/index.html` for visual verification
- Use `npm run dev` for development server on port 8080
- Check TypeScript types with `npm run types`
- Test across all three renderers (Canvas, SVG, WebGL) for compatibility
## Code Style and Conventions
- Use ES6+ features consistently
- Prefer `const` over `let` where possible
- Factory methods should always return the created object
- All classes should extend appropriate base classes (Element, Shape, etc.)
- Use JSDoc comments for public API methods
- Use 2-space indentation for JavaScript files
- Place new components in appropriate src/ subdirectories
- Application runs lots of functions on requestAnimationFrame (or per animation frame) so:
- Reduce the amount of objects and functions created within methods
- Prefer caching variables to the module scope
- Do not use function based iterators (prefer native for loops, etc.)
## Architecture Patterns
- All shapes inherit from Path or Shape classes
- Use factory methods (makeRectangle, makeCircle) instead of direct constructors
- Effects (gradients, textures) are applied via fill/stroke properties
- Memory management: always call release() for complex objects
- Event binding: use bind/unbind pattern, avoid anonymous functions
- Factory methods automatically add objects to the scene
## Common Issues and Solutions
- When adding new shapes, ensure they extend the correct base class
- WebGL renderer has different capabilities than Canvas/SVG
- Always test across all three renderers for compatibility
- SVG imports may need manual matrix calculations
- Memory leaks: unbind events in cleanup using release() method
- Coordinate system: origin (0,0) at top-left, positive Y axis points down
## Testing Guidelines
- Open `tests/index.html` in browser for manual testing
- Test new features across Canvas, SVG, and WebGL renderers
- Check `tests/noWebGL.html` for fallback scenarios
- TypeScript compilation tests: Run `npx tsc --noEmit --skipLibCheck tests/typescript/index.ts` to verify TypeScript definitions work correctly
- Manual browser testing required - no automated test runner
## File Organization Rules
- New shapes go in `src/shapes/` and follow existing naming pattern
- Effects belong in `src/effects/`
- Utilities in `src/utils/` should be pure functions
- Export new classes in `src/two.js` main file
- **TypeScript definitions**: Create a `.d.ts` file alongside each source file (e.g., `src/vector.d.ts` next to `src/vector.js`)
- Each `.d.ts` file contains a `declare module 'two.js/src/...'` block matching the module path
- Import statements go at the END of the module declaration
- Main type exports are aggregated in `src/two.d.ts`
- Renderers are in `src/renderers/` - modify with caution
## Performance Guidelines
- Minimize object creation in animation loops
- Use object pooling for frequently created/destroyed objects
- Batch DOM updates when possible
- Prefer transform operations over position updates
- Use release() method to prevent memory leaks in long-running applications
## Integration Patterns
- Node.js: Requires canvas polyfill for headless rendering
- TypeScript: Import specific modules for tree-shaking
- Bundlers: ESM build recommended for modern bundlers
- Browser: UMD build for direct script inclusion
### Nota Bene
- All visual tests run in the browser via HTML files
- TypeScript tests verify that the type definitions work correctly by compiling sample code – this is work in progress
- Manual testing approach - no automated test runners or CI integration
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at inquiries+two.js@jono.fyi. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: CONTRIBUTING.md
================================================
## How to contribute to Two.js
#### **Do you have a question?**
* All questions answered by Two.js maintainers are in the [Issues](https://github.com/jonobr1/two.js/issues?q=label%3Aquestion) section of the project with the label question. Ensure the question was not already asked by checking there first.
* If you're unable to find a question that has been answered, [create one](https://github.com/jonobr1/two.js/issues/new?assignees=&labels=question&template=question.md&title=%5BQuestion%5D). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** in situ or on a third party site like [CodePen](http://codepen.io), [jsfiddle](http://jsfiddle.com), or [glitch](http://glitch.com). This helps us to better help you.
#### **Did you find a bug?**
* **Ensure the bug was not already reported** by searching on the project under [Issues](https://github.com/jonobr1/two.js/issues).
* If you're unable to find an open issue, [open a new one](https://github.com/jonobr1/two.js/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBug%5D). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** in situ or on a third party site like [CodePen](http://codepen.io), [jsfiddle](http://jsfiddle.com), or [glitch](http://glitch.com) demonstrating the issue.
#### **Did you write a patch that fixes a bug, add a new feature, or change an existing one?**
* Open a new GitHub pull request with the patch.
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
#### **Do you want to contribute to the Two.js documentation?**
* This is still in its infancy and if you're interested to help out, please send an email to [inquires@jono.fyi](mailto:inquiries@jono.fyi) with the subject "Two.js Documentation". In the body of your email please describe why or how you'd like to help.
Two.js is a volunteer effort, so we apologize in advance for any delays.
Thanks! For both taking the time to read this and contributing.
Much :heart: from the Two.js Team
---
This document is adapted from the [Ruby on Rails](https://github.com/rails/rails/blob/main/CONTRIBUTING.md#how-to-contribute-to-ruby-on-rails) project.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Two.js
[![NPM Package][npm]][npm-url]
[![Build Size][build-size]][build-size-url]
[![NPM Downloads][npm-downloads]][npmtrends-url]
A two-dimensional drawing api meant for modern browsers. It is renderer agnostic enabling the same api to render in multiple contexts: webgl, canvas2d, and svg.
[Home](http://two.js.org/) • [Releases](https://github.com/jonobr1/two.js/releases) • [Examples](http://two.js.org/examples/) • [Documentation](https://two.js.org/docs/two/) • [Changelog](https://github.com/jonobr1/two.js/tree/dev/wiki/changelog) • [Help](https://github.com/jonobr1/two.js/issues/new/choose)
## Usage
Download the latest [minified library](https://raw.github.com/jonobr1/two.js/dev/build/two.min.js) and include it in your html.
```html
<script src="js/two.min.js"></script>
```
It can also be installed via [npm](https://www.npmjs.com/package/two.js), Node Package Manager:
```js
npm install --save two.js
```
Alternatively see [how to build the library yourself](https://github.com/jonobr1/two.js#custom-build).
Here is boilerplate html in order to draw a spinning rectangle in two.js:
```html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="js/two.min.js"></script>
</head>
<body>
<script>
var two = new Two({
fullscreen: true,
autostart: true
}).appendTo(document.body);
var rect = two.makeRectangle(two.width / 2, two.height / 2, 50 ,50);
two.bind('update', function() {
rect.rotation += 0.001;
});
</script>
</body>
</html>
```
## Custom Build
Two.js uses [nodejs](http://nodejs.org/) in order to build source files. You'll first want to install that. Once installed open up a terminal and head to the repository folder:
```
cd ~/path-to-repo/two.js
npm install
```
This will give you a number of libraries that the development of Two.js relies on. If for instance you only use the `SVGRenderer` then you can really cut down on the file size by excluding the other renderers. To do this, modify `/utils/build.js` to only add the files you'd like. Then run:
```
node ./utils/build
```
And the resulting `/build/two.js` and `/build/two.min.js` will be updated to your specification.
---
### Using ES6 Imports
As of version `v0.7.5+` Two.js is compatible with EcmaScript 6 imports. This is typically employed in contemporary frameworks like [React](https://reactjs.org/) and [Angular](https://angularjs.org/) as well as bundling libraries like [webpack](https://webpack.js.org/), [esbuild](https://esbuild.github.io/), and [gulp](https://gulpjs.com/). This adaptation of the boilerplate can be found on [CodeSandbox](https://codesandbox.io/s/beautiful-wilbur-ygxbc?file=/src/App.js:0-664):
```jsx
import React, { useEffect, useRef } from "react";
import Two from "two.js";
export default function App() {
var domElement = useRef();
useEffect(setup, []);
function setup() {
var two = new Two({
fullscreen: true,
autostart: true
}).appendTo(domElement.current);
var rect = two.makeRectangle(two.width / 2, two.height / 2, 50, 50);
two.bind("update", update);
return unmount;
function unmount() {
two.unbind("update");
two.pause();
domElement.current.removeChild(two.renderer.domElement);
}
function update() {
rect.rotation += 0.001;
}
}
return <div ref={domElement} />;
}
```
In addition to importing, the published packages of Two.js include the specific modules. So, if necessary you can import specific modules from the source code and bundle / minify for yourself like so:
```javascript
import { Vector } from 'two.js/src/vector.js';
// In TypeScript environments leave out the ".js"
// when importing modules directly. e.g:
import { Vector } from 'two.js/src/vector';
```
_While useful, the main import of the `Two` namespace imports all modules. So, there isn't yet proper tree shaking implemented for the library, though it's on the roadmap._
### Running in Headless Environments
As of version `v0.7.x` Two.js can also run in a headless environment, namely running on the server with the help of a library called [Node Canvas](https://github.com/Automattic/node-canvas). We don't add Node Canvas to dependencies of Two.js because it's _not necessary_ to run it in the browser. However, it has all the hooks set up to run in a cloud environment. To get started follow the installation instructions on Automattic's [readme](https://github.com/Automattic/node-canvas#installation). After you've done that run:
```
npm install canvas
npm install two.js
```
Now in a JavaScript file set up your Two.js scenegraph and save out frames whenever you need to:
```javascript
var { createCanvas, Image } = require('canvas');
var Two = require('two.js')
var fs = require('fs');
var path = require('path');
var width = 800;
var height = 600;
var canvas = createCanvas(width, height);
Two.Utils.polyfill(canvas, Image);
var time = Date.now();
var two = new Two({
width: width,
height: height,
domElement: canvas
});
var rect = two.makeRectangle(width / 2, height / 2, 50, 50);
rect.fill = 'rgb(255, 100, 100)';
rect.noStroke();
two.render();
var settings = { compressionLevel: 3, filters: canvas.PNG_FILTER_NONE };
fs.writeFileSync(path.resolve(__dirname, './images/rectangle.png'), canvas.toBuffer('image/png', settings));
console.log('Finished rendering. Time took: ', Date.now() - time);
process.exit();
```
## Build Documentation
The [Two.js](http://two.js.org/) website is bundled with this repository. Relying on [Vuepress](https://vuepress.vuejs.org/) the repository generates a website based on numerous `README.md` files housed in the `wiki` directory. Use the following the node commands as follows:
```bash
npm run docs:generate // Generate README.md files for documentation from source code comments
npm run docs:dev // Creates a local server to generate all documentation
npm run docs:build // Builds out static site and associated files to wiki/.vuepress/dist
```
N.B: Vuepress is a legacy library and as such these commands rely on an older version of Node. Run `nvm use` if you get errors. If you don't use [Node Version Manager](https://github.com/nvm-sh/nvm) then see `.nvmrc` to install the correct version of node on your local machine.
## Change Log
Two.js has been in operation since 2012. For a full list of changes from its first alpha version built with [Three.js](http://threejs.org/) to the most up-to-date tweaks. Check out the wiki [here](./wiki/changelog).
---
#### And a big thank you to our sponsors who include:
[Epilogue Press](https://github.com/epiloguepress)
[npm]: https://img.shields.io/npm/v/two.js
[npm-url]: https://www.npmjs.com/package/two.js
[build-size]: https://badgen.net/bundlephobia/minzip/two.js
[build-size-url]: https://bundlephobia.com/result?p=two.js
[npm-downloads]: https://img.shields.io/npm/dt/two.js
[npmtrends-url]: https://www.npmtrends.com/two.js
================================================
FILE: SECURITY.md
================================================
# Security Policy
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
**You may submit the report in the following ways:**
- Github users can privately report security advisories directly [here](https://github.com/jonobr1/two.js/security/advisories/new)
- Send an email to [inquiries+two.js@jono.fyi](mailto:inquiries+two.js@jono.fyi).
**Please provide the following information in your report:**
- The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue
This project is maintained by volunteers on a reasonable-effort basis. As such, we ask that you give us 90 days to work on a fix before public exposure.
---
_Two.js conforms to this [Incident Response Plan](https://two.js.org/incident-response-plan) in moments of security risks._
================================================
FILE: build/two.js
================================================
/*
MIT License
Copyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
var Two = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
// src/two.js
var two_exports = {};
__export(two_exports, {
default: () => Two
});
// src/utils/canvas-polyfill.js
var CanvasPolyfill = {
/**
* @param {Image}
*/
Image: null,
/**
* @param {Boolean}
*/
isHeadless: false,
/**
*
* @param {canvas} elem - An element to spoof as a `<canvas />`.
* @param {String} [name] - An optional tag and node name to spoof. Defaults to `'canvas'`.
* @returns {canvas} - The same `elem` passed in the first argument with updated attributes needed to be used by Two.js.
* @description Adds attributes invoked by Two.js in order to execute and run correctly. This is used by headless environments.
*/
shim: function(elem, name) {
elem.tagName = elem.nodeName = name || "canvas";
elem.nodeType = 1;
elem.getAttribute = function(prop) {
return this[prop];
};
elem.setAttribute = function(prop, val) {
this[prop] = val;
return this;
};
return elem;
},
/**
* @name Two.Utils.polyfill
* @function
* @param {canvas} canvas - The instanced `Canvas` object provided by `node-canvas`.
* @param {Image} [Image] - The prototypical `Image` object provided by `node-canvas`. This is only necessary to pass if you're going to load bitmap imagery.
* @returns {canvas} Returns the instanced canvas object you passed from with additional attributes needed for Two.js.
* @description Convenience method for defining all the dependencies from the npm package `node-canvas`. See [node-canvas](https://github.com/Automattic/node-canvas) for additional information on setting up HTML5 `<canvas />` drawing in a node.js environment.
*/
polyfill: function(canvas3, Image3) {
CanvasPolyfill.shim(canvas3);
if (typeof Image3 !== "undefined") {
CanvasPolyfill.Image = Image3;
}
CanvasPolyfill.isHeadless = true;
return canvas3;
}
};
// src/utils/curves.js
var curves_exports = {};
__export(curves_exports, {
Curve: () => Curve,
getAnchorsFromArcData: () => getAnchorsFromArcData,
getComponentOnCubicBezier: () => getComponentOnCubicBezier,
getControlPoints: () => getControlPoints,
getCurveBoundingBox: () => getCurveBoundingBox,
getCurveFromPoints: () => getCurveFromPoints,
getCurveLength: () => getCurveLength,
getReflection: () => getReflection,
integrate: () => integrate,
subdivide: () => subdivide
});
// src/utils/math.js
var math_exports = {};
__export(math_exports, {
HALF_PI: () => HALF_PI,
NumArray: () => NumArray,
TWO_PI: () => TWO_PI,
decomposeMatrix: () => decomposeMatrix,
getComputedMatrix: () => getComputedMatrix,
getEffectiveStrokeWidth: () => getEffectiveStrokeWidth,
getPoT: () => getPoT,
lerp: () => lerp,
mod: () => mod,
setMatrix: () => setMatrix,
toFixed: () => toFixed
});
// src/utils/root.js
var root;
if (typeof window !== "undefined") {
root = window;
} else if (typeof global !== "undefined") {
root = global;
} else if (typeof self !== "undefined") {
root = self;
}
// src/utils/math.js
var Matrix;
var TWO_PI = Math.PI * 2;
var HALF_PI = Math.PI * 0.5;
function decomposeMatrix(matrix, b, c, d, e, f) {
let a;
if (arguments.length <= 1) {
a = matrix.a;
b = matrix.b;
c = matrix.c;
d = matrix.d;
e = matrix.e;
f = matrix.f;
} else {
a = matrix;
}
return {
translateX: e,
translateY: f,
scaleX: Math.sqrt(a * a + b * b),
scaleY: Math.sqrt(c * c + d * d),
rotation: 180 * Math.atan2(b, a) / Math.PI
};
}
function setMatrix(matrix) {
Matrix = matrix;
}
function getComputedMatrix(object, matrix) {
matrix = matrix && matrix.identity() || new Matrix();
let parent = object;
const matrices = [];
while (parent && parent._matrix) {
matrices.push(parent._matrix);
parent = parent.parent;
}
matrices.reverse();
for (let i = 0; i < matrices.length; i++) {
const m = matrices[i];
const e = m.elements;
matrix.multiply(
e[0],
e[1],
e[2],
e[3],
e[4],
e[5],
e[6],
e[7],
e[8]
);
}
return matrix;
}
function lerp(a, b, t) {
return t * (b - a) + a;
}
var pots = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
function getPoT(value) {
let i = 0;
while (pots[i] && pots[i] < value) {
i++;
}
return pots[i];
}
function mod(v, l) {
while (v < 0) {
v += l;
}
return v % l;
}
var NumArray = root.Float32Array || Array;
var floor = Math.floor;
function toFixed(v) {
return floor(v * 1e6) / 1e6;
}
function getEffectiveStrokeWidth(object, worldMatrix) {
const linewidth = object._linewidth;
if (object.strokeAttenuation) {
return linewidth;
}
if (!worldMatrix) {
worldMatrix = object.worldMatrix || getComputedMatrix(object);
}
const decomposed = decomposeMatrix(
worldMatrix.elements[0],
worldMatrix.elements[3],
worldMatrix.elements[1],
worldMatrix.elements[4],
worldMatrix.elements[2],
worldMatrix.elements[5]
);
const scale = Math.max(Math.abs(decomposed.scaleX), Math.abs(decomposed.scaleY));
return scale > 0 ? linewidth / scale : linewidth;
}
// src/utils/path-commands.js
var Commands = {
move: "M",
line: "L",
curve: "C",
arc: "A",
close: "Z"
};
// src/events.js
var Events = class {
_events = {};
_bound = false;
constructor() {
}
/**
* @name Two.Events#addEventListener
* @function
* @param {String} [name] - The name of the event to bind a function to.
* @param {Function} [handler] - The function to be invoked when the event is dispatched.
* @description Call to add a listener to a specific event name.
*/
addEventListener(name, handler) {
const list = this._events[name] || (this._events[name] = []);
list.push(handler);
this._bound = true;
return this;
}
/**
* @name Two.Events#on
* @function
* @description Alias for {@link Two.Events#addEventListener}.
*/
on() {
return this.addEventListener.apply(this, arguments);
}
/**
* @name Two.Events#bind
* @function
* @description Alias for {@link Two.Events#addEventListener}.
*/
bind() {
return this.addEventListener.apply(this, arguments);
}
/**
* @name Two.Events#removeEventListener
* @function
* @param {String} [name] - The name of the event intended to be removed.
* @param {Function} [handler] - The handler intended to be removed.
* @description Call to remove listeners from a specific event. If only `name` is passed then all the handlers attached to that `name` will be removed. If no arguments are passed then all handlers for every event on the obejct are removed.
*/
removeEventListener(name, handler) {
if (!this._events) {
return this;
}
if (!name && !handler) {
this._events = {};
this._bound = false;
return this;
}
const names = name ? [name] : Object.keys(this._events);
for (let i = 0, l = names.length; i < l; i++) {
name = names[i];
let list = this._events[name];
if (list) {
let events = [];
if (handler) {
for (let j = 0, k = list.length; j < k; j++) {
let e = list[j];
e = e.handler ? e.handler : e;
if (handler !== e) {
events.push(e);
}
}
}
this._events[name] = events;
}
}
return this;
}
/**
* @name Two.Events#off
* @function
* @description Alias for {@link Two.Events#removeEventListener}.
*/
off() {
return this.removeEventListener.apply(this, arguments);
}
/**
* @name Two.Events#unbind
* @function
* @description Alias for {@link Two.Events#removeEventListener}.
*/
unbind() {
return this.removeEventListener.apply(this, arguments);
}
/**
* @name Two.Events#dispatchEvent
* @function
* @param {String} name - The name of the event to dispatch.
* @param args - Anything can be passed after the name and those will be passed on to handlers attached to the event in the order they are passed.
* @description Call to trigger a custom event. Any additional arguments passed after the name will be passed along to the attached handlers.
*/
dispatchEvent(name) {
if (!this._events) {
return this;
}
const args = Array.prototype.slice.call(arguments, 1);
const events = this._events[name];
if (events) {
for (let i = 0; i < events.length; i++) {
events[i].call(this, ...args);
}
}
return this;
}
trigger() {
return this.dispatchEvent.apply(this, arguments);
}
listen(obj, name, handler) {
const scope = this;
if (obj) {
e.obj = obj;
e.name = name;
e.handler = handler;
obj.on(name, e);
}
function e() {
handler.apply(scope, arguments);
}
return scope;
}
ignore(obj, name, handler) {
obj.off(name, handler);
return this;
}
/**
* @name Two.Events.Types
* @property {Object} - Object of different types of Two.js specific events.
*/
static Types = {
play: "play",
pause: "pause",
update: "update",
render: "render",
resize: "resize",
change: "change",
remove: "remove",
insert: "insert",
order: "order",
load: "load"
};
static Methods = [
"addEventListener",
"on",
"removeEventListener",
"off",
"unbind",
"dispatchEvent",
"trigger",
"listen",
"ignore"
];
};
// src/vector.js
var proto = {
x: {
enumerable: true,
get: function() {
return this._x;
},
set: function(v) {
if (this._x !== v) {
this._x = v;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
y: {
enumerable: true,
get: function() {
return this._y;
},
set: function(v) {
if (this._y !== v) {
this._y = v;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
}
};
var Vector = class _Vector extends Events {
/**
* @name Two.Vector#_x
* @private
*/
_x = 0;
/**
* @name Two.Vector#_y
* @private
*/
_y = 0;
constructor(x = 0, y = 0) {
super();
for (let prop in proto) {
Object.defineProperty(this, prop, proto[prop]);
}
this.x = x;
this.y = y;
}
/**
* @name Two.Vector.zero
* @readonly
* @property {Two.Vector} - Handy reference to a vector with component values 0, 0 at all times.
*/
static zero = new _Vector();
/**
* @name Two.Vector.left
* @readonly
* @property {Two.Vector} - Handy reference to a vector with component values -1, 0 at all times.
*/
static left = new _Vector(-1, 0);
/**
* @name Two.Vector.right
* @readonly
* @property {Two.Vector} - Handy reference to a vector with component values 1, 0 at all times.
*/
static right = new _Vector(1, 0);
/**
* @name Two.Vector.up
* @readonly
* @property {Two.Vector} - Handy reference to a vector with component values 0, -1 at all times.
*/
static up = new _Vector(0, -1);
/**
* @name Two.Vector.down
* @readonly
* @property {Two.Vector} - Handy reference to a vector with component values 0, 1 at all times.
*/
static down = new _Vector(0, 1);
/**
* @name Two.Vector.add
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Two.Vector}
* @description Add two vectors together.
*/
static add(v1, v2) {
return new _Vector(v1.x + v2.x, v1.y + v2.y);
}
/**
* @name Two.Vector.sub
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Two.Vector}
* @description Subtract two vectors: `v2` from `v1`.
*/
static sub(v1, v2) {
return new _Vector(v1.x - v2.x, v1.y - v2.y);
}
/**
* @name Two.Vector.subtract
* @function
* @description Alias for {@link Two.Vector.sub}.
*/
static subtract(v1, v2) {
return _Vector.sub(v1, v2);
}
/**
* @name Two.Vector.ratioBetween
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Number} The ratio betwen two points `v1` and `v2`.
*/
static ratioBetween(v1, v2) {
return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length());
}
/**
* @name Two.Vector.angleBetween
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Number} The angle between points `v1` and `v2`.
*/
static angleBetween(v1, v2) {
if (arguments.length >= 4) {
const dx2 = arguments[0] - arguments[2];
const dy2 = arguments[1] - arguments[3];
return Math.atan2(dy2, dx2);
}
const dx = v1.x - v2.x;
const dy = v1.y - v2.y;
return Math.atan2(dy, dx);
}
/**
* @name Two.Vector.distanceBetween
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Number} The distance between points `v1` and `v2`. Distance is always positive.
*/
static distanceBetween(v1, v2) {
return Math.sqrt(_Vector.distanceBetweenSquared(v1, v2));
}
/**
* @name Two.Vector.distanceBetweenSquared
* @function
* @param {Two.Vector} v1 - First {@link Two.Vector}
* @param {Two.Vector} v2 - Second {@link Two.Vector}
* @returns {Number} The squared distance between points `v1` and `v2`.
*/
static distanceBetweenSquared(v1, v2) {
const dx = v1.x - v2.x;
const dy = v1.y - v2.y;
return dx * dx + dy * dy;
}
//
/**
* @name Two.Vector#set
* @function
* @param {number} x - Value of `x` component
* @param {number} y - Value of `y` component
*/
set(x, y) {
this.x = x;
this.y = y;
return this;
}
/**
* @name Two.Vector#copy
* @function
* @param {Two.Vector} v - The {@link Two.Vector} to copy
* @description Copy the `x` / `y` components of another object {@link Two.Vector}.
*/
copy(v) {
this.x = v.x;
this.y = v.y;
return this;
}
/**
* @name Two.Vector#clear
* @function
* @description Set the `x` / `y` component values of the vector to zero.
*/
clear() {
this.x = 0;
this.y = 0;
return this;
}
/**
* @name Two.Vector#clone
* @function
* @description Create a new vector and copy the existing values onto the newly created instance.
* @return {Two.Vector}
*/
clone() {
return new _Vector(this.x, this.y);
}
/**
* @name Two.Vector#add
* @function
* @param {Two.Vector} v - The {@link Two.Vector} to add
* @description Add an object with `x` / `y` component values to the instance.
* @overloaded
*/
/**
* @name Two.Vector#add
* @function
* @param {Number} n - Number to add
* @description Add the **same** number to both `x` / `y` component values of the instance.
* @overloaded
*/
/**
* @name Two.Vector#add
* @function
* @param {Number} x - Number to add to `x` component
* @param {Number} y - Number to add to `y` component
* @description Add `x` / `y` values to their respective component value on the instance.
* @overloaded
*/
add(x, y) {
if (arguments.length <= 0) {
return this;
} else if (arguments.length <= 1) {
if (typeof x === "number") {
this.x += x;
this.y += x;
} else if (x && typeof x.x === "number" && typeof x.y === "number") {
this.x += x.x;
this.y += x.y;
}
} else {
this.x += x;
this.y += y;
}
return this;
}
/**
* @name Two.Vector#addSelf
* @function
* @description Alias for {@link Two.Vector.add}.
*/
addSelf(v) {
return this.add.apply(this, arguments);
}
/**
* @name Two.Vector#sub
* @function
* @param {Two.Vector} v - The amount as a {@link Two.Vector} to subtract
* @description Subtract an object with `x` / `y` component values to the instance.
* @overloaded
*/
/**
* @name Two.Vector#sub
* @function
* @param {Number} n - Number to subtract
* @description Subtract the **same** number to both `x` / `y` component values of the instance.
* @overloaded
*/
/**
* @name Two.Vector#sub
* @function
* @param {Number} x - Number to subtract from `x` component
* @param {Number} y - Number to subtract from `y` component
* @description Subtract `x` / `y` values to their respective component value on the instance.
* @overloaded
*/
sub(x, y) {
if (arguments.length <= 0) {
return this;
} else if (arguments.length <= 1) {
if (typeof x === "number") {
this.x -= x;
this.y -= x;
} else if (x && typeof x.x === "number" && typeof x.y === "number") {
this.x -= x.x;
this.y -= x.y;
}
} else {
this.x -= x;
this.y -= y;
}
return this;
}
/**
* @name Two.Vector#subtract
* @function
* @description Alias for {@link Two.Vector.sub}.
*/
subtract() {
return this.sub.apply(this, arguments);
}
/**
* @name Two.Vector#subSelf
* @function
* @description Alias for {@link Two.Vector.sub}.
*/
subSelf(v) {
return this.sub.apply(this, arguments);
}
/**
* @name Two.Vector#subtractSelf
* @function
* @description Alias for {@link Two.Vector.sub}.
*/
subtractSelf(v) {
return this.sub.apply(this, arguments);
}
/**
* @name Two.Vector#multiply
* @function
* @param {Two.Vector} v - The {@link Two.Vector} to multiply
* @description Multiply an object with `x` / `y` component values to the instance.
* @overloaded
*/
/**
* @name Two.Vector#multiply
* @function
* @param {Number} n - The number to multiply
* @description Multiply the **same** number to both x / y component values of the instance.
* @overloaded
*/
/**
* @name Two.Vector#multiply
* @function
* @param {Number} x - The number to multiply to `x` component
* @param {Number} y - The number to multiply to `y` component
* @description Multiply `x` / `y` values to their respective component value on the instance.
* @overloaded
*/
multiply(x, y) {
if (arguments.length <= 0) {
return this;
} else if (arguments.length <= 1) {
if (typeof x === "number") {
this.x *= x;
this.y *= x;
} else if (x && typeof x.x === "number" && typeof x.y === "number") {
this.x *= x.x;
this.y *= x.y;
}
} else {
this.x *= x;
this.y *= y;
}
return this;
}
/**
* @name Two.Vector#multiplySelf
* @function
* @description Alias for {@link Two.Vector.multiply}.
*/
multiplySelf(v) {
return this.multiply.apply(this, arguments);
}
/**
* @name Two.Vector#multiplyScalar
* @function
* @param {Number} s - The scalar to multiply by.
* @description Mulitiply the vector by a single number. Shorthand to call {@link Two.Vector#multiply} directly.
*/
multiplyScalar(s) {
return this.multiply(s);
}
/**
* @name Two.Vector#divide
* @function
* @param {Two.Vector} v - The {@link Two.Vector} to divide
* @description Divide an object with `x` / `y` component values to the instance.
* @overloaded
*/
/**
* @name Two.Vector#divide
* @function
* @param {Number} n - The number to divide
* @description Divide the **same** number to both x / y component values of the instance.
* @overloaded
*/
/**
* @name Two.Vector#divide
* @function
* @param {Number} x - The number to divide on the `x` component
* @param {Number} y - The number to divide on the `y` component
* @description Divide `x` / `y` values to their respective component value on the instance.
* @overloaded
*/
divide(x, y) {
if (arguments.length <= 0) {
return this;
} else if (arguments.length <= 1) {
if (typeof x === "number") {
this.x /= x;
this.y /= x;
} else if (x && typeof x.x === "number" && typeof x.y === "number") {
this.x /= x.x;
this.y /= x.y;
}
} else {
this.x /= x;
this.y /= y;
}
if (isNaN(this.x)) {
this.x = 0;
}
if (isNaN(this.y)) {
this.y = 0;
}
return this;
}
/**
* @name Two.Vector#divideSelf
* @function
* @description Alias for {@link Two.Vector.divide}.
*/
divideSelf(v) {
return this.divide.apply(this, arguments);
}
/**
* @name Two.Vector#divideScalar
* @function
* @param {Number} s - The scalar to divide by.
* @description Divide the vector by a single number. Shorthand to call {@link Two.Vector#divide} directly.
*/
divideScalar(s) {
return this.divide(s);
}
/**
* @name Two.Vector#negate
* @function
* @description Invert each component's sign value.
*/
negate() {
return this.multiply(-1);
}
/**
* @name Two.Vector#dot
* @function
* @returns {Number}
* @description Get the [dot product](https://en.wikipedia.org/wiki/Dot_product) of the vector.
*/
dot(v) {
return this.x * v.x + this.y * v.y;
}
/**
* @name Two.Vector#length
* @function
* @returns {Number}
* @description Get the length of a vector.
*/
length() {
return Math.sqrt(this.lengthSquared());
}
/**
* @name Two.Vector#lengthSquared
* @function
* @returns {Number}
* @description Get the length of the vector to the power of two. Widely used as less expensive than {@link Two.Vector#length} because it isn't square-rooting any numbers.
*/
lengthSquared() {
return this.x * this.x + this.y * this.y;
}
/**
* @name Two.Vector#normalize
* @function
* @description Normalize the vector from negative one to one.
*/
normalize() {
return this.divideScalar(this.length());
}
/**
* @name Two.Vector#distanceTo
* @function
* @returns {Number}
* @description Get the distance between two vectors.
*/
distanceTo(v) {
return Math.sqrt(this.distanceToSquared(v));
}
/**
* @name Two.Vector#distanceToSquared
* @function
* @returns {Number}
* @description Get the distance between two vectors to the power of two. Widely used as less expensive than {@link Two.Vector#distanceTo} because it isn't square-rooting any numbers.
*/
distanceToSquared(v) {
const dx = this.x - v.x;
const dy = this.y - v.y;
return dx * dx + dy * dy;
}
/**
* @name Two.Vector#setLength
* @function
* @param {Number} l - length to set vector to.
* @description Set the length of a vector.
*/
setLength(l) {
return this.normalize().multiplyScalar(l);
}
/**
* @name Two.Vector#equals
* @function
* @param {Two.Vector} v - The vector to compare against.
* @param {Number} [eps=0.0001] - An options epsilon for precision.
* @returns {Boolean}
* @description Qualify if one vector roughly equal another. With a margin of error defined by epsilon.
*/
equals(v, eps) {
eps = typeof eps === "undefined" ? 1e-4 : eps;
return this.distanceTo(v) < eps;
}
/**
* @name Two.Vector#lerp
* @function
* @param {Two.Vector} v - The destination vector to step towards.
* @param {Number} t - The zero to one value of how close the current vector gets to the destination vector.
* @description Linear interpolate one vector to another by an amount `t` defined as a zero to one number.
* @see [Matt DesLauriers](https://twitter.com/mattdesl/status/1031305279227478016) has a good thread about this.
*/
lerp(v, t) {
const x = (v.x - this.x) * t + this.x;
const y = (v.y - this.y) * t + this.y;
return this.set(x, y);
}
/**
* @name Two.Vector#isZero
* @function
* @param {Number} [eps=0.0001] - Optional precision amount to check against.
* @returns {Boolean}
* @description Check to see if vector is roughly zero, based on the `epsilon` precision value.
*/
isZero(eps) {
eps = typeof eps === "undefined" ? 1e-4 : eps;
return this.length() < eps;
}
/**
* @name Two.Vector#toString
* @function
* @returns {String}
* @description Return a comma-separated string of x, y value. Great for storing in a database.
*/
toString() {
return this.x + ", " + this.y;
}
/**
* @name Two.Vector#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the vector.
*/
toObject() {
return { x: toFixed(this.x), y: toFixed(this.y) };
}
/**
* @name Two.Vector#rotate
* @function
* @param {Number} radians - The amount to rotate the vector by in radians.
* @description Rotate a vector.
*/
rotate(radians) {
const x = this.x;
const y = this.y;
const cos7 = Math.cos(radians);
const sin7 = Math.sin(radians);
this.x = x * cos7 - y * sin7;
this.y = x * sin7 + y * cos7;
return this;
}
};
// src/anchor.js
var Anchor = class _Anchor extends Vector {
controls = {
left: new Vector(),
right: new Vector()
};
_command = Commands.move;
_relative = true;
_rx = 0;
_ry = 0;
_xAxisRotation = 0;
_largeArcFlag = 0;
_sweepFlag = 1;
constructor(x = 0, y = 0, ax = 0, ay = 0, bx = 0, by = 0, command = Commands.move) {
super(x, y);
for (let prop in proto2) {
Object.defineProperty(this, prop, proto2[prop]);
}
this.command = command;
this.relative = true;
const broadcast = _Anchor.makeBroadcast(this);
this.controls.left.set(ax, ay).addEventListener(Events.Types.change, broadcast);
this.controls.right.set(bx, by).addEventListener(Events.Types.change, broadcast);
}
static makeBroadcast(scope) {
return broadcast;
function broadcast() {
if (scope._bound) {
scope.dispatchEvent(Events.Types.change);
}
}
}
/**
* @name Two.Anchor.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Anchor} to create a new instance
* @returns {Two.Anchor}
* @description Create a new {@link Two.Anchor} from an object notation of a {@link Two.Anchor}.
* @nota-bene Works in conjunction with {@link Two.Anchor#toObject}
*/
static fromObject(obj) {
return new _Anchor().copy(obj);
}
/**
* @name Two.Anchor#copy
* @function
* @param {Two.Anchor} v - The anchor to apply values to.
* @description Copy the properties of one {@link Two.Anchor} onto another.
*/
copy(v) {
this.x = v.x;
this.y = v.y;
if (typeof v.command === "string") {
this.command = v.command;
}
if (v.controls) {
if (v.controls.left) {
this.controls.left.copy(v.controls.left);
}
if (v.controls.right) {
this.controls.right.copy(v.controls.right);
}
}
if (typeof v.relative === "boolean") {
this.relative = v.relative;
}
if (typeof v.rx === "number") {
this.rx = v.rx;
}
if (typeof v.ry === "number") {
this.ry = v.ry;
}
if (typeof v.xAxisRotation === "number") {
this.xAxisRotation = v.xAxisRotation;
}
if (typeof v.largeArcFlag === "number") {
this.largeArcFlag = v.largeArcFlag;
}
if (typeof v.sweepFlag === "number") {
this.sweepFlag = v.sweepFlag;
}
return this;
}
/**
* @name Two.Anchor#clone
* @function
* @returns {Two.Anchor}
* @description Create a new {@link Two.Anchor}, set all its values to the current instance and return it for use.
*/
clone() {
return new _Anchor().copy(this);
}
/**
* @name Two.Anchor#toObject
* @function
* @returns {Object} - An object with properties filled out to mirror {@link Two.Anchor}.
* @description Create a JSON compatible plain object of the current instance. Intended for use with storing values in a database.
* @nota-bene Works in conjunction with {@link Two.Anchor.fromObject}
*/
toObject() {
return {
x: toFixed(this.x),
y: toFixed(this.y),
command: this.command,
relative: this.relative,
controls: {
left: this.controls.left.toObject(),
right: this.controls.right.toObject()
},
rx: toFixed(this.rx),
ry: toFixed(this.ry),
xAxisRotation: toFixed(this.xAxisRotation),
largeArcFlag: toFixed(this.largeArcFlag),
sweepFlag: toFixed(this.sweepFlag)
};
}
/**
* @name Two.Anchor#toString
* @function
* @returns {String} - A String with comma-separated values reflecting the various values on the current instance.
* @description Create a string form of the current instance. Intended for use with storing values in a database. This is lighter to store than the JSON compatible {@link Two.Anchor#toObject}.
*/
toString() {
return JSON.stringify(this.toObject());
}
};
var proto2 = {
command: {
enumerable: true,
get: function() {
return this._command;
},
set: function(command) {
if (this._command !== command) {
this._command = command;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
relative: {
enumerable: true,
get: function() {
return this._relative;
},
set: function(relative) {
if (this._relative !== !!relative) {
this._relative = !!relative;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
rx: {
enumerable: true,
get: function() {
return this._rx;
},
set: function(rx) {
if (this._rx !== rx) {
this._rx = rx;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
ry: {
enumerable: true,
get: function() {
return this._ry;
},
set: function(ry) {
if (this._ry !== ry) {
this._ry = ry;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
xAxisRotation: {
enumerable: true,
get: function() {
return this._xAxisRotation;
},
set: function(xAxisRotation) {
if (this._xAxisRotation !== xAxisRotation) {
this._xAxisRotation = xAxisRotation;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
largeArcFlag: {
enumerable: true,
get: function() {
return this._largeArcFlag;
},
set: function(largeArcFlag) {
if (this._largeArcFlag !== largeArcFlag) {
this._largeArcFlag = largeArcFlag;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
},
sweepFlag: {
get: function() {
return this._sweepFlag;
},
set: function(sweepFlag) {
if (this._sweepFlag !== sweepFlag) {
this._sweepFlag = sweepFlag;
if (this._bound) {
this.dispatchEvent(Events.Types.change);
}
}
}
}
};
// src/constants.js
var count = 0;
var Constants = {
/**
* @name Two.NextFrameId
* @property {Number}
* @description The id of the next `requestAnimationFrame` function. Used to control the (or cancel) the default behavior of Two.js animation loops.
*/
NextFrameId: null,
// Primitive
/**
* @name Two.Types
* @property {Object} - The different rendering types available in the library.
*/
Types: {
webgl: "WebGLRenderer",
svg: "SVGRenderer",
canvas: "CanvasRenderer"
},
/**
* @name Two.Version
* @property {String} - The current working version of the library.
*/
Version: "v0.8.23",
/**
* @name Two.PublishDate
* @property {String} - The automatically generated publish date in the build process to verify version release candidates.
*/
PublishDate: "2026-01-05T18:28:31.207Z",
/**
* @name Two.Identifier
* @property {String} - String prefix for all Two.js object's ids. This trickles down to SVG ids.
*/
Identifier: "two-",
/**
* @name Two.Resolution
* @property {Number} - Default amount of vertices to be used for interpreting Arcs and ArcSegments.
*/
Resolution: 12,
/**
* @name Two.AutoCalculateImportedMatrices
* @property {Boolean} - When importing SVGs through the {@link Two#interpret} and {@link Two#load}, this boolean determines whether Two.js infers and then overrides the exact transformation matrix of the reference SVG.
* @nota-bene `false` copies the exact transformation matrix values, but also sets the path's `matrix.manual = true`.
*/
AutoCalculateImportedMatrices: true,
/**
* @name Two.Instances
* @property {Two[]} - Registered list of all Two.js instances in the current session.
*/
Instances: [],
/**
* @function Two.uniqueId
* @description Simple method to access an incrementing value. Used for `id` allocation on all Two.js objects.
* @returns {Number} Ever increasing Number.
*/
uniqueId: function() {
return count++;
}
};
// src/utils/curves.js
var Curve = {
CollinearityEpsilon: Math.pow(10, -30),
RecursionLimit: 16,
CuspLimit: 0,
Tolerance: {
distance: 0.25,
angle: 0,
epsilon: Number.EPSILON
},
// Lookup tables for abscissas and weights with values for n = 2 .. 16.
// As values are symmetric, only store half of them and adapt algorithm
// to factor in symmetry.
abscissas: [
[0.5773502691896],
[0, 0.7745966692415],
[0.3399810435849, 0.8611363115941],
[0, 0.5384693101057, 0.9061798459387],
[0.2386191860832, 0.6612093864663, 0.9324695142032],
[0, 0.4058451513774, 0.7415311855994, 0.9491079123428],
[0.1834346424956, 0.5255324099163, 0.7966664774136, 0.9602898564975],
[0, 0.3242534234038, 0.6133714327006, 0.8360311073266, 0.9681602395076],
[
0.1488743389816,
0.4333953941292,
0.679409568299,
0.865063366689,
0.9739065285172
],
[
0,
0.2695431559523,
0.5190961292068,
0.730152005574,
0.8870625997681,
0.9782286581461
],
[
0.1252334085115,
0.3678314989982,
0.5873179542866,
0.7699026741943,
0.9041172563705,
0.9815606342467
],
[
0,
0.2304583159551,
0.4484927510364,
0.6423493394403,
0.8015780907333,
0.917598399223,
0.9841830547186
],
[
0.1080549487073,
0.3191123689279,
0.5152486363582,
0.6872929048117,
0.8272013150698,
0.9284348836636,
0.9862838086968
],
[
0,
0.2011940939974,
0.3941513470776,
0.5709721726085,
0.7244177313602,
0.8482065834104,
0.9372733924007,
0.9879925180205
],
[
0.0950125098376,
0.2816035507793,
0.4580167776572,
0.6178762444026,
0.755404408355,
0.8656312023878,
0.9445750230732,
0.9894009349916
]
],
weights: [
[1],
[0.8888888888889, 0.5555555555556],
[0.6521451548625, 0.3478548451375],
[0.5688888888889, 0.4786286704994, 0.2369268850562],
[0.4679139345727, 0.3607615730481, 0.1713244923792],
[0.4179591836735, 0.3818300505051, 0.2797053914893, 0.1294849661689],
[0.3626837833784, 0.3137066458779, 0.2223810344534, 0.1012285362904],
[
0.3302393550013,
0.31234707704,
0.2606106964029,
0.1806481606949,
0.0812743883616
],
[
0.2955242247148,
0.26926671931,
0.219086362516,
0.1494513491506,
0.0666713443087
],
[
0.2729250867779,
0.2628045445102,
0.233193764592,
0.1862902109277,
0.1255803694649,
0.0556685671162
],
[
0.2491470458134,
0.2334925365384,
0.2031674267231,
0.1600783285433,
0.1069393259953,
0.0471753363865
],
[
0.2325515532309,
0.2262831802629,
0.2078160475369,
0.1781459807619,
0.1388735102198,
0.0921214998377,
0.0404840047653
],
[
0.2152638534632,
0.2051984637213,
0.1855383974779,
0.1572031671582,
0.1215185706879,
0.0801580871598,
0.0351194603318
],
[
0.2025782419256,
0.1984314853271,
0.1861610000156,
0.166269205817,
0.1395706779262,
0.1071592204672,
0.0703660474881,
0.0307532419961
],
[
0.1894506104551,
0.1826034150449,
0.169156519395,
0.1495959888166,
0.1246289712555,
0.0951585116825,
0.0622535239386,
0.0271524594118
]
]
};
function getComponentOnCubicBezier(t, a, b, c, d) {
const k = 1 - t;
return k * k * k * a + 3 * k * k * t * b + 3 * k * t * t * c + t * t * t * d;
}
function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
limit = limit || Curve.RecursionLimit;
const amount = limit + 1;
if (Math.abs(x1 - x4) < 1e-3 && Math.abs(y1 - y4) < 1e-3) {
return [new Anchor(x4, y4)];
}
const result = [];
for (let i = 0; i < amount; i++) {
const t = i / amount;
const x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
const y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
result.push(new Anchor(x, y));
}
return result;
}
function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) {
const dx = x4 - x1;
const dy = y4 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
const ax = 9 * (x2 - x3) + 3 * (x4 - x1), bx = 6 * (x1 + x3) - 12 * x2, cx = 3 * (x2 - x1), ay = 9 * (y2 - y3) + 3 * (y4 - y1), by = 6 * (y1 + y3) - 12 * y2, cy = 3 * (y2 - y1);
function integrand(t) {
const dx = (ax * t + bx) * t + cx, dy = (ay * t + by) * t + cy;
return Math.sqrt(dx * dx + dy * dy);
}
return integrate(integrand, 0, 1, limit || Curve.RecursionLimit);
}
function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) {
const tvalues = [];
const bounds = [[], []];
let a, b, c, t, t1, t2, b2ac, sqrtb2ac;
for (let i = 0; i < 2; ++i) {
if (i === 0) {
b = 6 * x1 - 12 * x2 + 6 * x3;
a = -3 * x1 + 9 * x2 - 9 * x3 + 3 * x4;
c = 3 * x2 - 3 * x1;
} else {
b = 6 * y1 - 12 * y2 + 6 * y3;
a = -3 * y1 + 9 * y2 - 9 * y3 + 3 * y4;
c = 3 * y2 - 3 * y1;
}
if (Math.abs(a) < 1e-3) {
if (Math.abs(b) < 1e-3) {
continue;
}
t = -c / b;
if (0 < t && t < 1) {
tvalues.push(t);
}
continue;
}
b2ac = b * b - 4 * c * a;
sqrtb2ac = Math.sqrt(b2ac);
if (b2ac < 0) {
continue;
}
t1 = (-b + sqrtb2ac) / (2 * a);
if (0 < t1 && t1 < 1) {
tvalues.push(t1);
}
t2 = (-b - sqrtb2ac) / (2 * a);
if (0 < t2 && t2 < 1) {
tvalues.push(t2);
}
}
let j = tvalues.length;
let jlen = j;
let mt;
while (j--) {
t = tvalues[j];
mt = 1 - t;
bounds[0][j] = mt * mt * mt * x1 + 3 * mt * mt * t * x2 + 3 * mt * t * t * x3 + t * t * t * x4;
bounds[1][j] = mt * mt * mt * y1 + 3 * mt * mt * t * y2 + 3 * mt * t * t * y3 + t * t * t * y4;
}
bounds[0][jlen] = x1;
bounds[1][jlen] = y1;
bounds[0][jlen + 1] = x4;
bounds[1][jlen + 1] = y4;
bounds[0].length = bounds[1].length = jlen + 2;
return {
min: { x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1]) },
max: { x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1]) }
};
}
function integrate(f, a, b, n) {
let x = Curve.abscissas[n - 2], w = Curve.weights[n - 2], A = 0.5 * (b - a), B = A + a, i = 0, m = n + 1 >> 1, sum = n & 1 ? w[i++] * f(B) : 0;
while (i < m) {
const Ax = A * x[i];
sum += w[i++] * (f(B + Ax) + f(B - Ax));
}
return A * sum;
}
function getCurveFromPoints(points, closed2) {
const l = points.length, last = l - 1;
for (let i = 0; i < l; i++) {
const point = points[i];
const prev = closed2 ? mod(i - 1, l) : Math.max(i - 1, 0);
const next = closed2 ? mod(i + 1, l) : Math.min(i + 1, last);
const a = points[prev];
const b = point;
const c = points[next];
getControlPoints(a, b, c);
b.command = i === 0 ? Commands.move : Commands.curve;
}
}
function getControlPoints(a, b, c) {
const a1 = Vector.angleBetween(a, b);
const a2 = Vector.angleBetween(c, b);
let d1 = Vector.distanceBetween(a, b);
let d2 = Vector.distanceBetween(c, b);
let mid = (a1 + a2) / 2;
if (d1 < 1e-3 || d2 < 1e-3) {
if (typeof b.relative === "boolean" && !b.relative) {
b.controls.left.copy(b);
b.controls.right.copy(b);
}
return b;
}
d1 *= 0.33;
d2 *= 0.33;
if (a2 < a1) {
mid += HALF_PI;
} else {
mid -= HALF_PI;
}
b.controls.left.x = Math.cos(mid) * d1;
b.controls.left.y = Math.sin(mid) * d1;
mid -= Math.PI;
b.controls.right.x = Math.cos(mid) * d2;
b.controls.right.y = Math.sin(mid) * d2;
if (typeof b.relative === "boolean" && !b.relative) {
b.controls.left.x += b.x;
b.controls.left.y += b.y;
b.controls.right.x += b.x;
b.controls.right.y += b.y;
}
return b;
}
function getReflection(a, b, relative) {
return new Vector(
2 * a.x - (b.x + a.x) - (relative ? a.x : 0),
2 * a.y - (b.y + a.y) - (relative ? a.y : 0)
);
}
function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, ccw) {
const resolution = Constants.Resolution;
const anchors = [];
for (let i = 0; i < resolution; i++) {
let pct = (i + 1) / resolution;
if (ccw) {
pct = 1 - pct;
}
const theta = pct * td + ts;
const x = rx * Math.cos(theta);
const y = ry * Math.sin(theta);
const anchor2 = new Anchor(x, y);
anchor2.command = Commands.line;
anchors.push(anchor2);
}
}
// src/utils/underscore.js
var slice = Array.prototype.slice;
function isArrayLike(collection) {
if (collection === null || collection === void 0) return false;
const length = collection.length;
return typeof length == "number" && length >= 0 && length < 4294967296;
}
var _ = {
isNaN: function(obj) {
return typeof obj === "number" && obj !== +obj;
},
isElement: function(obj) {
return !!(obj && obj.nodeType === 1);
},
isObject: function(obj) {
const type = typeof obj;
return type === "function" || type === "object" && !!obj;
},
isFunction: function(obj) {
return typeof obj === "function";
},
extend: function(base) {
const sources = slice.call(arguments, 1);
for (let i = 0; i < sources.length; i++) {
const obj = sources[i];
for (let k in obj) {
base[k] = obj[k];
}
}
return base;
},
defaults: function(base) {
const sources = slice.call(arguments, 1);
for (let i = 0; i < sources.length; i++) {
const obj = sources[i];
for (let k in obj) {
if (base[k] === void 0) {
base[k] = obj[k];
}
}
}
return base;
},
each: function(obj, iteratee, context) {
const ctx = context || this;
const keys = !isArrayLike(obj) && Object.keys(obj);
const length = (keys || obj).length;
for (let i = 0; i < length; i++) {
const k = keys ? keys[i] : i;
iteratee.call(ctx, obj[k], k, obj);
}
return obj;
},
/**
* @name Two.Utils.performance
* @property {Date} - A special `Date` like object to get the current millis of the session. Used internally to calculate time between frames.
* e.g: `Utils.performance.now() // milliseconds since epoch`
*/
performance: root.performance && root.performance.now ? root.performance : Date
};
// src/utils/dom.js
var dom = {
hasEventListeners: typeof root.addEventListener === "function",
bind: function(elem, event, func, bool) {
if (this.hasEventListeners) {
elem.addEventListener(event, func, !!bool);
} else {
elem.attachEvent("on" + event, func);
}
return dom;
},
unbind: function(elem, event, func, bool) {
if (dom.hasEventListeners) {
elem.removeEventListeners(event, func, !!bool);
} else {
elem.detachEvent("on" + event, func);
}
return dom;
},
getRequestAnimationFrame: function() {
const vendors = ["ms", "moz", "webkit", "o"];
let lastTime = 0;
let request = root.requestAnimationFrame;
if (!request) {
for (let i = 0; i < vendors.length; i++) {
request = root[vendors[i] + "RequestAnimationFrame"] || request;
}
request = request || fallbackRequest;
}
function fallbackRequest(callback, element) {
const currTime = (/* @__PURE__ */ new Date()).getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = root.setTimeout(nextRequest, timeToCall);
lastTime = currTime + timeToCall;
function nextRequest() {
callback(currTime + timeToCall);
}
return id;
}
return request;
}
};
var temp = root.document ? root.document.createElement("div") : {};
temp.id = "help-two-load";
Object.defineProperty(dom, "temp", {
enumerable: true,
get: function() {
if (_.isElement(temp) && !root.document.head.contains(temp)) {
temp.style.display = "none";
root.document.head.appendChild(temp);
}
return temp;
}
});
// src/utils/error.js
var TwoError = class extends Error {
name = "Two.js";
message;
constructor(message) {
super();
this.message = message;
}
};
// src/utils/device-pixel-ratio.js
var devicePixelRatio = root.devicePixelRatio || 1;
function getBackingStoreRatio(ctx) {
return ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
}
function getRatio(ctx) {
return devicePixelRatio / getBackingStoreRatio(ctx);
}
// src/registry.js
var Registry = class {
map = {};
constructor() {
}
/**
* @name Two.Registry#add
* @function
* @param {String} id - A unique identifier.
* @param obj - Any type of variable to be registered to the directory.
* @description Adds any value to the directory. Assigned by the `id`.
*/
add(id, obj) {
this.map[id] = obj;
return this;
}
/**
* @name Two.Registry#remove
* @function
* @param {String} id - A unique identifier.
* @description Remove any value from the directory by its `id`.
*/
remove(id) {
delete this.map[id];
return this;
}
/**
* @name Two.Registry#get
* @function
* @param {String} id - A unique identifier.
* @returns {?Object} The associated value. If unavailable then `undefined` is returned.
* @description Get a registered value by its `id`.
*/
get(id) {
return this.map[id];
}
/**
* @name Two.Registry#contains
* @function
* @param {String} id - A unique identifier.
* @returns {Boolean}
* @description Convenience method to see if a value is registered to an `id` already.
*/
contains(id) {
return id in this.map;
}
};
// src/collection.js
var Collection = class extends Array {
// Warning: Multiple inheritance hack
/**
* @private
*/
#events = new Events();
// N.B: Technique to disable enumeration on object
get _events() {
return this.#events;
}
set _events(e) {
this.#events = e;
}
// Getters and setters aren't enumerable
get _bound() {
return this.#events._bound;
}
set _bound(v) {
this.#events._bound = v;
}
addEventListener() {
return this.#events.addEventListener?.apply(this, arguments);
}
on() {
return this.#events.on?.apply(this, arguments);
}
bind() {
return this.#events.bind?.apply(this, arguments);
}
removeEventListener() {
return this.#events.removeEventListener?.apply(this, arguments);
}
off() {
return this.#events.off?.apply(this, arguments);
}
unbind() {
return this.#events.unbind?.apply(this, arguments);
}
dispatchEvent() {
return this.#events.dispatchEvent?.apply(this, arguments);
}
trigger() {
return this.#events.trigger?.apply(this, arguments);
}
listen() {
return this.#events.listen?.apply(this, arguments);
}
ignore() {
return this.#events.ignore?.apply(this, arguments);
}
constructor() {
super();
if (arguments[0] && Array.isArray(arguments[0])) {
if (arguments[0].length > 0) {
this.push.apply(this, arguments[0]);
}
} else if (arguments.length > 0) {
this.push.apply(this, arguments);
}
}
pop() {
const popped = super.pop.apply(this, arguments);
this.trigger(Events.Types.remove, [popped]);
return popped;
}
shift() {
const shifted = super.shift.apply(this, arguments);
this.trigger(Events.Types.remove, [shifted]);
return shifted;
}
push() {
const pushed = super.push.apply(this, arguments);
this.trigger(Events.Types.insert, arguments);
return pushed;
}
unshift() {
const unshifted = super.unshift.apply(this, arguments);
this.trigger(Events.Types.insert, arguments);
return unshifted;
}
splice() {
const spliced = super.splice.apply(this, arguments);
this.trigger(Events.Types.remove, spliced);
if (arguments.length > 2) {
const inserted = this.slice(
arguments[0],
arguments[0] + arguments.length - 2
);
this.trigger(Events.Types.insert, inserted);
this.trigger(Events.Types.order);
}
return spliced;
}
sort() {
super.sort.apply(this, arguments);
this.trigger(Events.Types.order);
return this;
}
reverse() {
super.reverse.apply(this, arguments);
this.trigger(Events.Types.order);
return this;
}
indexOf() {
return super.indexOf.apply(this, arguments);
}
map(func, scope) {
const results = [];
for (let key = 0; key < this.length; key++) {
const value = this[key];
let result;
if (scope) {
result = func.call(scope, value, key);
} else {
result = func(value, key);
}
results.push(result);
}
return results;
}
};
// src/element.js
var Element = class _Element extends Events {
/**
* @name Two.Element#_flagId
* @private
* @property {Boolean} - Determines whether the {@link Two.Element#id} needs updating.
*/
_flagId = false;
/**
* @name Two.Element#_flagClassName
* @private
* @property {Boolean} - Determines whether the {@link Two.Group#className} need updating.
*/
_flagClassName = false;
/**
* @name Two.Element#renderer
* @property {Object} - Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
* @nota-bene With the {@link Two.SVGRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
*/
_renderer = {};
/**
* @name Two.Element#id
* @property {String} - Session specific unique identifier.
* @nota-bene In the {@link Two.SVGRenderer} change this to change the underlying SVG element's id too.
*/
_id = Constants.Identifier + Constants.uniqueId();
/**
* @name Two.Element#className
* @property {String} - A class to be applied to the element to be compatible with CSS styling.
* @nota-bene Only rendered to DOM in the SVG renderer.
*/
_className = "";
/**
* @name Two.Element#classList
* @property {String[]}
* @description A list of class strings stored if imported / interpreted from an SVG element.
*/
classList = [];
constructor() {
super();
for (let prop in proto3) {
Object.defineProperty(this, prop, proto3[prop]);
}
}
static Properties = ["renderer", "id", "className"];
/**
* @name Two.Element.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Element} to create a new instance
* @returns {Two.Element}
* @description Create a new {@link Two.Element} from an object notation of a {@link Two.Element}.
* @nota-bene Works in conjunction with {@link Two.Element#toObject}
*/
static fromObject(obj) {
const elem = new _Element().copy(obj);
if ("id" in obj) {
elem.id = obj.id;
}
return elem;
}
/**
* @name Two.Element#flagReset
* @function
* @description Called internally by Two.js's renderer to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagId = this._flagClassName = false;
return this;
}
copy(element) {
if (element.renderer && typeof element.renderer.type === "string") {
this.renderer.type = element.renderer.type;
}
if (typeof element.className === "string") {
this.className = element.className;
}
return this;
}
toObject() {
return {
renderer: { type: this.renderer.type },
id: this.id,
className: this.className
};
}
/**
* @name Two.Element#dispose
* @function
* @description Release the element's renderer object and detach any events.
* This cleans up renderer-specific resources and unbinds all event listeners.
*/
dispose() {
if (typeof this.unbind === "function") {
this.unbind();
}
if (this._renderer) {
if (this._renderer.elem && this._renderer.elem.parentNode) {
this._renderer.elem.parentNode.removeChild(this._renderer.elem);
delete this._renderer.elem;
}
if (this.type === "WebGLRenderer" && this.renderer.ctx) {
const gl = this.renderer.ctx;
if (this._renderer.texture) {
gl.deleteTexture(this._renderer.texture);
delete this._renderer.texture;
}
if (this._renderer.positionBuffer) {
gl.deleteBuffer(this._renderer.positionBuffer);
delete this._renderer.positionBuffer;
}
if (this._renderer.effect) {
this._renderer.effect = null;
}
}
if (this.type === "CanvasRenderer" && this._renderer.context) {
delete this._renderer.context;
}
}
const rendererType = this._renderer.type;
this._renderer = { type: rendererType };
return this;
}
};
var proto3 = {
renderer: {
enumerable: false,
get: function() {
return this._renderer;
}
},
id: {
enumerable: true,
get: function() {
return this._id;
},
set: function(v) {
const id = this._id;
if (v === this._id) {
return;
}
this._id = v;
this._flagId = true;
if (this.parent) {
delete this.parent.children.ids[id];
this.parent.children.ids[this._id] = this;
}
}
},
className: {
enumerable: true,
get: function() {
return this._className;
},
set: function(v) {
if (this._className !== v) {
this._flagClassName = true;
this.classList = v.split(/\s+?/);
this._className = v;
}
}
}
};
// src/effects/texture.js
var anchor;
var regex = {
video: /\.(mp4|webm|ogg)$/i,
image: /\.(jpe?g|png|gif|tiff|webp)$/i,
effect: /texture|gradient/i
};
if (root.document) {
anchor = document.createElement("a");
}
var Texture = class _Texture extends Element {
/**
* @name Two.Texture#_flagSrc
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#src} needs updating.
*/
_flagSrc = false;
/**
* @name Two.Texture#_flagImage
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#image} needs updating.
*/
_flagImage = false;
/**
* @name Two.Texture#_flagVideo
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#video} needs updating.
*/
_flagVideo = false;
/**
* @name Two.Texture#_flagLoaded
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#loaded} needs updating.
*/
_flagLoaded = false;
/**
* @name Two.Texture#_flagRepeat
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#repeat} needs updating.
*/
_flagRepeat = false;
/**
* @name Two.Texture#_flagOffset
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#offset} needs updating.
*/
_flagOffset = false;
/**
* @name Two.Texture#_flagScale
* @private
* @property {Boolean} - Determines whether the {@link Two.Texture#scale} needs updating.
*/
_flagScale = false;
/**
* @name Two.Texture#_src
* @private
* @see {@link Two.Texture#src}
*/
_src = "";
/**
* @name Two.Texture#_image
* @private
* @see {@link Two.Texture#image}
*/
_image = null;
/**
* @name Two.Texture#_loaded
* @private
* @see {@link Two.Texture#loaded}
*/
_loaded = false;
/**
* @name Two.Texture#_repeat
* @private
* @see {@link Two.Texture#repeat}
*/
_repeat = "no-repeat";
/**
* @name Two.Texture#_scale
* @private
* @see {@link Two.Texture#scale}
*/
_scale = 1;
/**
* @name Two.Texture#_offset
* @private
* @see {@link Two.Texture#offset}
*/
_offset = null;
constructor(src, callback) {
super();
for (let prop in proto4) {
Object.defineProperty(this, prop, proto4[prop]);
}
this._renderer.type = "texture";
this._renderer.flagOffset = FlagOffset.bind(this);
this._renderer.flagScale = FlagScale.bind(this);
this.loaded = false;
this.repeat = "no-repeat";
this.offset = new Vector();
if (typeof callback === "function") {
const loaded = function() {
this.unbind(Events.Types.load, loaded);
if (typeof callback === "function") {
callback();
}
}.bind(this);
this.bind(Events.Types.load, loaded);
}
if (typeof src === "string") {
this.src = src;
} else if (typeof src === "object") {
const elemString = Object.prototype.toString.call(src);
if (elemString === "[object HTMLImageElement]" || elemString === "[object HTMLCanvasElement]" || elemString === "[object HTMLVideoElement]" || elemString === "[object Image]") {
this.image = src;
}
}
this._update();
}
/**
* @name Two.Texture.Properties
* @property {String[]} - A list of properties that are on every {@link Two.Texture}.
*/
static Properties = ["src", "loaded", "repeat", "scale", "offset", "image"];
/**
* @name Two.Texture.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Texture} to create a new instance
* @returns {Two.Texture}
* @description Create a new {@link Two.Texture} from an object notation of a {@link Two.Texture}.
* @nota-bene Works in conjunction with {@link Two.Texture#toObject}
*/
fromObject(obj) {
const texture = new _Texture().copy(obj);
if ("id" in obj) {
texture.id = obj.id;
}
return texture;
}
/**
* @name Two.Texture.RegularExpressions
* @property {Object} - A map of compatible DOM Elements categorized by media format.
*/
static RegularExpressions = regex;
/**
* @name Two.Texture.ImageRegistry
* @property {Two.Registry} - A canonical listing of image data used in a single session of Two.js.
* @nota-bene This object is used to cache image data between different textures.
*/
static ImageRegistry = new Registry();
/**
* @name Two.Texture.getAbsoluteURL
* @property {Function} - Serializes a URL as an absolute path for canonical attribution in {@link Two.Texture.ImageRegistry}.
* @param {String} path
* @returns {String} - The serialized absolute path.
*/
static getAbsoluteURL(path) {
if (!anchor) {
return path;
}
anchor.href = path;
return anchor.href;
}
/**
* @name Two.Texture.loadHeadlessBuffer
* @property {Function} - Loads an image as a buffer in headless environments.
* @param {Two.Texture} texture - The {@link Two.Texture} to be loaded.
* @param {Function} onLoad - The callback function to be triggered once the image is loaded.
* @nota-bene - This function uses node's `fs.readFileSync` to spoof the `<img />` loading process in the browser.
*/
static loadHeadlessBuffer(texture, onLoad) {
texture.image.onload = onLoad;
texture.image.src = texture.src;
}
/**
* @name Two.Texture.getTag
* @property {Function} - Retrieves the tag name of an image, video, or canvas node.
* @param {HTMLImageElement} image - The image to infer the tag name from.
* @returns {String} - Returns the tag name of an image, video, or canvas node.
*/
static getTag(image) {
return image && image.nodeName && image.nodeName.toLowerCase() || // Headless environments
"img";
}
/**
* @name Two.Texture.getImage
* @property {Function} - Convenience function to set {@link Two.Texture#image} properties with canonical versions set in {@link Two.Texture.ImageRegistry}.
* @param {String} src - The URL path of the image.
* @returns {HTMLImageElement} - Returns either a cached version of the image or a new one that is registered in {@link Two.Texture.ImageRegistry}.
*/
static getImage(src) {
const absoluteSrc = _Texture.getAbsoluteURL(src);
if (_Texture.ImageRegistry.contains(absoluteSrc)) {
return _Texture.ImageRegistry.get(absoluteSrc);
}
let image;
if (CanvasPolyfill.Image) {
image = new CanvasPolyfill.Image();
CanvasPolyfill.shim(image, "img");
} else if (root.document) {
if (regex.video.test(absoluteSrc)) {
image = document.createElement("video");
} else {
image = document.createElement("img");
}
} else {
console.warn("Two.js: no prototypical image defined for Two.Texture");
}
image.crossOrigin = "anonymous";
image.referrerPolicy = "no-referrer";
return image;
}
/**
* @name Two.Texture.Register
* @interface
* @description A collection of functions to register different types of textures. Used internally by a {@link Two.Texture}.
*/
static Register = {
canvas: function(texture, callback) {
texture._src = "#" + texture.id;
_Texture.ImageRegistry.add(texture.src, texture.image);
if (typeof callback === "function") {
callback();
}
},
img: function(texture, callback) {
const image = texture.image;
const loaded = function(e) {
if (!CanvasPolyfill.isHeadless && image.removeEventListener && typeof image.removeEventListener === "function") {
image.removeEventListener("load", loaded, false);
image.removeEventListener("error", error, false);
}
if (typeof callback === "function") {
callback();
}
};
const error = function(e) {
if (!CanvasPolyfill.isHeadless && typeof image.removeEventListener === "function") {
image.removeEventListener("load", loaded, false);
image.removeEventListener("error", error, false);
}
throw new TwoError("unable to load " + texture.src);
};
if (typeof image.width === "number" && image.width > 0 && typeof image.height === "number" && image.height > 0) {
loaded();
} else if (!CanvasPolyfill.isHeadless && typeof image.addEventListener === "function") {
image.addEventListener("load", loaded, false);
image.addEventListener("error", error, false);
}
texture._src = _Texture.getAbsoluteURL(texture._src);
if (!CanvasPolyfill.isHeadless && image && image.getAttribute("two-src")) {
return;
}
if (!CanvasPolyfill.isHeadless) {
image.setAttribute("two-src", texture.src);
}
_Texture.ImageRegistry.add(texture.src, image);
if (CanvasPolyfill.isHeadless) {
_Texture.loadHeadlessBuffer(texture, loaded);
} else {
texture.image.src = texture.src;
}
},
video: function(texture, callback) {
if (CanvasPolyfill.isHeadless) {
throw new TwoError(
"video textures are not implemented in headless environments."
);
}
const loaded = function(e) {
texture.image.removeEventListener("canplaythrough", loaded, false);
texture.image.removeEventListener("error", error, false);
texture.image.width = texture.image.videoWidth;
texture.image.height = texture.image.videoHeight;
if (typeof callback === "function") {
callback();
}
};
const error = function(e) {
texture.image.removeEventListener("canplaythrough", loaded, false);
texture.image.removeEventListener("error", error, false);
throw new TwoError("unable to load " + texture.src);
};
texture._src = _Texture.getAbsoluteURL(texture._src);
if (!texture.image.getAttribute("two-src")) {
texture.image.setAttribute("two-src", texture.src);
_Texture.ImageRegistry.add(texture.src, texture.image);
}
if (texture.image.readyState >= 4) {
loaded();
} else {
texture.image.addEventListener("canplaythrough", loaded, false);
texture.image.addEventListener("error", error, false);
texture.image.src = texture.src;
texture.image.load();
}
}
};
/**
* @name Two.Texture.load
* @function
* @param {Two.Texture} texture - The texture to load.
* @param {Function} callback - The function to be called once the texture is loaded.
*/
static load(texture, callback) {
let image = texture.image;
let tag = _Texture.getTag(image);
if (texture._flagImage) {
if (/canvas/i.test(tag)) {
_Texture.Register.canvas(texture, callback);
} else {
texture._src = !CanvasPolyfill.isHeadless && image.getAttribute("two-src") || image.src;
_Texture.Register[tag](texture, callback);
}
}
if (texture._flagSrc) {
if (!image) {
image = _Texture.getImage(texture.src);
texture.image = image;
}
tag = _Texture.getTag(image);
_Texture.Register[tag](texture, callback);
}
}
/**
* @name Two.Texture#clone
* @function
* @returns {Two.Texture}
* @description Create a new instance of {@link Two.Texture} with the same properties of the current texture.
*/
clone() {
const clone = new _Texture(this.src);
clone.repeat = this.repeat;
clone.offset.copy(this.offset);
clone.scale = this.scale;
return clone;
}
/**
* @name Two.Texture#copy
* @function
* @param {Two.Texture} texture - The reference {@link Two.Texture}
* @description Copy the properties of one {@link Two.Texture} onto another.
*/
copy(texture) {
this.src = texture.src;
this.repeat = texture.repeat;
this.offset = typeof texture.offset === "number" || texture.offset instanceof Vector ? texture.offset : new Vector().copy(texture.offset);
this.scale = typeof texture.scale === "number" || texture.scale instanceof Vector ? texture.scale : new Vector().copy(texture.scale);
return this;
}
/**
* @name Two.Texture#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the texture.
*/
toObject() {
const result = super.toObject.call(this);
result.renderer.type = "texture";
result.src = this.src;
result.repeat = this.repeat;
result.offset = this.offset.toObject();
result.scale = typeof this.scale === "number" ? this.scale : this.scale.toObject();
return result;
}
/**
* @name Two.Texture#_update
* @function
* @private
* @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
* @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
* @nota-bene Try not to call this method more than once a frame.
*/
_update() {
if (this._flagSrc || this._flagImage) {
this.trigger(Events.Types.change);
if (this._flagSrc || this._flagImage) {
this.loaded = false;
_Texture.load(
this,
function() {
this.loaded = true;
this.trigger(Events.Types.change).trigger(Events.Types.load);
}.bind(this)
);
}
}
if (this._image && this._image.readyState >= 4) {
this._flagVideo = true;
}
return this;
}
/**
* @name Two.Texture#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagSrc = this._flagImage = this._flagLoaded = this._flagRepeat = this._flagVideo = this._flagScale = this._flagOffset = false;
super.flagReset.call(this);
return this;
}
/**
* @name Two.Texture#dispose
* @function
* @description Detach instance from renderer including any `<defs />` or textures stored in memory.
*/
dispose() {
super.dispose();
if ("elem" in this._renderer) {
const elem = this._renderer.elem;
elem.parentNode.removeChild(elem);
}
if ("effect" in this._renderer) {
this._renderer.effect = null;
}
return this;
}
};
var proto4 = {
src: {
enumerable: true,
get: function() {
return this._src;
},
set: function(v) {
this._src = v;
this._flagSrc = true;
}
},
loaded: {
enumerable: true,
get: function() {
return this._loaded;
},
set: function(v) {
this._loaded = v;
this._flagLoaded = true;
}
},
repeat: {
enumerable: true,
get: function() {
return this._repeat;
},
set: function(v) {
this._repeat = v;
this._flagRepeat = true;
}
},
image: {
enumerable: true,
get: function() {
return this._image;
},
set: function(image) {
const tag = Texture.getTag(image);
let index;
switch (tag) {
case "canvas":
index = "#" + image.id;
break;
default:
index = image.src;
}
if (Texture.ImageRegistry.contains(index)) {
this._image = Texture.ImageRegistry.get(image.src);
} else {
this._image = image;
}
this._flagImage = true;
}
},
offset: {
enumerable: true,
get: function() {
return this._offset;
},
set: function(v) {
if (this._offset) {
this._offset.unbind(Events.Types.change, this._renderer.flagOffset);
}
this._offset = v;
this._offset.bind(Events.Types.change, this._renderer.flagOffset);
this._flagOffset = true;
}
},
scale: {
enumerable: true,
get: function() {
return this._scale;
},
set: function(v) {
if (this._scale instanceof Vector) {
this._scale.unbind(Events.Types.change, this._renderer.flagScale);
}
this._scale = v;
if (this._scale instanceof Vector) {
this._scale.bind(Events.Types.change, this._renderer.flagScale);
}
this._flagScale = true;
}
}
};
function FlagOffset() {
this._flagOffset = true;
}
function FlagScale() {
this._flagScale = true;
}
// src/effects/stop.js
var Stop = class _Stop extends Element {
/**
* @name Two.Stop#_flagOffset
* @private
* @property {Boolean} - Determines whether the {@link Two.Stop#offset} needs updating.
*/
_flagOffset = true;
/**
* @name Two.Stop#_flagOpacity
* @private
* @property {Boolean} - Determines whether the {@link Two.Stop#opacity} needs updating.
*/
_flagOpacity = true;
/**
* @name Two.Stop#_flagColor
* @private
* @property {Boolean} - Determines whether the {@link Two.Stop#color} needs updating.
*/
_flagColor = true;
/**
* @name Two.Stop#_offset
* @private
* @see {@link Two.Stop#offset}
*/
_offset = 0;
/**
* @name Two.Stop#_opacity
* @private
* @see {@link Two.Stop#opacity}
*/
_opacity = 1;
/**
* @name Two.Stop#_color
* @private
* @see {@link Two.Stop#color}
*/
_color = "#fff";
constructor(offset, color, opacity) {
super();
for (let prop in proto5) {
Object.defineProperty(this, prop, proto5[prop]);
}
this._renderer.type = "stop";
this.offset = typeof offset === "number" ? offset : _Stop.Index <= 0 ? 0 : 1;
this.opacity = typeof opacity === "number" ? opacity : 1;
this.color = typeof color === "string" ? color : _Stop.Index <= 0 ? "#fff" : "#000";
_Stop.Index = (_Stop.Index + 1) % 2;
}
/**
* @name Two.Stop.Index
* @property {Number} - The current index being referenced for calculating a stop's default offset value.
*/
static Index = 0;
/**
* @name Two.Stop.Properties
* @property {String[]} - A list of properties that are on every {@link Two.Stop}.
*/
static Properties = ["offset", "opacity", "color"];
/**
* @name Two.Stop.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Stop} to create a new instance
* @returns {Two.Stop}
* @description Create a new {@link Two.Stop} from an object notation of a {@link Two.Stop}.
* @nota-bene Works in conjunction with {@link Two.Stop#toObject}
*/
static fromObject(obj) {
const stop = new _Stop().copy(obj);
if ("id" in obj) {
stop.id = obj.id;
}
return stop;
}
/**
* @name Two.Stop#copy
* @function
* @param {Two.Stop} stop - The reference {@link Two.Stop}
* @description Copy the properties of one {@link Two.Stop} onto another.
*/
copy(stop) {
super.copy.call(this, stop);
for (let i = 0; i < _Stop.Properties.length; i++) {
const k = _Stop.Properties[i];
if (k in stop) {
this[k] = stop[k];
}
}
return this;
}
/**
* @name Two.Stop#clone
* @function
* @param {Two.Gradient} [parent] - The parent gradient to add the clone to.
* @returns {Two.Stop}
* @description Create a new instance of {@link Two.Stop} with the same properties of the current path.
*/
clone(parent) {
const clone = new _Stop();
_.each(
_Stop.Properties,
function(property) {
clone[property] = this[property];
},
this
);
if (parent && parent.stops) {
parent.stops.push(clone);
}
return clone;
}
/**
* @name Two.Stop#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the path.
*/
toObject() {
const result = super.toObject.call(this);
result.renderer.type = "stop";
_.each(
_Stop.Properties,
(k) => {
result[k] = this[k];
},
this
);
return result;
}
/**
* @name Two.Stop#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagOffset = this._flagColor = this._flagOpacity = false;
super.flagReset.call(this);
return this;
}
};
var proto5 = {
offset: {
enumerable: true,
get: function() {
return this._offset;
},
set: function(v) {
this._offset = v;
this._flagOffset = true;
if (this.parent) {
this.parent._flagStops = true;
}
}
},
opacity: {
enumerable: true,
get: function() {
return this._opacity;
},
set: function(v) {
this._opacity = v;
this._flagOpacity = true;
if (this.parent) {
this.parent._flagStops = true;
}
}
},
color: {
enumerable: true,
get: function() {
return this._color;
},
set: function(v) {
this._color = v;
this._flagColor = true;
if (this.parent) {
this.parent._flagStops = true;
}
}
}
};
// src/effects/gradient.js
var Gradient = class _Gradient extends Element {
_flagStops = false;
_flagSpread = false;
_flagUnits = false;
_spread = "";
_units = "";
constructor(stops) {
super();
for (let prop in proto6) {
Object.defineProperty(this, prop, proto6[prop]);
}
this._renderer.type = "gradient";
this._renderer.flagStops = FlagStops.bind(this);
this._renderer.bindStops = BindStops.bind(this);
this._renderer.unbindStops = UnbindStops.bind(this);
this.spread = "pad";
this.units = "objectBoundingBox";
if (stops) {
this.stops = stops;
}
}
/**
* @name Two.Gradient.Stop
* @see {@link Two.Stop}
*/
static Stop = Stop;
/**
* @name Two.Gradient.Properties
* @property {String[]} - A list of properties that are on every {@link Two.Gradient}.
*/
static Properties = ["spread", "stops", "units"];
/**
* @name Two.Gradient.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Gradient} to create a new instance
* @returns {Two.Gradient}
* @description Create a new {@link Two.Gradient} from an object notation of a {@link Two.Gradient}.
* @nota-bene Works in conjunction with {@link Two.Gradient#toObject}
*/
static fromObject(obj) {
let stops = obj.stops;
if (stops && stops.length > 0) {
stops = stops.map((o) => o instanceof Stop ? o : new Stop().copy(o));
}
const gradient = new _Gradient(stops).copy(obj);
if ("id" in obj) {
gradient.id = obj.id;
}
return gradient;
}
/**
* @name Two.Gradient#clone
* @function
* @param {Two.Group} [parent] - The parent group or scene to add the clone to.
* @returns {Two.Gradient}
* @description Create a new instance of {@link Two.Gradient} with the same properties of the current path.
*/
clone(parent) {
const stops = this.stops.map((s) => {
return s.clone();
});
const clone = new _Gradient(stops);
_.each(
_Gradient.Properties,
(k) => {
clone[k] = this[k];
},
this
);
if (parent) {
parent.add(clone);
}
return clone;
}
/**
* @name Two.Gradient#copy
* @function
* @param {Two.Gradient} gradient - The reference {@link Two.Gradient}
* @description Copy the properties of one {@link Two.Gradient} onto another.
*/
copy(gradient) {
super.copy.call(this, gradient);
for (let i = 0; i < _Gradient.Properties.length; i++) {
const k = _Gradient.Properties[i];
if (k in gradient) {
this[k] = gradient[k];
}
}
return this;
}
/**
* @name Two.Gradient#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the path.
*/
toObject() {
const result = {
stops: this.stops.map((s) => {
return s.toObject();
})
};
_.each(
_Gradient.Properties,
(k) => {
result[k] = this[k];
},
this
);
return result;
}
/**
* @name Two.Gradient#_update
* @function
* @private
* @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
* @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
* @nota-bene Try not to call this method more than once a frame.
*/
_update() {
if (this._flagSpread || this._flagStops) {
this.trigger(Events.Types.change);
}
return this;
}
/**
* @name Two.Gradient#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagSpread = this._flagUnits = this._flagStops = false;
super.flagReset.call(this);
return this;
}
/**
* @name Two.Gradient#dispose
* @function
* @description Detach instance from renderer including any `<defs />` or textures stored in memory.
*/
dispose() {
if ("elem" in this._renderer) {
const elem = this._renderer.elem;
elem.parentNode.removeChild(elem);
}
if ("effect" in this._renderer) {
this._renderer.effect = null;
}
return this;
}
};
var proto6 = {
spread: {
enumerable: true,
get: function() {
return this._spread;
},
set: function(v) {
this._spread = v;
this._flagSpread = true;
}
},
units: {
enumerable: true,
get: function() {
return this._units;
},
set: function(v) {
this._units = v;
this._flagUnits = true;
}
},
stops: {
enumerable: true,
get: function() {
return this._stops;
},
set: function(stops) {
const bindStops = this._renderer.bindStops;
const unbindStops = this._renderer.unbindStops;
if (this._stops) {
this._stops.unbind(Events.Types.insert, bindStops).unbind(Events.Types.remove, unbindStops);
}
this._stops = new Collection((stops || []).slice(0));
this._stops.bind(Events.Types.insert, bindStops).bind(Events.Types.remove, unbindStops);
bindStops(this._stops);
}
}
};
function FlagStops() {
this._flagStops = true;
}
function BindStops(items) {
let i = items.length;
while (i--) {
items[i].bind(Events.Types.change, this._renderer.flagStops);
items[i].parent = this;
}
this._renderer.flagStops();
}
function UnbindStops(items) {
let i = items.length;
while (i--) {
items[i].unbind(Events.Types.change, this._renderer.flagStops);
delete items[i].parent;
}
this._renderer.flagStops();
}
// src/effects/linear-gradient.js
var LinearGradient = class _LinearGradient extends Gradient {
/**
* @name Two.LinearGradient#_flagEndPoints
* @private
* @property {Boolean} - Determines whether the {@link Two.LinearGradient#left} or {@link Two.LinearGradient#right} changed and needs to update.
*/
_flagEndPoints = false;
_left = null;
_right = null;
constructor(x1, y1, x2, y2, stops) {
super(stops);
for (let prop in proto7) {
Object.defineProperty(this, prop, proto7[prop]);
}
this._renderer.type = "linear-gradient";
this._renderer.flagEndPoints = FlagEndPoints.bind(this);
this.left = new Vector();
this.right = new Vector();
if (typeof x1 === "number") {
this.left.x = x1;
}
if (typeof y1 === "number") {
this.left.y = y1;
}
if (typeof x2 === "number") {
this.right.x = x2;
}
if (typeof y2 === "number") {
this.right.y = y2;
}
}
/**
* @name Two.LinearGradient.Stop
* @see {@link Two.Stop}
*/
static Stop = Stop;
static Properties = ["left", "right"];
/**
* @name Two.LinearGradient.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.LinearGradient} to create a new instance
* @returns {Two.LinearGradient}
* @description Create a new {@link Two.LinearGradient} from an object notation of a {@link Two.LinearGradient}.
* @nota-bene Works in conjunction with {@link Two.LinearGradient#toObject}
*/
static fromObject(obj) {
const gradient = new _LinearGradient().copy(obj);
if ("id" in obj) {
gradient.id = obj.id;
}
return gradient;
}
/**
* @name Two.LinearGradient#copy
* @function
* @param {Two.LinearGradient} gradient - The reference {@link Two.LinearGradient}
* @description Copy the properties of one {@link Two.LinearGradient} onto another.
*/
copy(gradient) {
super.copy.call(this, gradient);
for (let i = 0; i < _LinearGradient.Properties.length; i++) {
const k = _LinearGradient.Properties[i];
if (k in gradient) {
this[k] = gradient[k] instanceof Vector ? gradient[k] : new Vector().copy(gradient[k]);
}
}
return this;
}
/**
* @name Two.LinearGradient#clone
* @function
* @param {Two.Group} [parent] - The parent group or scene to add the clone to.
* @returns {Two.Gradient}
* @description Create a new instance of {@link Two.LinearGradient} with the same properties of the current path.
*/
clone(parent) {
const stops = this.stops.map(function(stop) {
return stop.clone();
});
const clone = new _LinearGradient(
this.left._x,
this.left._y,
this.right._x,
this.right._y,
stops
);
_.each(
Gradient.Properties,
function(k) {
clone[k] = this[k];
},
this
);
if (parent) {
parent.add(clone);
}
return clone;
}
/**
* @name Two.LinearGradient#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the path.
*/
toObject() {
const result = super.toObject.call(this);
result.left = this.left.toObject();
result.right = this.right.toObject();
return result;
}
/**
* @name Two.LinearGradient#_update
* @function
* @private
* @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
* @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
* @nota-bene Try not to call this method more than once a frame.
*/
_update() {
if (this._flagEndPoints || this._flagSpread || this._flagStops) {
this.trigger(Events.Types.change);
}
return this;
}
/**
* @name Two.LinearGradient#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagEndPoints = false;
super.flagReset.call(this);
return this;
}
};
var proto7 = {
left: {
enumerable: true,
get: function() {
return this._left;
},
set: function(v) {
if (this._left instanceof Vector) {
this._left.unbind(Events.Types.change, this._renderer.flagEndPoints);
}
this._left = v;
this._left.bind(Events.Types.change, this._renderer.flagEndPoints);
this._flagEndPoints = true;
}
},
right: {
enumerable: true,
get: function() {
return this._right;
},
set: function(v) {
if (this._right instanceof Vector) {
this._right.unbind(Events.Types.change, this._renderer.flagEndPoints);
}
this._right = v;
this._right.bind(Events.Types.change, this._renderer.flagEndPoints);
this._flagEndPoints = true;
}
}
};
function FlagEndPoints() {
this._flagEndPoints = true;
}
// src/effects/radial-gradient.js
var RadialGradient = class _RadialGradient extends Gradient {
/**
* @name Two.RadialGradient#_flagRadius
* @private
* @property {Boolean} - Determines whether the {@link Two.RadialGradient#radius} changed and needs to update.
*/
_flagRadius = false;
/**
* @name Two.RadialGradient#_flagCenter
* @private
* @property {Boolean} - Determines whether the {@link Two.RadialGradient#center} changed and needs to update.
*/
_flagCenter = false;
/**
* @name Two.RadialGradient#_flagFocal
* @private
* @property {Boolean} - Determines whether the {@link Two.RadialGradient#focal} changed and needs to update.
*/
_flagFocal = false;
_radius = 0;
_center = null;
_focal = null;
constructor(cx, cy, r, stops, fx, fy) {
super(stops);
for (let prop in proto8) {
Object.defineProperty(this, prop, proto8[prop]);
}
this._renderer.type = "radial-gradient";
this._renderer.flagCenter = FlagCenter.bind(this);
this._renderer.flagFocal = FlagFocal.bind(this);
this.center = new Vector();
this.radius = typeof r === "number" ? r : 1;
this.focal = new Vector();
if (typeof cx === "number") {
this.center.x = cx;
}
if (typeof cy === "number") {
this.center.y = cy;
}
this.focal.copy(this.center);
if (typeof fx === "number") {
this.focal.x = fx;
}
if (typeof fy === "number") {
this.focal.y = fy;
}
}
/**
* @name Two.RadialGradient.Stop
* @see {@link Two.Stop}
*/
static Stop = Stop;
/**
* @name Two.RadialGradient.Properties
* @property {String[]} - A list of properties that are on every {@link Two.RadialGradient}.
*/
static Properties = ["center", "radius", "focal"];
/**
* @name Two.RadialGradient.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.RadialGradient} to create a new instance
* @returns {Two.RadialGradient}
* @description Create a new {@link Two.RadialGradient} from an object notation of a {@link Two.RadialGradient}.
* @nota-bene Works in conjunction with {@link Two.RadialGradient#toObject}
*/
static fromObject(obj) {
const gradient = new _RadialGradient().copy(obj);
if ("id" in obj) {
gradient.id = obj.id;
}
return gradient;
}
/**
* @name Two.RadialGradient#copy
* @function
* @param {Two.RadialGradient} gradient - The reference {@link Two.RadialGradient}
* @description Copy the properties of one {@link Two.RadialGradient} onto another.
*/
copy(gradient) {
super.copy.call(this, gradient);
for (let i = 0; i < _RadialGradient.Properties.length; i++) {
const k = _RadialGradient.Properties[i];
if (k in gradient) {
if (/(center|focal)i/.test(k)) {
this[k] = gradient[k] instanceof Vector ? gradient[k] : new Vector().copy(gradient[k]);
} else if (typeof gradient[k] === "number") {
this[k] = gradient[MediaKeySystemAccess];
}
}
}
return this;
}
/**
* @name Two.RadialGradient#clone
* @function
* @param {Two.Group} [parent] - The parent group or scene to add the clone to.
* @returns {Two.RadialGradient}
* @description Create a new instance of {@link Two.RadialGradient} with the same properties of the current path.
*/
clone(parent) {
const stops = this.stops.map(function(stop) {
return stop.clone();
});
const clone = new _RadialGradient(
this.center._x,
this.center._y,
this._radius,
stops,
this.focal._x,
this.focal._y
);
_.each(
Gradient.Properties.concat(_RadialGradient.Properties),
function(k) {
clone[k] = this[k];
},
this
);
if (parent) {
parent.add(clone);
}
return clone;
}
/**
* @name Two.RadialGradient#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the path.
*/
toObject() {
const result = super.toObject.call(this);
_.each(
_RadialGradient.Properties,
function(k) {
result[k] = this[k];
},
this
);
result.center = this.center.toObject();
result.focal = this.focal.toObject();
return result;
}
/**
* @name Two.RadialGradient#_update
* @function
* @private
* @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
* @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
* @nota-bene Try not to call this method more than once a frame.
*/
_update() {
if (this._flagRadius || this._flatCenter || this._flagFocal || this._flagSpread || this._flagStops) {
this.trigger(Events.Types.change);
}
return this;
}
/**
* @name Two.RadialGradient#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagRadius = this._flagCenter = this._flagFocal = false;
super.flagReset.call(this);
return this;
}
};
var proto8 = {
radius: {
enumerable: true,
get: function() {
return this._radius;
},
set: function(v) {
this._radius = v;
this._flagRadius = true;
}
},
center: {
enumerable: true,
get: function() {
return this._center;
},
set: function(v) {
if (this._center) {
this._center.unbind(Events.Types.change, this._renderer.flagCenter);
}
this._center = v;
this._center.bind(Events.Types.change, this._renderer.flagCenter);
this._flagCenter = true;
}
},
focal: {
enumerable: true,
get: function() {
return this._focal;
},
set: function(v) {
if (this._focal) {
this._focal.unbind(Events.Types.change, this._renderer.flagFocal);
}
this._focal = v;
this._focal.bind(Events.Types.change, this._renderer.flagFocal);
this._flagFocal = true;
}
}
};
function FlagCenter() {
this._flagCenter = true;
}
function FlagFocal() {
this._flagFocal = true;
}
// src/utils/shape.js
function contains(path, t) {
if (t === 0 || t === 1) {
return true;
}
const length = path._length;
const target = length * t;
let elapsed = 0;
for (let i = 0; i < path._lengths.length; i++) {
const dist = path._lengths[i];
if (elapsed >= target) {
return target - elapsed >= 0;
}
elapsed += dist;
}
return false;
}
function getIdByLength(path, target) {
const total = path._length;
if (target <= 0) {
return 0;
} else if (target >= total) {
return path._lengths.length - 1;
}
for (let i = 0, sum = 0; i < path._lengths.length; i++) {
if (sum + path._lengths[i] >= target) {
target -= sum;
return Math.max(i - 1, 0) + target / path._lengths[i];
}
sum += path._lengths[i];
}
return -1;
}
function getCurveLength2(a, b, limit) {
let x1, x2, x3, x4, y1, y2, y3, y4;
const right = b.controls && b.controls.right;
const left = a.controls && a.controls.left;
x1 = b.x;
y1 = b.y;
x2 = (right || b).x;
y2 = (right || b).y;
x3 = (left || a).x;
y3 = (left || a).y;
x4 = a.x;
y4 = a.y;
if (right && b._relative) {
x2 += b.x;
y2 += b.y;
}
if (left && a._relative) {
x3 += a.x;
y3 += a.y;
}
return getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit);
}
function getSubdivisions(a, b, limit) {
let x1, x2, x3, x4, y1, y2, y3, y4;
const right = b.controls && b.controls.right;
const left = a.controls && a.controls.left;
x1 = b.x;
y1 = b.y;
x2 = (right || b).x;
y2 = (right || b).y;
x3 = (left || a).x;
y3 = (left || a).y;
x4 = a.x;
y4 = a.y;
if (right && b._relative) {
x2 += b.x;
y2 += b.y;
}
if (left && a._relative) {
x3 += a.x;
y3 += a.y;
}
return subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit);
}
function getEffectFromObject(obj) {
switch (obj.renderer.type) {
case "texture":
return Texture.fromObject(obj);
case "gradient":
return Gradient.fromObject(obj);
case "linear-gradient":
return LinearGradient.fromObject(obj);
case "radial-gradient":
return RadialGradient.fromObject(obj);
}
return obj;
}
// src/matrix.js
var cos = Math.cos;
var sin = Math.sin;
var tan = Math.tan;
var array = [];
var Matrix2 = class _Matrix extends Events {
/**
* @name Two.Matrix#elements
* @property {Number[]} - The underlying data stored as an array.
*/
elements = new NumArray(9);
/**
* @name Two.Matrix#manual
* @property {Boolean} - Determines whether Two.js automatically calculates the values for the matrix or if the developer intends to manage the matrix.
* @nota-bene - Setting to `true` nullifies {@link Two.Shape#translation}, {@link Two.Shape#rotation}, and {@link Two.Shape#scale}.
*/
manual = false;
constructor(a, b, c, d, e, f) {
super();
let elements = a;
if (!Array.isArray(elements)) {
elements = Array.prototype.slice.call(arguments);
}
this.identity();
if (elements.length > 0) {
this.set(elements);
}
}
//
/**
* @name Two.Matrix.Identity
* @property {Number[]} - A stored reference to the default value of a 3 x 3 matrix.
*/
static Identity = [1, 0, 0, 0, 1, 0, 0, 0, 1];
/**
* @name Two.Matrix.Multiply
* @function
* @param {Number[]} A - The first {@link Two.Matrix} to multiply
* @param {Number[]} B - The second {@link Two.Matrix} to multiply
* @param {Number[]} [C] - An optional {@link Two.Matrix} to apply the result to
* @returns {Number[]} - If an optional `C` matrix isn't passed then a new one is created and returned.
* @description Multiply two matrices together and return the result.
*/
static Multiply(A, B, C) {
if (B.length <= 3) {
const e = A;
let x, y, z;
const a = B[0] || 0, b = B[1] || 0, c = B[2] || 0;
x = e[0] * a + e[1] * b + e[2] * c;
y = e[3] * a + e[4] * b + e[5] * c;
z = e[6] * a + e[7] * b + e[8] * c;
return [x, y, z];
}
const A0 = A[0], A1 = A[1], A2 = A[2];
const A3 = A[3], A4 = A[4], A5 = A[5];
const A6 = A[6], A7 = A[7], A8 = A[8];
const B0 = B[0], B1 = B[1], B2 = B[2];
const B3 = B[3], B4 = B[4], B5 = B[5];
const B6 = B[6], B7 = B[7], B8 = B[8];
C = C || new NumArray(9);
C[0] = A0 * B0 + A1 * B3 + A2 * B6;
C[1] = A0 * B1 + A1 * B4 + A2 * B7;
C[2] = A0 * B2 + A1 * B5 + A2 * B8;
C[3] = A3 * B0 + A4 * B3 + A5 * B6;
C[4] = A3 * B1 + A4 * B4 + A5 * B7;
C[5] = A3 * B2 + A4 * B5 + A5 * B8;
C[6] = A6 * B0 + A7 * B3 + A8 * B6;
C[7] = A6 * B1 + A7 * B4 + A8 * B7;
C[8] = A6 * B2 + A7 * B5 + A8 * B8;
return C;
}
/**
* @name Two.Matrix.fromObject
* @function
* @param {Object} obj - The object notation of a Two.Matrix to create a new instance
* @returns {Two.Matrix}
* @description Create a new {@link Two.Matrix} from an object notation of a {@link Two.Matrix}.
* @nota-bene Works in conjunction with {@link Two.Matrix#toObject}
*/
static fromObject(obj) {
return new _Matrix().copy(obj);
}
/**
* @name Two.Matrix#set
* @function
* @param {Number} a - The value for element at the first column and first row
* @param {Number} b - The value for element at the second column and first row
* @param {Number} c - The value for element at the third column and first row
* @param {Number} d - The value for element at the first column and second row
* @param {Number} e - The value for element at the second column and second row
* @param {Number} f - The value for element at the third column and second row
* @param {Number} g - The value for element at the first column and third row
* @param {Number} h - The value for element at the second column and third row
* @param {Number} i - The value for element at the third column and third row
* @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
*/
/**
* @name Two.Matrix#set
* @function
* @param {Number[]} a - The array of elements to apply
* @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
*/
set(a, b, c, d, e, f, g, h, i) {
if (typeof b === "undefined") {
const elements = a;
a = elements[0];
b = elements[1];
c = elements[2];
d = elements[3];
e = elements[4];
f = elements[5];
g = elements[6];
h = elements[7];
i = elements[8];
}
this.elements[0] = a;
this.elements[1] = b;
this.elements[2] = c;
this.elements[3] = d;
this.elements[4] = e;
this.elements[5] = f;
this.elements[6] = g;
this.elements[7] = h;
this.elements[8] = i;
return this.trigger(Events.Types.change);
}
/**
* @name Two.Matrix#copy
* @function
* @param {Two.Matrix} m - The matrix to copy
* @description Copy the matrix of one to the current instance.
*/
copy(m) {
this.elements[0] = m.elements[0];
this.elements[1] = m.elements[1];
this.elements[2] = m.elements[2];
this.elements[3] = m.elements[3];
this.elements[4] = m.elements[4];
this.elements[5] = m.elements[5];
this.elements[6] = m.elements[6];
this.elements[7] = m.elements[7];
this.elements[8] = m.elements[8];
this.manual = m.manual;
return this.trigger(Events.Types.change);
}
/**
* @name Two.Matrix#identity
* @function
* @description Turn matrix to the identity, like resetting.
*/
identity() {
this.elements[0] = _Matrix.Identity[0];
this.elements[1] = _Matrix.Identity[1];
this.elements[2] = _Matrix.Identity[2];
this.elements[3] = _Matrix.Identity[3];
this.elements[4] = _Matrix.Identity[4];
this.elements[5] = _Matrix.Identity[5];
this.elements[6] = _Matrix.Identity[6];
this.elements[7] = _Matrix.Identity[7];
this.elements[8] = _Matrix.Identity[8];
return this.trigger(Events.Types.change);
}
/**
* @name Two.Matrix#multiply
* @function
* @param {Number} s - The scalar to be multiplied.
* @description Multiply all components of the matrix against a single scalar value.
* @overloaded
*/
/**
* @name Two.Matrix#multiply
* @function
* @param {Number} x - The `x` component to be multiplied.
* @param {Number} y - The `y` component to be multiplied.
* @param {Number} z - The `z` component to be multiplied.
* @description Multiply all components of a matrix against a 3 component vector.
* @overloaded
*/
/**
* @name Two.Matrix#multiply
* @function
* @param {Number} a - The value at the first column and first row of the matrix to be multiplied.
* @param {Number} b - The value at the second column and first row of the matrix to be multiplied.
* @param {Number} c - The value at the third column and first row of the matrix to be multiplied.
* @param {Number} d - The value at the first column and second row of the matrix to be multiplied.
* @param {Number} e - The value at the second column and second row of the matrix to be multiplied.
* @param {Number} f - The value at the third column and second row of the matrix to be multiplied.
* @param {Number} g - The value at the first column and third row of the matrix to be multiplied.
* @param {Number} h - The value at the second column and third row of the matrix to be multiplied.
* @param {Number} i - The value at the third column and third row of the matrix to be multiplied.
* @description Multiply all components of a matrix against another matrix.
* @overloaded
*/
multiply(a, b, c, d, e, f, g, h, i) {
if (typeof b === "undefined") {
this.elements[0] *= a;
this.elements[1] *= a;
this.elements[2] *= a;
this.elements[3] *= a;
this.elements[4] *= a;
this.elements[5] *= a;
this.elements[6] *= a;
this.elements[7] *= a;
this.elements[8] *= a;
return this.trigger(Events.Types.change);
}
if (typeof c === "undefined") {
c = 1;
}
if (typeof d === "undefined") {
a = a || 0;
b = b || 0;
c = c || 0;
e = this.elements;
const x = e[0] * a + e[1] * b + e[2] * c;
const y = e[3] * a + e[4] * b + e[5] * c;
const z = e[6] * a + e[7] * b + e[8] * c;
return [x, y, z];
}
const A = this.elements;
const B = [a, b, c, d, e, f, g, h, i];
const A0 = A[0], A1 = A[1], A2 = A[2];
const A3 = A[3], A4 = A[4], A5 = A[5];
const A6 = A[6], A7 = A[7], A8 = A[8];
const B0 = B[0], B1 = B[1], B2 = B[2];
const B3 = B[3], B4 = B[4], B5 = B[5];
const B6 = B[6], B7 = B[7], B8 = B[8];
this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;
this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;
this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;
return this.trigger(Events.Types.change);
}
/**
* @name Two.Matrix#inverse
* @function
* @param {Two.Matrix} [output] - The optional matrix to apply the inversion to.
* @description Return an inverted version of the matrix. If no optional one is passed a new matrix is created and returned.
*/
inverse(output) {
const a = this.elements;
output = output || new _Matrix();
const a00 = a[0], a01 = a[1], a02 = a[2];
const a10 = a[3], a11 = a[4], a12 = a[5];
const a20 = a[6], a21 = a[7], a22 = a[8];
const b01 = a22 * a11 - a12 * a21;
const b11 = -a22 * a10 + a12 * a20;
const b21 = a21 * a10 - a11 * a20;
let det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1 / det;
output.elements[0] = b01 * det;
output.elements[1] = (-a22 * a01 + a02 * a21) * det;
output.elements[2] = (a12 * a01 - a02 * a11) * det;
output.elements[3] = b11 * det;
output.elements[4] = (a22 * a00 - a02 * a20) * det;
output.elements[5] = (-a12 * a00 + a02 * a10) * det;
output.elements[6] = b21 * det;
output.elements[7] = (-a21 * a00 + a01 * a20) * det;
output.elements[8] = (a11 * a00 - a01 * a10) * det;
return output;
}
/**
* @name Two.Matrix#scale
* @function
* @param {Number} s - The one dimensional scale to apply to the matrix.
* @description Uniformly scale the transformation matrix.
*/
/**
* @name Two.Matrix#scale
* @function
* @param {Number} sx - The horizontal scale factor.
* @param {Number} sy - The vertical scale factor
* @description Scale the transformation matrix in two dimensions.
*/
scale(sx, sy) {
const l = arguments.length;
if (l <= 1) {
sy = sx;
}
return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);
}
/**
* @name Two.Matrix#rotate
* @function
* @param {Number} n - The amount to rotate in Number.
* @description Rotate the matrix.
*/
rotate(n) {
const c = cos(n);
const s = sin(n);
return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);
}
/**
* @name Two.Matrix#translate
* @function
* @param {Number} x - The horizontal translation value to apply
* @param {Number} y - The vertical translation value to apply
* @description Translate the matrix to specific `x` / `y` values.
*/
translate(x, y) {
return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);
}
/**
* @name Two.Matrix#skewX
* @function
* @param {Number} n - The amount to skew
* @description Skew the matrix by an angle in the x axis direction.
*/
skewX(n) {
const a = tan(n);
return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);
}
/**
* @name Two.Matrix#skewY
* @function
* @param {Number} n - The amount to skew
* @description Skew the matrix by an angle in the y axis direction.
*/
skewY(n) {
const a = tan(n);
return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);
}
/**
* @name Two.Matrix#toString
* @function
* @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
* @returns {String} - The transformation matrix as a 6 component string separated by spaces.
* @description Create a transform string. Used for the Two.js rendering APIs.
*/
toString(fullMatrix) {
array.length = 0;
this.toTransformArray(fullMatrix, array);
return array.map(toFixed).join(" ");
}
/**
* @name Two.Matrix#toTransformArray
* @function
* @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 in the format for 2D transformations.
* @param {Number[]} [output] - An array empty or otherwise to apply the values to.
* @description Create a transform array. Used for the Two.js rendering APIs.
*/
toTransformArray(fullMatrix, output) {
const elements = this.elements;
const hasOutput = !!output;
const a = elements[0];
const b = elements[1];
const c = elements[2];
const d = elements[3];
const e = elements[4];
const f = elements[5];
if (fullMatrix) {
const g = elements[6];
const h = elements[7];
const i = elements[8];
if (hasOutput) {
output[0] = a;
output[1] = d;
output[2] = g;
output[3] = b;
output[4] = e;
output[5] = h;
output[6] = c;
output[7] = f;
output[8] = i;
return;
}
return [a, d, g, b, e, h, c, f, i];
}
if (hasOutput) {
output[0] = a;
output[1] = d;
output[2] = b;
output[3] = e;
output[4] = c;
output[5] = f;
return;
}
return [
a,
d,
b,
e,
c,
f
// Specific format see LN:19
];
}
/**
* @name Two.Matrix#toArray
* @function
* @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
* @param {Number[]} [output] - An array empty or otherwise to apply the values to.
* @description Create a transform array. Used for the Two.js rendering APIs.
*/
toArray(fullMatrix, output) {
const elements = this.elements;
const hasOutput = !!output;
const a = elements[0];
const b = elements[1];
const c = elements[2];
const d = elements[3];
const e = elements[4];
const f = elements[5];
if (fullMatrix) {
const g = elements[6];
const h = elements[7];
const i = elements[8];
if (hasOutput) {
output[0] = a;
output[1] = b;
output[2] = c;
output[3] = d;
output[4] = e;
output[5] = f;
output[6] = g;
output[7] = h;
output[8] = i;
return;
}
return [a, b, c, d, e, f, g, h, i];
}
if (hasOutput) {
output[0] = a;
output[1] = b;
output[2] = c;
output[3] = d;
output[4] = e;
output[5] = f;
return;
}
return [a, b, c, d, e, f];
}
/**
* @name Two.Matrix#toObject
* @function
* @description Create a JSON compatible object that represents information of the matrix.
* @nota-bene Works in conjunction with {@link Two.Matrix.fromObject}
*/
toObject() {
return {
renderer: { type: "matrix" },
elements: this.toArray(true),
manual: !!this.manual
};
}
/**
* @name Two.Matrix#clone
* @function
* @description Clone the current matrix.
*/
clone() {
return new _Matrix().copy(this);
}
};
setMatrix(Matrix2);
// src/shape.js
var Shape = class _Shape extends Element {
/**
* @name Two.Shape#_flagMatrix
* @private
* @property {Boolean} - Determines whether the matrix needs updating.
*/
_flagMatrix = true;
/**
* @name Two.Shape#_flagScale
* @private
* @property {Boolean} - Determines whether the scale needs updating.
*/
_flagScale = false;
// Underlying Properties
/**
* @name Two.Shape#_matrix
* @private
* @property {Two.Matrix} - The matrix value of the shape's position, rotation, and scale.
*/
_matrix = null;
/**
* @name Two.Shape#_worldMatrix
* @private
* @property {Two.Matrix} - The matrix value of the shape's position, rotation, and scale in the scene.
*/
_worldMatrix = null;
/**
* @name Two.Shape#_position
* @private
* @property {Two.Vector} - The translation values as a {@link Two.Vector}.
*/
_position = null;
/**
* @name Two.Shape#_rotation
* @private
* @property {Number} - The rotation value in radians.
*/
_rotation = 0;
/**
* @name Two.Shape#_scale
* @private
* @property {Number|Two.Vector} - The scale value in Number. Can be a vector for non-uniform scaling.
*/
_scale = 1;
/**
* @name Two.Shape#_skewX
* @private
* @property {Number} - The rotation value in Number.
*/
_skewX = 0;
/**
* @name Two.Shape#_skewY
* @private
* @property {Number} - The rotation value in Number.
*/
_skewY = 0;
constructor() {
super();
for (let prop in proto9) {
Object.defineProperty(this, prop, proto9[prop]);
}
this._renderer.flagMatrix = FlagMatrix.bind(this);
this.isShape = true;
this.matrix = new Matrix2();
this.worldMatrix = new Matrix2();
this.position = new Vector();
this.rotation = 0;
this.scale = 1;
this.skewX = 0;
this.skewY = 0;
}
static Properties = [
"position",
"rotation",
"scale",
"skewX",
"skewY",
"matrix",
"worldMatrix"
];
/**
* @name Two.Shape.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Shape} to create a new instance
* @returns {Two.Shape}
* @description Create a new {@link Two.Shape} from an object notation of a {@link Two.Shape}.
* @nota-bene Works in conjunction with {@link Two.Shape#toObject}
*/
static fromObject(obj) {
const shape = new _Shape().copy(obj);
if ("id" in obj) {
shape.id = obj.id;
}
return shape;
}
get renderer() {
return this._renderer;
}
set renderer(v) {
this._renderer = v;
}
/**
* @name Two.Shape#translation
* @description Alias for {@link Two.Shape#position}.
*/
get translation() {
return proto9.position.get.apply(this, arguments);
}
set translation(v) {
proto9.position.set.apply(this, arguments);
}
/**
* @name Two.Shape#addTo
* @function
* @param {Two.Group} group - The parent the shape adds itself to.
* @description Convenience method to add itself to the scenegraph.
*/
addTo(group) {
group.add(this);
return this;
}
/**
* @name Two.Shape#remove
* @function
* @description Remove self from the scene / parent.
*/
remove() {
if (!this.parent) {
return this;
}
this.parent.remove(this);
return this;
}
/**
* @name Two.Shape#contains
* @function
* @param {Number} x - x coordinate to hit test against
* @param {Number} y - y coordinate to hit test against
* @param {Object} [options] - Optional options object
* @param {Boolean} [options.ignoreVisibility] - If `true`, hit test against `shape.visible = false` shapes
* @param {Number} [options.tolerance] - Padding to hit test against in pixels
* @returns {Boolean}
* @description Check to see if coordinates are within a {@link Two.Shape}'s bounding rectangle
* @nota-bene Expects *world-space coordinates* – the same pixel-space you get from the renderer (e.g., mouse `clientX`/`clientY` adjusted for the canvas’s offset and pixel ratio).
*/
contains(x, y, options) {
const opts = options || {};
const ignoreVisibility = opts.ignoreVisibility === true;
if (!ignoreVisibility && "visible" in this && this.visible === false) {
return false;
}
if (!ignoreVisibility && "opacity" in this && typeof this.opacity === "number" && this.opacity <= 0) {
return false;
}
if (typeof this.getBoundingClientRect !== "function") {
return false;
}
const tolerance = typeof opts.tolerance === "number" ? opts.tolerance : 0;
this._update(true);
const rect = this.getBoundingClientRect();
if (!rect) {
return false;
}
return x >= rect.left - tolerance && x <= rect.right + tolerance && y >= rect.top - tolerance && y <= rect.bottom + tolerance;
}
/**
* @name Two.Shape#copy
* @function
* @param {Two.Shape} shape
* @description Copy the properties of one {@link Two.Shape} onto another.
*/
copy(shape) {
super.copy.call(this, shape);
if ("position" in shape) {
if (shape.position instanceof Vector) {
this.position = shape.position;
} else {
this.position.copy(shape.position);
}
}
if ("rotation" in shape) {
this.rotation = shape.rotation;
}
if ("scale" in shape) {
this.scale = typeof shape.scale === "number" || shape.scale instanceof Vector ? shape.scale : new Vector(shape.scale.x, shape.scale.y);
}
if ("skewX" in shape) {
this.skewX = shape.skewX;
}
if ("skewY" in shape) {
this.skewY = shape.skewY;
}
if ("matrix" in shape && shape.matrix.manual) {
this.matrix.copy(shape.matrix);
this.matrix.manual = true;
}
return this;
}
/**
* @name Two.Shape#clone
* @function
* @param {Two.Group} [parent] - Optional argument to automatically add the shape to a scenegraph.
* @returns {Two.Shape}
* @description Create a new {@link Two.Shape} with the same values as the current shape.
*/
clone(parent) {
const clone = new _Shape();
clone.position.copy(this.position);
clone.rotation = this.rotation;
clone.scale = this.scale;
clone.skewX = this.skewX;
clone.skewY = this.skewY;
if (this.matrix.manual) {
clone.matrix.copy(this.matrix);
}
if (parent) {
parent.add(clone);
}
return clone._update();
}
/**
* @name Two.Shape#toObject
* @function
* @description Create a JSON compatible object that represents information of the shape.
* @nota-bene Works in conjunction with {@link Two.Shape.fromObject}
*/
toObject() {
const result = super.toObject.call(this);
result.renderer = { type: "shape" };
result.isShape = true;
result.translation = this.translation.toObject();
result.rotation = this.translation.rotation;
result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale;
result.skewX = this.skewX;
result.skewY = this.skewY;
result.matrix = this.matrix.toObject();
return result;
}
/**
* @name Two.Shape#dispose
* @function
* @description Release the shape's bound objects by unbinding relevant events.
*/
dispose() {
super.dispose();
if (typeof this.translation === "object" && typeof this.translation.unbind === "function") {
this.translation.unbind();
}
if (typeof this.scale === "object" && typeof this.scale.unbind === "function") {
this.scale.unbind();
}
}
/**
* @name Two.Shape#_update
* @function
* @private
* @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
* @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
* @nota-bene Try not to call this method more than once a frame.
*/
_update(bubbles) {
if (!this._matrix.manual && this._flagMatrix) {
this._matrix.identity().translate(this.position.x, this.position.y);
this._matrix.rotate(this.rotation);
if (this._scale instanceof Vector) {
this._matrix.scale(this._scale.x, this._scale.y);
} else {
this._matrix.scale(this._scale);
}
this._matrix.skewX(this.skewX);
this._matrix.skewY(this.skewY);
}
if (bubbles) {
if (this.parent && this.parent._update) {
this.parent._update();
}
}
return this;
}
/**
* @name Two.Shape#flagReset
* @function
* @private
* @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
*/
flagReset() {
this._flagMatrix = this._flagScale = false;
super.flagReset.call(this);
return this;
}
};
var proto9 = {
position: {
enumerable: true,
get: function() {
return this._position;
},
set: function(v) {
if (this._position) {
this._position.unbind(Events.Types.change, this._renderer.flagMatrix);
}
this._position = v;
this._position.bind(Events.Types.change, this._renderer.flagMatrix);
FlagMatrix.call(this);
}
},
rotation: {
enumerable: true,
get: function() {
return this._rotation;
},
set: function(v) {
this._rotation = v;
this._flagMatrix = true;
}
},
scale: {
enumerable: true,
get: function() {
return this._scale;
},
set: function(v) {
if (this._scale instanceof Vector) {
this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
}
this._scale = v;
if (this._scale instanceof Vector) {
this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
}
this._flagMatrix = true;
this._flagScale = true;
}
},
skewX: {
enumerable: true,
get: function() {
return this._skewX;
},
set: function(v) {
this._skewX = v;
this._flagMatrix = true;
}
},
skewY: {
enumerable: true,
get: function() {
return this._skewY;
},
set: function(v) {
this._skewY = v;
this._flagMatrix = true;
}
},
matrix: {
enumerable: true,
get: function() {
return this._matrix;
},
set: function(v) {
this._matrix = v;
this._flagMatrix = true;
}
},
worldMatrix: {
enumerable: true,
get: function() {
getComputedMatrix(this, this._worldMatrix);
return this._worldMatrix;
},
set: function(v) {
this._worldMatrix = v;
}
}
};
function FlagMatrix() {
this._flagMatrix = true;
}
// src/utils/hit-test.js
var TRANSPARENT_REGEX = /^(?:none|transparent)$/i;
var DEFAULT_PRECISION = 8;
var EPSILON = Number.EPSILON;
function createPoint(x, y) {
return { x, y };
}
function pointsEqual(a, b, epsilon = EPSILON) {
return Math.abs(a.x - b.x) <= epsilon && Math.abs(a.y - b.y) <= epsilon;
}
function svgAngle(ux, uy, vx, vy) {
const dot = ux * vx + uy * vy;
const len = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy) || 1e-12;
let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));
if (ux * vy - uy * vx < 0) {
ang = -ang;
}
return ang;
}
function sampleArcPoints(prev, anchor2, precision) {
if (!prev) {
return [createPoint(anchor2.x, anchor2.y)];
}
let rx = anchor2.rx;
let ry = anchor2.ry;
if (!(rx && ry)) {
return [createPoint(anchor2.x, anchor2.y)];
}
const xAxisRotation = (anchor2.xAxisRotation || 0) * Math.PI / 180;
const largeArcFlag = anchor2.largeArcFlag ? 1 : 0;
const sweepFlag = anchor2.sweepFlag ? 1 : 0;
rx = Math.abs(rx);
ry = Math.abs(ry);
const ax = prev.x;
const ay = prev.y;
const x = anchor2.x;
const y = anchor2.y;
const dx2 = (ax - x) / 2;
const dy2 = (ay - y) / 2;
const cosRot = Math.cos(xAxisRotation);
const sinRot = Math.sin(xAxisRotation);
let x1p = cosRot * dx2 + sinRot * dy2;
let y1p = -sinRot * dx2 + cosRot * dy2;
let rxs = rx * rx;
let rys = ry * ry;
const cr = x1p * x1p / rxs + y1p * y1p / rys;
if (cr > 1) {
const s = Math.sqrt(cr);
rx *= s;
ry *= s;
rxs = rx * rx;
rys = ry * ry;
}
const dq = rxs * y1p * y1p + rys * x1p * x1p;
const pq = dq === 0 ? 0 : (rxs * rys - dq) / dq;
let q = Math.sqrt(Math.max(0, pq));
if (largeArcFlag === sweepFlag) {
q = -q;
}
const cxp = q * rx * y1p / ry;
const cyp = -q * ry * x1p / rx;
const cx = cosRot * cxp - sinRot * cyp + (ax + x) / 2;
const cy = sinRot * cxp + cosRot * cyp + (ay + y) / 2;
const startAngle = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
const delta = svgAngle(
(x1p - cxp) / rx,
(y1p - cyp) / ry,
(-x1p - cxp) / rx,
(-y1p - cyp) / ry
) % TWO_PI;
const endAngle = startAngle + delta;
const clockwise = sweepFlag === 0;
const angleDelta = (() => {
const raw = endAngle - startAngle;
const samePoints = Math.abs(raw) < Number.EPSILON;
let deltaAngle = mod(raw, TWO_PI);
if (deltaAngle < Number.EPSILON) {
deltaAngle = samePoints ? 0 : TWO_PI;
}
if (clockwise && !samePoints) {
deltaAngle = deltaAngle === TWO_PI ? -TWO_PI : deltaAngle - TWO_PI;
}
return deltaAngle;
})();
const steps = Math.max(Constants.Resolution, Math.max(precision * 2, 1));
const points = [];
for (let i = 1; i <= steps; i++) {
const t = i / steps;
const angle = startAngle + t * angleDelta;
let px = cx + rx * Math.cos(angle);
let py = cy + ry * Math.sin(angle);
if (xAxisRotation !== 0) {
const tx = px - cx;
const ty = py - cy;
const cosR = Math.cos(xAxisRotation);
const sinR = Math.sin(xAxisRotation);
px = tx * cosR - ty * sinR + cx;
py = tx * sinR + ty * cosR + cy;
}
points.push(createPoint(px, py));
}
return points;
}
function buildPathHitParts(path, precision = DEFAULT_PRECISION) {
const polygons = [];
const segments = [];
const vertices = path._renderer && path._renderer.vertices && path._renderer.vertices.length > 0 ? path._renderer.vertices : path.vertices;
if (!vertices || vertices.length === 0) {
return { polygons, segments };
}
const limit = Math.max(1, Math.floor(precision));
let currentPolygon = null;
let firstPoint = null;
let lastPoint = null;
let prevVertex = null;
const closePolygon = (forceClose = false) => {
if (!currentPolygon) {
return;
}
if (forceClose && firstPoint && lastPoint && !pointsEqual(firstPoint, lastPoint)) {
const closingPoint = createPoint(firstPoint.x, firstPoint.y);
segments.push({ a: lastPoint, b: closingPoint });
currentPolygon.push(closingPoint);
lastPoint = closingPoint;
}
if (currentPolygon.length >= 3 && firstPoint && lastPoint && pointsEqual(firstPoint, lastPoint)) {
polygons.push(currentPolygon);
}
currentPolygon = null;
firstPoint = null;
lastPoint = null;
};
const appendPoint = (pt) => {
if (!lastPoint) {
lastPoint = pt;
if (currentPolygon) {
currentPolygon.push(pt);
}
return;
}
if (pointsEqual(lastPoint, pt)) {
return;
}
segments.push({ a: lastPoint, b: pt });
if (currentPolygon) {
currentPolygon.push(pt);
}
lastPoint = pt;
};
for (let i = 0; i < vertices.length; i++) {
const vertex = vertices[i];
const command = vertex.command || (i === 0 ? Commands.move : Commands.line);
if (command === Commands.move) {
closePolygon(false);
const pt = createPoint(vertex.x, vertex.y);
currentPolygon = [pt];
firstPoint = pt;
lastPoint = pt;
prevVertex = vertex;
continue;
}
if (!prevVertex) {
prevVertex = vertices[Math.max(i - 1, 0)];
}
if (command === Commands.line) {
appendPoint(createPoint(vertex.x, vertex.y));
} else if (command === Commands.curve) {
const subdivisions = getSubdivisions(vertex, prevVertex, limit);
for (let j = 1; j < subdivisions.length; j++) {
const sv = subdivisions[j];
appendPoint(createPoint(sv.x, sv.y));
}
appendPoint(createPoint(vertex.x, vertex.y));
} else if (command === Commands.arc) {
const arcPoints = sampleArcPoints(prevVertex, vertex, limit);
for (let j = 0; j < arcPoints.length; j++) {
appendPoint(arcPoints[j]);
}
} else if (command === Commands.close) {
closePolygon(true);
prevVertex = vertex;
continue;
} else {
appendPoint(createPoint(vertex.x, vertex.y));
}
prevVertex = vertex;
}
if (currentPolygon) {
const shouldForceClose = !!path._closed || !!path.closed || firstPoint && lastPoint && !pointsEqual(firstPoint, lastPoint);
closePolygon(shouldForceClose);
}
return { polygons, segments };
}
function pointInPolygons(polygons, x, y) {
let inside = false;
for (let i = 0; i < polygons.length; i++) {
const polygon = polygons[i];
if (!polygon || polygon.length < 3) {
continue;
}
let lastIndex = polygon.length - 1;
for (let j = 0; j < polygon.length; j++) {
const v0 = polygon[lastIndex];
const v1 = polygon[j];
const intersects = v1.y > y !== v0.y > y && x < (v0.x - v1.x) * (y - v1.y) / (v0.y - v1.y || 1e-12) + v1.x;
if (intersects) {
inside = !inside;
}
lastIndex = j;
}
}
return inside;
}
function distanceToSegmentSquared(x, y, a, b) {
const dx = b.x - a.x;
const dy = b.y - a.y;
if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) {
const ddx2 = x - a.x;
const ddy2 = y - a.y;
return ddx2 * ddx2 + ddy2 * ddy2;
}
const t = ((x - a.x) * dx + (y - a.y) * dy) / (dx * dx + dy * dy);
const clamped = Math.max(0, Math.min(1, t));
const cx = a.x + clamped * dx;
const cy = a.y + clamped * dy;
const ddx = x - cx;
const ddy = y - cy;
return ddx * ddx + ddy * ddy;
}
function distanceToSegments(segments, x, y) {
if (!segments || segments.length === 0) {
return Infinity;
}
let minDistance = Infinity;
for (let i = 0; i < segments.length; i++) {
const segment = segments[i];
const distance = distanceToSegmentSquared(x, y, segment.a, segment.b);
if (distance < minDistance) {
minDistance = distance;
}
}
return Math.sqrt(minDistance);
}
function hasVisibleFill(shape, override) {
if (typeof override === "boolean") {
return override;
}
const fill = shape.fill;
if (!fill && fill !== 0) {
return false;
}
if (typeof fill === "string") {
return !TRANSPARENT_REGEX.test(fill);
}
return true;
}
function hasVisibleStroke(shape, override) {
const linewidth = typeof shape.linewidth === "number" ? shape.linewidth : shape._linewidth || 0;
if (typeof override === "boolean") {
return override && linewidth > 0;
}
if (!(linewidth > 0)) {
return false;
}
const stroke = shape.stroke;
if (!stroke && stroke !== 0) {
return false;
}
if (typeof stroke === "string") {
return !TRANSPARENT_REGEX.test(stroke);
}
return true;
}
function boundsContains(rect, x, y, tolerance = 0) {
if (!rect) {
return false;
}
const left = rect.left - tolerance;
const right = rect.right + tolerance;
const top = rect.top - tolerance;
const bottom = rect.bottom + tolerance;
return x >= left && x <= right && y >= top && y <= bottom;
}
// src/utils/path.js
var EPSILON2 = Number.EPSILON;
function isRelativeAnchor(anchor2) {
return !(typeof anchor2.relative === "boolean") || !!anchor2.relative;
}
function setHandleComponent(anchor2, side, dx, dy) {
const controls = anchor2.controls;
if (!controls || !controls[side]) {
return;
}
if (Math.abs(dx) < EPSILON2 && Math.abs(dy) < EPSILON2) {
if (isRelativeAnchor(anchor2)) {
controls[side].clear();
} else {
controls[side].set(anchor2.x, anchor2.y);
}
return;
}
if (isRelativeAnchor(anchor2)) {
controls[side].set(dx, dy);
} else {
controls[side].set(anchor2.x + dx, anchor2.y + dy);
}
}
function clearHandleComponent(anchor2, side) {
setHandleComponent(anchor2, side, 0, 0);
}
function getHandleOffset(anchor2, side) {
const controls = anchor2.controls;
if (!controls || !controls[side]) {
return { x: 0, y: 0 };
}
if (isRelativeAnchor(anchor2)) {
return { x: controls[side].x, y: controls[side].y };
}
return {
x: controls[side].x - anchor2.x,
y: controls[side].y - anchor2.y
};
}
function hasNonZeroHandle(anchor2, side) {
const offset = getHandleOffset(anchor2, side);
return Math.abs(offset.x) > EPSILON2 || Math.abs(offset.y) > EPSILON2;
}
function updateAnchorCommand(anchor2) {
if (anchor2.command === Commands.move || anchor2.command === Commands.close) {
return;
}
anchor2.command = hasNonZeroHandle(anchor2, "left") || hasNonZeroHandle(anchor2, "right") ? Commands.curve : Commands.line;
}
function inheritRelative(anchor2, reference) {
if (typeof reference.relative === "boolean") {
anchor2.relative = reference.relative;
}
}
function isSegmentCurved(a, b) {
return hasNonZeroHandle(b, "right") || hasNonZeroHandle(a, "left") || hasNonZeroHandle(a, "right") || hasNonZeroHandle(b, "left") || a.command === Commands.curve || b.command === Commands.curve;
}
function lerpPoint(a, b, t) {
return {
x: lerp(a.x, b.x, t),
y: lerp(a.y, b.y, t)
};
}
function getAbsoluteHandle(anchor2, side) {
const controls = anchor2.controls && anchor2.controls[side];
if (!controls) {
return { x: anchor2.x, y: anchor2.y };
}
if (isRelativeAnchor(anchor2)) {
return { x: anchor2.x + controls.x, y: anchor2.y + controls.y };
}
return { x: controls.x, y: controls.y };
}
function splitSubdivisionSegment(start, end, t) {
const right = start.controls && start.controls.right;
const left = end.controls && end.controls.left;
const p0 = { x: start.x, y: start.y };
const p1 = right ? getAbsoluteHandle(start, "right") : { ...p0 };
const p3 = { x: end.x, y: end.y };
const p2 = left ? getAbsoluteHandle(end, "left") : { ...p3 };
const q0 = lerpPoint(p0, p1, t);
const q1 = lerpPoint(p1, p2, t);
const q2 = lerpPoint(p2, p3, t);
const r0 = lerpPoint(q0, q1, t);
const r1 = lerpPoint(q1, q2, t);
const point = lerpPoint(r0, r1, t);
const anchor2 = new Anchor(point.x, point.y);
inheritRelative(anchor2, start);
setHandleComponent(anchor2, "left", r0.x - point.x, r0.y - point.y);
setHandleComponent(anchor2, "right", r1.x - point.x, r1.y - point.y);
anchor2.command = Commands.curve;
return {
anchor: anchor2,
startOut: q0,
endIn: q2
};
}
function applyGlobalSmooth(vertices, from, to, closed2, loop2, asymmetric) {
const length = vertices.length;
const amount = to - from + 1;
let n = amount - 1;
let padding = loop2 ? Math.min(amount, 4) : 1;
let paddingLeft = padding;
let paddingRight = padding;
if (!closed2) {
paddingLeft = Math.min(1, from);
paddingRight = Math.min(1, length - to - 1);
}
n += paddingLeft + paddingRight;
if (n <= 1) {
return;
}
const knots = new Array(n + 1);
for (let i = 0, j = from - paddingLeft; i <= n; i += 1, j += 1) {
const index = mod(j, length);
knots[i] = vertices[index];
}
let x = knots[0].x + 2 * knots[1].x;
let y = knots[0].y + 2 * knots[1].y;
let f = 2;
const n1 = n - 1;
const rx = [x];
const ry = [y];
const rf = [f];
const px = new Array(n + 1);
const py = new Array(n + 1);
for (let i = 1; i < n; i += 1) {
const internal = i < n1;
const a = internal ? 1 : asymmetric ? 1 : 2;
const b = internal ? 4 : asymmetric ? 2 : 7;
const u = internal ? 4 : asymmetric ? 3 : 8;
const v = internal ? 2 : asymmetric ? 0 : 1;
const m = a / f;
f = rf[i] = b - m;
x = rx[i] = u * knots[i].x + v * knots[i + 1].x - m * x;
y = ry[i] = u * knots[i].y + v * knots[i + 1].y - m * y;
}
px[n1] = rx[n1] / rf[n1];
py[n1] = ry[n1] / rf[n1];
for (let i = n - 2; i >= 0; i -= 1) {
px[i] = (rx[i] - px[i + 1]) / rf[i];
py[i] = (ry[i] - py[i + 1]) / rf[i];
}
px[n] = (3 * knots[n].x - px[n1]) / 2;
py[n] = (3 * knots[n].y - py[n1]) / 2;
const max5 = n - paddingRight;
for (let i = paddingLeft, j = from; i <= max5; i += 1, j += 1) {
const index = mod(j, length);
const anchor2 = vertices[index];
const hx = px[i] - anchor2.x;
const hy = py[i] - anchor2.y;
if (loop2 || i < max5) {
setHandleComponent(anchor2, "right", hx, hy);
} else {
clearHandleComponent(anchor2, "right");
}
if (loop2 || i > paddingLeft) {
setHandleComponent(anchor2, "left", -hx, -hy);
} else {
clearHandleComponent(anchor2, "left");
}
updateAnchorCommand(anchor2);
}
}
function applyCatmullRom(anchor2, prev, next, factor, clampIn, clampOut) {
const p0 = prev || anchor2;
const p1 = anchor2;
const p2 = next || anchor2;
const d1 = Vector.distanceBetween(p0, p1);
const d2 = Vector.distanceBetween(p1, p2);
const a = factor === void 0 ? 0.5 : factor;
const d1a = Math.pow(d1, a);
const d2a = Math.pow(d2, a);
const d1_2a = d1a * d1a;
const d2_2a = d2a * d2a;
if (!clampIn && prev) {
const A = 2 * d2_2a + 3 * d2a * d1a + d1_2a;
const N = 3 * d2a * (d2a + d1a);
if (N !== 0) {
const hx = (d2_2a * p0.x + A * p1.x - d1_2a * p2.x) / N - p1.x;
const hy = (d2_2a * p0.y + A * p1.y - d1_2a * p2.y) / N - p1.y;
setHandleComponent(anchor2, "left", hx, hy);
} else {
clearHandleComponent(anchor2, "left");
}
} else {
clearHandleComponent(anchor2, "left");
}
if (!clampOut && next) {
const A = 2 * d1_2a + 3 * d1a * d2a + d2_2a;
const N = 3 * d1a * (d1a + d2a);
if (N !== 0) {
const hx = (d1_2a * p2.x + A * p1.x - d2_2a * p0.x) / N - p1.x;
const hy = (d1_2a * p2.y + A * p1.y - d2_2a * p0.y) / N - p1.y;
setHandleComponent(anchor2, "right", hx, hy);
} else {
clearHandleComponent(anchor2, "right");
}
} else {
clearHandleComponent(anchor2, "right");
}
updateAnchorCommand(anchor2);
}
function applyGeometric(anchor2, prev, next, factor, clampIn, clampOut) {
if (!(prev && next)) {
if (!prev) {
clearHandleComponent(anchor2, "left");
}
if (!next) {
clearHandleComponent(anchor2, "right");
}
updateAnchorCommand(anchor2);
return;
}
const p0 = prev;
const p1 = anchor2;
const p2 = next;
const d1 = Vector.distanceBetween(p0, p1);
const d2 = Vector.distanceBetween(p1, p2);
const total = d1 + d2;
const tension = factor === void 0 ? 0.4 : factor;
const vector3 = { x: p0.x - p2.x, y: p0.y - p2.y };
if (!clampIn && total !== 0) {
const k = tension * d1 / total;
setHandleComponent(anchor2, "left", vector3.x * k, vector3.y * k);
} else {
clearHandleComponent(anchor2, "left");
}
if (!clampOut && total !== 0) {
const k = tension * d1 / total - tension;
setHandleComponent(anchor2, "right", vector3.x * k, vector3.y * k);
} else {
clearHandleComponent(anchor2, "right");
}
updateAnchorCommand(anchor2);
}
function applyLocalSmooth(vertices, from, to, closed2, loop2, options) {
const type = options.type || "catmull-rom";
const factor = options.factor;
const length = vertices.length;
for (let i = from; i <= to; i += 1) {
const index = mod(i, length);
const anchor2 = vertices[index];
if (anchor2.command === Commands.move) {
clearHandleComponent(anchor2, "left");
clearHandleComponent(anchor2, "right");
continue;
}
const prevIndex = i === from && !loop2 ? null : i - 1;
const nextIndex = i === to && !loop2 ? null : i + 1;
const prev = prevIndex === null ? null : vertices[mod(prevIndex, length)];
const next = nextIndex === null ? null : vertices[mod(nextIndex, length)];
const clampIn = prevIndex === null;
const clampOut = nextIndex === null;
if (type === "geometric") {
applyGeometric(anchor2, prev, next, factor, clampIn, clampOut);
} else {
applyCatmullRom(anchor2, prev, next, factor, clampIn, clampOut);
}
}
}
// src/path.js
var min = Math.min;
var max = Math.max;
var ceil = Math.ceil;
var floor2 = Math.floor;
var vector = new Vector();
var hitTestMatrix = new Matrix2();
var Path = class _Path extends Shape {
/**
* @name Two.Path#_flagVertices
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#vertices} need updating.
*/
_flagVertices = true;
/**
* @name Two.Path#_flagLength
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#length} needs updating.
*/
_flagLength = true;
/**
* @name Two.Path#_flagFill
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#fill} needs updating.
*/
_flagFill = true;
/**
* @name Two.Path#_flagStroke
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#stroke} needs updating.
*/
_flagStroke = true;
/**
* @name Two.Path#_flagLinewidth
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#linewidth} needs updating.
*/
_flagLinewidth = true;
/**
* @name Two.Path#_flagOpacity
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#opacity} needs updating.
*/
_flagOpacity = true;
/**
* @name Two.Path#_flagVisible
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#visible} needs updating.
*/
_flagVisible = true;
/**
* @name Two.Path#_flagCap
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#cap} needs updating.
*/
_flagCap = true;
/**
* @name Two.Path#_flagJoin
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#join} needs updating.
*/
_flagJoin = true;
/**
* @name Two.Path#_flagMiter
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#miter} needs updating.
*/
_flagMiter = true;
/**
* @name Two.Path#_flagStrokeAttenuation
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#strokeAttenuation} needs updating.
*/
_flagStrokeAttenuation = true;
/**
* @name Two.Path#_flagMask
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#mask} needs updating.
*/
_flagMask = false;
/**
* @name Two.Path#_flagClip
* @private
* @property {Boolean} - Determines whether the {@link Two.Path#clip} needs updating.
*/
_flagClip = false;
// Underlying Properties
/**
* @name Two.Path#_length
* @private
* @see {@link Two.Path#length}
*/
_length = 0;
/**
* @name Two.Path#_fill
* @private
* @see {@link Two.Path#fill}
*/
_fill = "#fff";
/**
* @name Two.Path#_stroke
* @private
* @see {@link Two.Path#stroke}
*/
_stroke = "#000";
/**
* @name Two.Path#_linewidth
* @private
* @see {@link Two.Path#linewidth}
*/
_linewidth = 1;
/**
* @name Two.Path#_opacity
* @private
* @see {@link Two.Path#opacity}
*/
_opacity = 1;
/**
* @name Two.Path#_visible
* @private
* @see {@link Two.Path#visible}
*/
_visible = true;
/**
* @name Two.Path#_cap
* @private
* @see {@link Two.Path#cap}
*/
_cap = "round";
/**
* @name Two.Path#_join
* @private
* @see {@link Two.Path#join}
*/
_join = "round";
/**
* @name Two.Path#_miter
* @private
* @see {@link Two.Path#miter}
*/
_miter = 4;
/**
* @name Two.Path#_closed
* @private
* @see {@link Two.Path#closed}
*/
_closed = true;
/**
* @name Two.Path#_curved
* @private
* @see {@link Two.Path#curved}
*/
_curved = false;
/**
* @name Two.Path#_automatic
* @private
* @see {@link Two.Path#automatic}
*/
_automatic = true;
/**
* @name Two.Path#_beginning
* @private
* @see {@link Two.Path#beginning}
*/
_beginning = 0;
/**
* @name Two.Path#_ending
* @private
* @see {@link Two.Path#ending}
*/
_ending = 1;
/**
* @name Two.Path#_mask
* @private
* @see {@link Two.Path#mask}
*/
_mask = null;
/**
* @name Two.Path#_clip
* @private
* @see {@link Two.Path#clip}
*/
_clip = false;
/**
* @name Two.Path#_dashes
* @private
* @see {@link Two.Path#dashes}
*/
_dashes = null;
/**
* @name Two.Path#_strokeAttenuation
* @private
* @see {@link Two.Path#strokeAttenuation}
*/
_strokeAttenuation = true;
constructor(vertices, closed2, curved, manual) {
super();
for (let prop in proto10) {
Object.defineProperty(this, prop, proto10[prop]);
}
this._renderer.type = "path";
this._renderer.flagVertices = FlagVertices.bind(this);
this._renderer.bindVertices = BindVertices.bind(this);
this._renderer.unbindVertices = UnbindVertices.bind(this);
this._renderer.flagFill = FlagFill.bind(this);
this._renderer.flagStroke = FlagStroke.bind(this);
this._renderer.vertices = [];
this._renderer.collection = [];
this.closed = !!closed2;
this.curved = !!curved;
this.beginning = 0;
this.ending = 1;
this.fill = "#fff";
this.stroke = "#000";
this.linewidth = 1;
this.opacity = 1;
this.className = "";
this.visible = true;
this.cap = "butt";
this.join = "miter";
this.miter = 4;
this.vertices = vertices;
this.automatic = !manual;
this.dashes = [];
this.dashes.offset = 0;
}
/**
* @name Two.Path.Properties
* @property {String[]} - A list of properties that are on every {@link Two.Path}.
*/
static Properties = [
"fill",
"stroke",
"linewidth",
"opacity",
"visible",
"cap",
"join",
"miter",
"closed",
"curved",
"automatic",
"beginning",
"ending",
"dashes",
"strokeAttenuation"
];
static Utils = {
getCurveLength: getCurveLength2
};
/**
* @name Two.Path.fromObject
* @function
* @param {Object} obj - Object notation of a {@link Two.Path} to create a new instance
* @returns {Two.Path}
* @description Create a new {@link Two.Path} from an object notation of a {@link Two.Path}.
* @nota-bene Works in conjunction with {@link Two.Path#toObject}
*/
static fromObject(obj) {
const fill = typeof obj.fill === "string" ? obj.fill : getEffectFromObject(obj.fill);
const stroke = typeof obj.stroke === "string" ? obj.stroke : getEffectFromObject(obj.stroke);
const path = new _Path().copy({ ...obj, fill, stroke });
if ("id" in obj) {
path.id = obj.id;
}
return path;
}
/**
* @name Two.Path#copy
* @function
* @param {Two.Path} path - The reference {@link Two.Path}
* @description Copy the properties of one {@link Two.Path} onto another.
*/
copy(path) {
super.copy.call(this, path);
if (path.vertices) {
this.vertices = [];
for (let j = 0; j < path.vertices.length; j++) {
const v = path.vertices[j];
if (v instanceof Anchor) {
this.vertices.push(path.vertices[j].clone());
} else {
this.vertices.push(new Anchor().copy(v));
}
}
}
for (let i = 0; i < _Path.Properties.length; i++) {
const k = _Path.Properties[i];
if (k in path) {
this[k] = path[k];
}
}
return this;
}
/**
* @name Two.Path#clone
* @function
* @param {Two.Group} [parent] - The parent group or scene to add the clone to.
* @returns {Two.Path}
* @description Create a new instance of {@link Two.Path} with the same properties of the current path.
*/
clone(parent) {
const clone = new _Path();
for (let j = 0; j < this.vertices.length; j++) {
clone.vertices.push(this.vertices[j].clone());
}
for (let i = 0; i < _Path.Properties.length; i++) {
const k = _Path.Properties[i];
clone[k] = this[k];
}
clone.className = this.className;
clone.translation.copy(this.translation);
clone.rotation = this.rotation;
clone.scale = this.scale;
clone.skewX = this.skewX;
clone.skewY = this.skewY;
if (this.matrix.manual) {
clone.matrix.copy(this.matrix);
}
if (parent) {
parent.add(clone);
}
return clone._update();
}
/**
* @name Two.Path#toObject
* @function
* @returns {Object}
* @description Return a JSON compatible plain object that represents the path.
* @nota-bene Works in conjunction with {@link Two.Path.fromObject}
*/
toObject() {
const result = super.toObject.call(this);
result.renderer.type = "path";
result.vertices = this.vertices.map((v) => v.toObject());
_.each(
_Path.Properties,
(k) => {
if (typeof this[k] !== "undefined") {
if (this[k].toObject) {
result[k] = this[k].toObject();
} else {
result[k] = this[k];
}
}
},
this
);
return result;
}
/**
* @name Two.Path#dispose
* @function
* @returns {Two.Path}
* @description Release the path's renderer resources and detach all events.
* This method cleans up vertices collection events, individual vertex events,
* control point events, and disposes fill/stroke effects (calling dispose()
* on Gradients and Textures for thorough cleanup) while preserving the
* renderer type for potential re-attachment to a new renderer.
*/
dispose() {
super.dispose();
if (this.vertices && typeof this.vertices.unbind === "function") {
try {
this.vertices.unbind();
} catch (e) {
}
}
if (this.vertices) {
for (let i = 0; i < this.vertices.length; i++) {
const v = this.vertices[i];
if (typeof v.unbind === "function") {
v.unbind();
}
if (v.controls) {
if (v.controls.left && typeof v.controls.left.unbind === "function") {
v.controls.left.unbind();
}
if (v.controls.right && typeof v.controls.right.unbind === "function") {
v.controls.right.unbind();
}
}
}
}
if (typeof this.fill === "object" && typeof this.fill.dispose === "function") {
this.fill.dispose();
} else if (typeof this.fill === "object" && typeof this.fill.unbind === "function") {
this.fill.unbind();
}
if (typeof this.stroke === "object" && typeof this.stroke.dispose === "function") {
this.stroke.dispose();
} else if (typeof this.stroke === "object" && typeof this.stroke.unbind === "function") {
this.stroke.unbind();
}
return this;
}
/**
* @name Two.Path#noFill
* @function
* @description Short hand method to set fill to `none`.
*/
noFill() {
this.fill = "none";
return this;
}
/**
* @name Two.Path#noStroke
* @function
* @description Short hand method to set stroke to `none`.
*/
noStroke() {
this.stroke = "none";
this.linewidth = 0;
return this;
}
/**
* @name Two.Path#corner
* @function
* @description Orient the vertices of the shape to the upper left-hand corner of the path.
*/
corner() {
const rect = this.getBoundingClientRect(true);
const hw = rect.width / 2;
const hh = rect.height / 2;
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
for (let i = 0; i < this.vertices.length; i++) {
const v = this.vertices[i];
v.x -= cx;
v.y -= cy;
v.x += hw;
v.y += hh;
}
if (this.mask) {
this.mask.translation.x -= cx;
this.mask.translation.x += hw;
this.mask.translation.y -= cy;
this.mask.translation.y += hh;
}
return this;
}
/**
* @name Two.Path#center
* @function
* @description Orient the vertices of the shape to the center of the path.
*/
center() {
const rect = this.getBoundingClientRect(true);
const cx = rect.left + rect.width / 2 - this.translation.x;
const cy = rect.top + rect.height / 2 - this.translation.y;
for (let i = 0; i < this.vertices.length; i++) {
const v = this.vertices[i];
v.x -= cx;
v.y -= cy;
}
if (this.mask) {
this.mask.translation.x -= cx;
this.mask.translation.y -= cy;
}
return this;
}
/**
* @name Two.Path#getBoundingClientRect
* @function
* @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
* @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
* @description Return an object with top, left, right, bottom, width, and height parameters of the path.
*/
getBoundingClientRect(shallow) {
let matrix, border, l, i, v0, v1;
let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity;
this._update(true);
matrix = shallow ? this.matrix : this.worldMatrix;
border = (this.linewidth || 0) / 2;
l = this._renderer.vertices.length;
if (this.linewidth > 0 || this.stroke && !/(transparent|none)/i.test(this.stroke)) {
if (this.matrix.manual) {
const { scaleX, scaleY } = decomposeMatrix(
matrix.elements[0],
matrix.elements[3],
matrix.elements[1],
matrix.elements[4],
matrix.elements[2],
matrix.elements[5]
);
if (typeof scaleX === "number" && typeof scaleY === "number") {
border = Math.max(scaleX, scaleY) * (this.linewidth || 0) / 2;
}
} else {
border *= typeof this.scale === "number" ? this.scale : Math.max(this.scale.x, this.scale.y);
}
}
if (l <= 0) {
return {
width: 0,
height: 0
};
}
for (i = 0; i < l; i++) {
v1 = this._renderer.vertices[i];
v0 = this._renderer.vertices[(i + l - 1) % l];
const [v0x, v0y] = matrix.multiply(v0.x, v0.y);
const [v1x, v1y] = matrix.multiply(v1.x, v1.y);
if (v0.controls && v1.controls) {
let rx = v0.controls.right.x;
let ry = v0.controls.right.y;
if (v0.relative) {
rx += v0.x;
ry += v0.y;
}
let [c0x, c0y] = matrix.multiply(rx, ry);
let lx = v1.controls.left.x;
let ly = v1.controls.left.y;
if (v1.relative) {
lx += v1.x;
ly += v1.y;
}
let [c1x, c1y] = matrix.multiply(lx, ly);
const bb = getCurveBoundingBox(v0x, v0y, c0x, c0y, c1x, c1y, v1x, v1y);
top = min(bb.min.y - border, top);
left = min(bb.min.x - border, left);
right = max(bb.max.x + border, right);
bottom = max(bb.max.y + border, bottom);
} else {
if (i <= 1) {
top = min(v0y - border, top);
left = min(v0x - border, left);
right = max(v0x + border, right);
bottom = max(v0y + border, bottom);
}
top = min(v1y - border, top);
left = min(v1x - border, left);
right = max(v1x + border, right);
bottom = max(v1y + border, bottom);
}
}
return {
top,
left,
right,
bottom,
width: right - left,
height: bottom - top
};
}
/**
* @name Two.Path#contains
* @function
* @param {Number} x - x coordinate to hit test against
* @param {Number} y - y coordinate to hit test against
* @param {Object} [options] - Optional options object
* @param {Boolean} [options.ignoreVisibility] - If `true`, hit test against `path.visible = false` shapes
* @param {Number} [options.tolerance] - Padding to hit test against in pixels
* @returns {Boolean}
gitextract_pil82dhw/
├── .eslintignore
├── .eslintrc.json
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ ├── output.md
│ │ └── question.md
│ └── workflows/
│ ├── codeql.yml
│ ├── lint.yml
│ └── publish.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── build/
│ ├── two.js
│ └── two.module.js
├── deploy.sh
├── extras/
│ ├── js/
│ │ ├── arc.js
│ │ └── zui.js
│ └── jsm/
│ ├── arc.js
│ ├── zui.d.ts
│ └── zui.js
├── package.json
├── src/
│ ├── anchor.d.ts
│ ├── anchor.js
│ ├── children.d.ts
│ ├── children.js
│ ├── collection.d.ts
│ ├── collection.js
│ ├── constants.d.ts
│ ├── constants.js
│ ├── effects/
│ │ ├── gradient.d.ts
│ │ ├── gradient.js
│ │ ├── image-sequence.d.ts
│ │ ├── image-sequence.js
│ │ ├── image.d.ts
│ │ ├── image.js
│ │ ├── linear-gradient.d.ts
│ │ ├── linear-gradient.js
│ │ ├── radial-gradient.d.ts
│ │ ├── radial-gradient.js
│ │ ├── sprite.d.ts
│ │ ├── sprite.js
│ │ ├── stop.d.ts
│ │ ├── stop.js
│ │ ├── texture.d.ts
│ │ └── texture.js
│ ├── element.d.ts
│ ├── element.js
│ ├── events.d.ts
│ ├── events.js
│ ├── group.d.ts
│ ├── group.js
│ ├── matrix.d.ts
│ ├── matrix.js
│ ├── path.d.ts
│ ├── path.js
│ ├── registry.d.ts
│ ├── registry.js
│ ├── renderers/
│ │ ├── canvas.d.ts
│ │ ├── canvas.js
│ │ ├── svg.d.ts
│ │ ├── svg.js
│ │ ├── webgl.d.ts
│ │ └── webgl.js
│ ├── shape.d.ts
│ ├── shape.js
│ ├── shapes/
│ │ ├── arc-segment.d.ts
│ │ ├── arc-segment.js
│ │ ├── circle.d.ts
│ │ ├── circle.js
│ │ ├── ellipse.d.ts
│ │ ├── ellipse.js
│ │ ├── line.d.ts
│ │ ├── line.js
│ │ ├── points.d.ts
│ │ ├── points.js
│ │ ├── polygon.d.ts
│ │ ├── polygon.js
│ │ ├── rectangle.d.ts
│ │ ├── rectangle.js
│ │ ├── rounded-rectangle.d.ts
│ │ ├── rounded-rectangle.js
│ │ ├── star.d.ts
│ │ └── star.js
│ ├── text.d.ts
│ ├── text.js
│ ├── two.d.ts
│ ├── two.js
│ ├── utils/
│ │ ├── canvas-polyfill.d.ts
│ │ ├── canvas-polyfill.js
│ │ ├── curves.d.ts
│ │ ├── curves.js
│ │ ├── device-pixel-ratio.d.ts
│ │ ├── device-pixel-ratio.js
│ │ ├── dom.d.ts
│ │ ├── dom.js
│ │ ├── error.d.ts
│ │ ├── error.js
│ │ ├── hit-test.js
│ │ ├── interpret-svg.d.ts
│ │ ├── interpret-svg.js
│ │ ├── math.d.ts
│ │ ├── math.js
│ │ ├── path-commands.d.ts
│ │ ├── path-commands.js
│ │ ├── path.js
│ │ ├── root.d.ts
│ │ ├── root.js
│ │ ├── shaders.d.ts
│ │ ├── shaders.js
│ │ ├── shape.d.ts
│ │ ├── shape.js
│ │ ├── underscore.d.ts
│ │ ├── underscore.js
│ │ ├── xhr.d.ts
│ │ └── xhr.js
│ ├── vector.d.ts
│ └── vector.js
├── tests/
│ ├── index.html
│ ├── noWebGL.html
│ ├── src/
│ │ └── utils.js
│ ├── suite/
│ │ ├── bounding-box.js
│ │ ├── canvas.js
│ │ ├── core.js
│ │ ├── dispose.js
│ │ ├── hit-test.js
│ │ ├── release.js
│ │ ├── shapes.js
│ │ ├── svg-interpreter.js
│ │ ├── svg.js
│ │ └── webgl.js
│ └── typescript/
│ ├── index.js
│ ├── index.ts
│ └── package.json
├── utils/
│ ├── INSTRUCTIONS.md
│ ├── build.js
│ ├── docs.template
│ ├── document.js
│ ├── file-sizes.json
│ └── source-files.js
└── wiki/
├── .vuepress/
│ ├── components/
│ │ ├── carbon-ads.vue
│ │ ├── custom-button.vue
│ │ ├── example-card.vue
│ │ ├── inline-editor.vue
│ │ ├── redirect-page.vue
│ │ └── version-link.vue
│ ├── config.js
│ ├── enhanceApp.js
│ ├── plugins/
│ │ └── search/
│ │ ├── SearchBox.vue
│ │ └── match-query.js
│ ├── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ └── theme/
│ ├── components/
│ │ ├── Navbar.vue
│ │ └── Sidebar.vue
│ ├── index.js
│ └── layouts/
│ └── NotFound.vue
├── README.md
├── change-log/
│ └── README.md
├── changelog/
│ └── README.md
├── docs/
│ ├── README.md
│ ├── anchor/
│ │ └── README.md
│ ├── children/
│ │ └── README.md
│ ├── collection/
│ │ └── README.md
│ ├── effects/
│ │ ├── gradient/
│ │ │ └── README.md
│ │ ├── image/
│ │ │ └── README.md
│ │ ├── image-sequence/
│ │ │ └── README.md
│ │ ├── linear-gradient/
│ │ │ └── README.md
│ │ ├── radial-gradient/
│ │ │ └── README.md
│ │ ├── sprite/
│ │ │ └── README.md
│ │ ├── stop/
│ │ │ └── README.md
│ │ └── texture/
│ │ └── README.md
│ ├── element/
│ │ └── README.md
│ ├── events/
│ │ └── README.md
│ ├── extras/
│ │ ├── arc/
│ │ │ └── README.md
│ │ └── zui/
│ │ └── README.md
│ ├── group/
│ │ └── README.md
│ ├── matrix/
│ │ └── README.md
│ ├── path/
│ │ └── README.md
│ ├── registry/
│ │ └── README.md
│ ├── renderers/
│ │ ├── canvas/
│ │ │ └── README.md
│ │ ├── svg/
│ │ │ └── README.md
│ │ └── webgl/
│ │ └── README.md
│ ├── shape/
│ │ └── README.md
│ ├── shapes/
│ │ ├── arc-segment/
│ │ │ └── README.md
│ │ ├── circle/
│ │ │ └── README.md
│ │ ├── ellipse/
│ │ │ └── README.md
│ │ ├── line/
│ │ │ └── README.md
│ │ ├── points/
│ │ │ └── README.md
│ │ ├── polygon/
│ │ │ └── README.md
│ │ ├── rectangle/
│ │ │ └── README.md
│ │ ├── rounded-rectangle/
│ │ │ └── README.md
│ │ └── star/
│ │ └── README.md
│ ├── text/
│ │ └── README.md
│ ├── two/
│ │ └── README.md
│ └── vector/
│ └── README.md
├── donate/
│ └── README.md
├── examples/
│ └── README.md
├── incident-response-plan/
│ └── README.md
├── privacy/
│ └── README.md
└── security/
└── README.md
SYMBOL INDEX (1558 symbols across 96 files)
FILE: build/two.js
function decomposeMatrix (line 141) | function decomposeMatrix(matrix, b, c, d, e, f) {
function setMatrix (line 161) | function setMatrix(matrix) {
function getComputedMatrix (line 164) | function getComputedMatrix(object, matrix) {
function lerp (line 190) | function lerp(a, b, t) {
function getPoT (line 194) | function getPoT(value) {
function mod (line 201) | function mod(v, l) {
function toFixed (line 209) | function toFixed(v) {
function getEffectiveStrokeWidth (line 212) | function getEffectiveStrokeWidth(object, worldMatrix) {
method constructor (line 245) | constructor() {
method addEventListener (line 254) | addEventListener(name, handler) {
method on (line 265) | on() {
method bind (line 273) | bind() {
method removeEventListener (line 283) | removeEventListener(name, handler) {
method off (line 317) | off() {
method unbind (line 325) | unbind() {
method dispatchEvent (line 335) | dispatchEvent(name) {
method trigger (line 348) | trigger() {
method listen (line 351) | listen(obj, name, handler) {
method ignore (line 364) | ignore(obj, name, handler) {
method constructor (line 439) | constructor(x = 0, y = 0) {
method add (line 485) | static add(v1, v2) {
method sub (line 496) | static sub(v1, v2) {
method subtract (line 504) | static subtract(v1, v2) {
method ratioBetween (line 514) | static ratioBetween(v1, v2) {
method angleBetween (line 524) | static angleBetween(v1, v2) {
method distanceBetween (line 541) | static distanceBetween(v1, v2) {
method distanceBetweenSquared (line 551) | static distanceBetweenSquared(v1, v2) {
method set (line 563) | set(x, y) {
method copy (line 574) | copy(v) {
method clear (line 584) | clear() {
method clone (line 595) | clone() {
method add (line 620) | add(x, y) {
method addSelf (line 642) | addSelf(v) {
method sub (line 667) | sub(x, y) {
method subtract (line 689) | subtract() {
method subSelf (line 697) | subSelf(v) {
method subtractSelf (line 705) | subtractSelf(v) {
method multiply (line 730) | multiply(x, y) {
method multiplySelf (line 752) | multiplySelf(v) {
method multiplyScalar (line 761) | multiplyScalar(s) {
method divide (line 786) | divide(x, y) {
method divideSelf (line 814) | divideSelf(v) {
method divideScalar (line 823) | divideScalar(s) {
method negate (line 831) | negate() {
method dot (line 840) | dot(v) {
method length (line 849) | length() {
method lengthSquared (line 858) | lengthSquared() {
method normalize (line 866) | normalize() {
method distanceTo (line 875) | distanceTo(v) {
method distanceToSquared (line 884) | distanceToSquared(v) {
method setLength (line 895) | setLength(l) {
method equals (line 906) | equals(v, eps) {
method lerp (line 918) | lerp(v, t) {
method isZero (line 930) | isZero(eps) {
method toString (line 940) | toString() {
method toObject (line 949) | toObject() {
method rotate (line 958) | rotate(radians) {
method constructor (line 982) | constructor(x = 0, y = 0, ax = 0, ay = 0, bx = 0, by = 0, command = Comm...
method makeBroadcast (line 993) | static makeBroadcast(scope) {
method fromObject (line 1009) | static fromObject(obj) {
method copy (line 1018) | copy(v) {
method clone (line 1058) | clone() {
method toObject (line 1068) | toObject() {
method toString (line 1091) | toString() {
function getComponentOnCubicBezier (line 1417) | function getComponentOnCubicBezier(t, a, b, c, d) {
function subdivide (line 1421) | function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveLength (line 1436) | function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveBoundingBox (line 1449) | function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) {
function integrate (line 1506) | function integrate(f, a, b, n) {
function getCurveFromPoints (line 1514) | function getCurveFromPoints(points, closed2) {
function getControlPoints (line 1527) | function getControlPoints(a, b, c) {
function getReflection (line 1560) | function getReflection(a, b, relative) {
function getAnchorsFromArcData (line 1566) | function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, cc...
function isArrayLike (line 1585) | function isArrayLike(collection) {
function fallbackRequest (line 1673) | function fallbackRequest(callback, element) {
method constructor (line 1703) | constructor(message) {
function getBackingStoreRatio (line 1711) | function getBackingStoreRatio(ctx) {
function getRatio (line 1714) | function getRatio(ctx) {
method constructor (line 1721) | constructor() {
method add (line 1730) | add(id, obj) {
method remove (line 1740) | remove(id) {
method get (line 1751) | get(id) {
method contains (line 1761) | contains(id) {
method _events (line 1774) | get _events() {
method _events (line 1777) | set _events(e) {
method _bound (line 1781) | get _bound() {
method _bound (line 1784) | set _bound(v) {
method addEventListener (line 1787) | addEventListener() {
method on (line 1790) | on() {
method bind (line 1793) | bind() {
method removeEventListener (line 1796) | removeEventListener() {
method off (line 1799) | off() {
method unbind (line 1802) | unbind() {
method dispatchEvent (line 1805) | dispatchEvent() {
method trigger (line 1808) | trigger() {
method listen (line 1811) | listen() {
method ignore (line 1814) | ignore() {
method constructor (line 1817) | constructor() {
method pop (line 1827) | pop() {
method shift (line 1832) | shift() {
method push (line 1837) | push() {
method unshift (line 1842) | unshift() {
method splice (line 1847) | splice() {
method sort (line 1860) | sort() {
method reverse (line 1865) | reverse() {
method indexOf (line 1870) | indexOf() {
method map (line 1873) | map(func, scope) {
method constructor (line 1927) | constructor() {
method fromObject (line 1942) | static fromObject(obj) {
method flagReset (line 1954) | flagReset() {
method copy (line 1958) | copy(element) {
method toObject (line 1967) | toObject() {
method dispose (line 1980) | dispose() {
method constructor (line 2141) | constructor(src, callback) {
method fromObject (line 2184) | fromObject(obj) {
method getAbsoluteURL (line 2208) | static getAbsoluteURL(path) {
method loadHeadlessBuffer (line 2222) | static loadHeadlessBuffer(texture, onLoad) {
method getTag (line 2232) | static getTag(image) {
method getImage (line 2242) | static getImage(src) {
method load (line 2356) | static load(texture, callback) {
method clone (line 2382) | clone() {
method copy (line 2395) | copy(texture) {
method toObject (line 2408) | toObject() {
method _update (line 2425) | _update() {
method flagReset (line 2450) | flagReset() {
method dispose (line 2460) | dispose() {
function FlagOffset (line 2557) | function FlagOffset() {
function FlagScale (line 2560) | function FlagScale() {
method constructor (line 2602) | constructor(offset, color, opacity) {
method fromObject (line 2631) | static fromObject(obj) {
method copy (line 2644) | copy(stop) {
method clone (line 2661) | clone(parent) {
method toObject (line 2681) | toObject() {
method flagReset (line 2699) | flagReset() {
method constructor (line 2754) | constructor(stops) {
method fromObject (line 2787) | static fromObject(obj) {
method clone (line 2805) | clone(parent) {
method copy (line 2828) | copy(gradient) {
method toObject (line 2844) | toObject() {
method _update (line 2867) | _update() {
method flagReset (line 2879) | flagReset() {
method dispose (line 2889) | dispose() {
function FlagStops (line 2938) | function FlagStops() {
function BindStops (line 2941) | function BindStops(items) {
function UnbindStops (line 2949) | function UnbindStops(items) {
method constructor (line 2968) | constructor(x1, y1, x2, y2, stops) {
method fromObject (line 3004) | static fromObject(obj) {
method copy (line 3017) | copy(gradient) {
method clone (line 3034) | clone(parent) {
method toObject (line 3063) | toObject() {
method _update (line 3077) | _update() {
method flagReset (line 3089) | flagReset() {
function FlagEndPoints (line 3125) | function FlagEndPoints() {
method constructor (line 3152) | constructor(cx, cy, r, stops, fx, fy) {
method fromObject (line 3195) | static fromObject(obj) {
method copy (line 3208) | copy(gradient) {
method clone (line 3229) | clone(parent) {
method toObject (line 3259) | toObject() {
method _update (line 3280) | _update() {
method flagReset (line 3292) | flagReset() {
function FlagCenter (line 3338) | function FlagCenter() {
function FlagFocal (line 3341) | function FlagFocal() {
function contains (line 3346) | function contains(path, t) {
function getIdByLength (line 3362) | function getIdByLength(path, target) {
function getCurveLength2 (line 3378) | function getCurveLength2(a, b, limit) {
function getSubdivisions (line 3400) | function getSubdivisions(a, b, limit) {
function getEffectFromObject (line 3422) | function getEffectFromObject(obj) {
method constructor (line 3453) | constructor(a, b, c, d, e, f) {
method Multiply (line 3479) | static Multiply(A, B, C) {
method fromObject (line 3515) | static fromObject(obj) {
method set (line 3538) | set(a, b, c, d, e, f, g, h, i) {
method copy (line 3568) | copy(m) {
method identity (line 3586) | identity() {
method multiply (line 3629) | multiply(a, b, c, d, e, f, g, h, i) {
method inverse (line 3680) | inverse(output) {
method scale (line 3718) | scale(sx, sy) {
method rotate (line 3731) | rotate(n) {
method translate (line 3743) | translate(x, y) {
method skewX (line 3752) | skewX(n) {
method skewY (line 3762) | skewY(n) {
method toString (line 3773) | toString(fullMatrix) {
method toTransformArray (line 3785) | toTransformArray(fullMatrix, output) {
method toArray (line 3838) | toArray(fullMatrix, output) {
method toObject (line 3882) | toObject() {
method clone (line 3894) | clone() {
method constructor (line 3957) | constructor() {
method fromObject (line 3989) | static fromObject(obj) {
method renderer (line 3996) | get renderer() {
method renderer (line 3999) | set renderer(v) {
method translation (line 4006) | get translation() {
method translation (line 4009) | set translation(v) {
method addTo (line 4018) | addTo(group) {
method remove (line 4027) | remove() {
method contains (line 4046) | contains(x, y, options) {
method copy (line 4072) | copy(shape) {
method clone (line 4106) | clone(parent) {
method toObject (line 4127) | toObject() {
method dispose (line 4144) | dispose() {
method _update (line 4161) | _update(bubbles) {
method flagReset (line 4186) | flagReset() {
function FlagMatrix (line 4275) | function FlagMatrix() {
function createPoint (line 4283) | function createPoint(x, y) {
function pointsEqual (line 4286) | function pointsEqual(a, b, epsilon = EPSILON) {
function svgAngle (line 4289) | function svgAngle(ux, uy, vx, vy) {
function sampleArcPoints (line 4298) | function sampleArcPoints(prev, anchor2, precision) {
function buildPathHitParts (line 4382) | function buildPathHitParts(path, precision = DEFAULT_PRECISION) {
function pointInPolygons (line 4472) | function pointInPolygons(polygons, x, y) {
function distanceToSegmentSquared (line 4492) | function distanceToSegmentSquared(x, y, a, b) {
function distanceToSegments (line 4508) | function distanceToSegments(segments, x, y) {
function hasVisibleFill (line 4522) | function hasVisibleFill(shape, override) {
function hasVisibleStroke (line 4535) | function hasVisibleStroke(shape, override) {
function boundsContains (line 4552) | function boundsContains(rect, x, y, tolerance = 0) {
function isRelativeAnchor (line 4565) | function isRelativeAnchor(anchor2) {
function setHandleComponent (line 4568) | function setHandleComponent(anchor2, side, dx, dy) {
function clearHandleComponent (line 4587) | function clearHandleComponent(anchor2, side) {
function getHandleOffset (line 4590) | function getHandleOffset(anchor2, side) {
function hasNonZeroHandle (line 4603) | function hasNonZeroHandle(anchor2, side) {
function updateAnchorCommand (line 4607) | function updateAnchorCommand(anchor2) {
function inheritRelative (line 4613) | function inheritRelative(anchor2, reference) {
function isSegmentCurved (line 4618) | function isSegmentCurved(a, b) {
function lerpPoint (line 4621) | function lerpPoint(a, b, t) {
function getAbsoluteHandle (line 4627) | function getAbsoluteHandle(anchor2, side) {
function splitSubdivisionSegment (line 4637) | function splitSubdivisionSegment(start, end, t) {
function applyGlobalSmooth (line 4661) | function applyGlobalSmooth(vertices, from, to, closed2, loop2, asymmetri...
function applyCatmullRom (line 4728) | function applyCatmullRom(anchor2, prev, next, factor, clampIn, clampOut) {
function applyGeometric (line 4767) | function applyGeometric(anchor2, prev, next, factor, clampIn, clampOut) {
function applyLocalSmooth (line 4800) | function applyLocalSmooth(vertices, from, to, closed2, loop2, options) {
method constructor (line 5021) | constructor(vertices, closed2, curved, manual) {
method fromObject (line 5084) | static fromObject(obj) {
method copy (line 5099) | copy(path) {
method clone (line 5127) | clone(parent) {
method toObject (line 5157) | toObject() {
method dispose (line 5186) | dispose() {
method noFill (line 5227) | noFill() {
method noStroke (line 5236) | noStroke() {
method corner (line 5246) | corner() {
method center (line 5272) | center() {
method getBoundingClientRect (line 5294) | getBoundingClientRect(shallow) {
method contains (line 5383) | contains(x, y, options) {
method getPointAt (line 5438) | getPointAt(t, obj) {
method plot (line 5545) | plot() {
method smooth (line 5564) | smooth(options) {
method subdivide (line 5642) | subdivide(limit) {
method _updateLength (line 5744) | _updateLength(limit, silent) {
method _update (line 5782) | _update() {
method flagReset (line 5875) | flagReset() {
function FlagVertices (line 6123) | function FlagVertices() {
function BindVertices (line 6130) | function BindVertices(items) {
function UnbindVertices (line 6137) | function UnbindVertices(items) {
function FlagFill (line 6144) | function FlagFill() {
function FlagStroke (line 6147) | function FlagStroke() {
method constructor (line 6153) | constructor(x, y, width, height) {
method fromObject (line 6190) | static fromObject(obj) {
method copy (line 6203) | copy(rectangle) {
method _update (line 6250) | _update() {
method flagReset (line 6274) | flagReset() {
method clone (line 6286) | clone(parent) {
method toObject (line 6315) | toObject() {
method constructor (line 6473) | constructor(src, ox, oy, cols, rows, frameRate) {
method fromObject (line 6521) | static fromObject(obj) {
method copy (line 6534) | copy(sprite) {
method play (line 6552) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 6578) | pause() {
method stop (line 6587) | stop() {
method clone (line 6599) | clone(parent) {
method toObject (line 6625) | toObject() {
method dispose (line 6648) | dispose() {
method _update (line 6670) | _update() {
method flagReset (line 6740) | flagReset() {
method ids (line 6834) | get ids() {
method constructor (line 6837) | constructor(children) {
method attach (line 6850) | attach(children) {
method detach (line 6865) | detach(children) {
method constructor (line 6923) | constructor(x, y, ir, or, sa, ea, res) {
method fromObject (line 6967) | static fromObject(obj) {
method copy (line 6980) | copy(arcSegment) {
method _update (line 6998) | _update() {
method flagReset (line 7108) | flagReset() {
method clone (line 7120) | clone(parent) {
method toObject (line 7150) | toObject() {
method constructor (line 7219) | constructor(ox, oy, r, resolution) {
method fromObject (line 7254) | static fromObject(obj) {
method copy (line 7267) | copy(circle) {
method _update (line 7285) | _update() {
method flagReset (line 7319) | flagReset() {
method clone (line 7331) | clone(parent) {
method toObject (line 7356) | toObject() {
method constructor (line 7407) | constructor(x, y, rx, ry, resolution) {
method fromObject (line 7448) | static fromObject(obj) {
method copy (line 7461) | copy(ellipse) {
method _update (line 7479) | _update() {
method flagReset (line 7513) | flagReset() {
method clone (line 7525) | clone(parent) {
method toObject (line 7553) | toObject() {
method constructor (line 7612) | constructor(vertices) {
method fromObject (line 7664) | static fromObject(obj) {
method copy (line 7679) | copy(points) {
method clone (line 7704) | clone(parent) {
method toObject (line 7733) | toObject() {
method dispose (line 7762) | dispose() {
method subdivide (line 7828) | subdivide(limit) {
method _update (line 7864) | _update() {
method flagReset (line 7897) | flagReset() {
method constructor (line 8114) | constructor(x, y, radius, sides) {
method fromObject (line 8150) | static fromObject(obj) {
method copy (line 8163) | copy(polygon) {
method _update (line 8181) | _update() {
method flagReset (line 8212) | flagReset() {
method clone (line 8224) | clone(parent) {
method toObject (line 8251) | toObject() {
method constructor (line 8345) | constructor(x, y, width, height, radius) {
method fromObject (line 8393) | static fromObject(obj) {
method copy (line 8406) | copy(roundedRectangle) {
method _update (line 8429) | _update() {
method flagReset (line 8503) | flagReset() {
method clone (line 8515) | clone(parent) {
method toObject (line 8543) | toObject() {
function FlagRadius (line 8592) | function FlagRadius() {
method constructor (line 8636) | constructor(x, y, innerRadius, outerRadius, sides) {
method fromObject (line 8681) | static fromObject(obj) {
method copy (line 8694) | copy(star) {
method _update (line 8712) | _update() {
method flagReset (line 8744) | flagReset() {
method clone (line 8756) | clone(parent) {
method toObject (line 8784) | toObject() {
method constructor (line 9048) | constructor(message, x, y, styles) {
method Measure (line 9110) | static Measure(text) {
method fromObject (line 9145) | static fromObject(obj) {
method copy (line 9160) | copy(text) {
method clone (line 9177) | clone(parent) {
method toObject (line 9201) | toObject() {
method dispose (line 9219) | dispose() {
method noFill (line 9238) | noFill() {
method noStroke (line 9247) | noStroke() {
method getBoundingClientRect (line 9262) | getBoundingClientRect(shallow) {
method flagReset (line 9314) | flagReset() {
function FlagFill2 (line 9535) | function FlagFill2() {
function FlagStroke2 (line 9538) | function FlagStroke2() {
method constructor (line 9630) | constructor(src, ox, oy, frameRate) {
method fromObject (line 9680) | static fromObject(obj) {
method copy (line 9693) | copy(imageSequence) {
method play (line 9711) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 9737) | pause() {
method stop (line 9746) | stop() {
method clone (line 9758) | clone(parent) {
method toObject (line 9780) | toObject() {
method dispose (line 9803) | dispose() {
method _update (line 9835) | _update() {
method flagReset (line 9903) | flagReset() {
function FlagTextures (line 9974) | function FlagTextures() {
function BindTextures (line 9977) | function BindTextures(items) {
function UnbindTextures (line 9984) | function UnbindTextures(items) {
function GenerateTexture (line 9991) | function GenerateTexture(obj) {
method constructor (line 10164) | constructor(children) {
method InsertChildren (line 10181) | static InsertChildren(children) {
method RemoveChildren (line 10192) | static RemoveChildren(children) {
method OrderChildren (line 10202) | static OrderChildren(children) {
method fromObject (line 10220) | static fromObject(obj) {
method IsVisible (line 10280) | static IsVisible(element, visibleOnly) {
method VisitForHitTest (line 10296) | static VisitForHitTest(group, context, includeGroups, filter, hitOptions...
method copy (line 10359) | copy(group) {
method clone (line 10379) | clone(parent) {
method toObject (line 10407) | toObject() {
method dispose (line 10432) | dispose() {
method getShapesAtPoint (line 10469) | getShapesAtPoint(x, y, options) {
method corner (line 10529) | corner() {
method center (line 10547) | center() {
method getById (line 10570) | getById(id) {
method getByClassName (line 10596) | getByClassName(className) {
method getByType (line 10618) | getByType(type) {
method add (line 10640) | add(objects) {
method remove (line 10665) | remove(objects) {
method getBoundingClientRect (line 10695) | getBoundingClientRect(shallow) {
method noFill (line 10744) | noFill() {
method noStroke (line 10755) | noStroke() {
method subdivide (line 10766) | subdivide() {
method _update (line 10781) | _update() {
method flagReset (line 10820) | flagReset() {
function replaceParent (line 11066) | function replaceParent(child, newParent) {
method constructor (line 11122) | constructor(x1, y1, x2, y2) {
function getAlignment (line 11186) | function getAlignment(anchor2) {
function getBaseline (line 11189) | function getBaseline(node) {
function getTagName (line 11194) | function getTagName(tag) {
function applyTransformsToVector (line 11197) | function applyTransformsToVector(transforms, vector3) {
function extractCSSText (line 11208) | function extractCSSText(text, styles) {
function getSvgStyles (line 11226) | function getSvgStyles(node) {
function getSvgAttributes (line 11242) | function getSvgAttributes(node) {
function applySvgViewBox (line 11253) | function applySvgViewBox(node, value) {
function applySvgAttributes (line 11294) | function applySvgAttributes(node, elem, parentStyles) {
function updateDefsCache (line 11527) | function updateDefsCache(node, defsCache) {
function getScene (line 11536) | function getScene(node) {
function xhr (line 12168) | function xhr(path, callback) {
method constructor (line 12206) | constructor(src, ox, oy, width, height, mode) {
method fromObject (line 12253) | static fromObject(obj) {
method copy (line 12266) | copy(image) {
method clone (line 12283) | clone(parent) {
method toObject (line 12302) | toObject() {
method dispose (line 12318) | dispose() {
method _update (line 12335) | _update() {
method flagReset (line 12393) | flagReset() {
method constructor (line 13195) | constructor(params) {
method setSize (line 13221) | setSize(width, height, ratio) {
method render (line 13240) | render() {
function renderArcEstimate (line 13256) | function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, cl...
function svgAngle2 (line 13291) | function svgAngle2(ux, uy, vx, vy) {
function isDefaultMatrix (line 13300) | function isDefaultMatrix(m) {
method constructor (line 14149) | constructor(params) {
method setSize (line 14173) | setSize(width, height) {
method render (line 14187) | render() {
method constructor (line 15474) | constructor(params) {
method setSize (line 15557) | setSize(width, height, ratio) {
method render (line 15587) | render() {
method _bound (line 15619) | get _bound() {
method _bound (line 15622) | set _bound(v) {
method addEventListener (line 15625) | addEventListener() {
method on (line 15628) | on() {
method bind (line 15631) | bind() {
method removeEventListener (line 15634) | removeEventListener() {
method off (line 15637) | off() {
method unbind (line 15640) | unbind() {
method dispatchEvent (line 15643) | dispatchEvent() {
method trigger (line 15646) | trigger() {
method listen (line 15649) | listen() {
method ignore (line 15652) | ignore() {
method constructor (line 15695) | constructor(options) {
method appendTo (line 15859) | appendTo(elem) {
method play (line 15877) | play() {
method pause (line 15888) | pause() {
method setPlaying (line 15892) | setPlaying(p) {
method release (line 15902) | release(obj) {
method getShapesAtPoint (line 15994) | getShapesAtPoint(x, y, options) {
method update (line 16007) | update() {
method render (line 16034) | render() {
method add (line 16045) | add(objects) {
method remove (line 16058) | remove(objects) {
method clear (line 16070) | clear() {
method makeLine (line 16084) | makeLine(x1, y1, x2, y2) {
method makeArrow (line 16099) | makeArrow(x1, y1, x2, y2, size) {
method makeRectangle (line 16166) | makeRectangle(x, y, width, height) {
method makeRoundedRectangle (line 16182) | makeRoundedRectangle(x, y, width, height, sides) {
method makeCircle (line 16197) | makeCircle(x, y, radius, resolution) {
method makeEllipse (line 16213) | makeEllipse(x, y, rx, ry, resolution) {
method makeStar (line 16229) | makeStar(x, y, outerRadius, innerRadius, sides) {
method makeCurve (line 16243) | makeCurve(points) {
method makePolygon (line 16277) | makePolygon(x, y, radius, sides) {
method makeArcSegment (line 16294) | makeArcSegment(x, y, innerRadius, outerRadius, startAngle, endAngle, res...
method makePoints (line 16315) | makePoints(p) {
method makePath (line 16342) | makePath(p) {
method makeText (line 16381) | makeText(message, x, y, styles) {
method makeLinearGradient (line 16397) | makeLinearGradient(x1, y1, x2, y2) {
method makeRadialGradient (line 16413) | makeRadialGradient(x1, y1, radius) {
method makeSprite (line 16432) | makeSprite(src, x, y, columns, rows, frameRate, autostart) {
method makeImage (line 16452) | makeImage(src, x, y, width, height, mode) {
method makeImageSequence (line 16468) | makeImageSequence(src, x, y, frameRate, autostart) {
method makeTexture (line 16484) | makeTexture(src, callback) {
method makeGroup (line 16495) | makeGroup(objects) {
method interpret (line 16513) | interpret(svg2, shallow, add) {
method load (line 16535) | load(pathOrSVGContent, callback) {
function fitToWindow (line 16560) | function fitToWindow() {
function fitToParent (line 16566) | function fitToParent() {
function updateDimensions (line 16577) | function updateDimensions(width, height) {
function loop (line 16583) | function loop() {
FILE: build/two.module.js
function decomposeMatrix (line 148) | function decomposeMatrix(matrix, b, c, d, e, f) {
function setMatrix (line 168) | function setMatrix(matrix) {
function getComputedMatrix (line 171) | function getComputedMatrix(object, matrix) {
function lerp (line 197) | function lerp(a, b, t) {
function getPoT (line 201) | function getPoT(value) {
function mod (line 208) | function mod(v, l) {
function toFixed (line 216) | function toFixed(v) {
function getEffectiveStrokeWidth (line 219) | function getEffectiveStrokeWidth(object, worldMatrix) {
method constructor (line 250) | constructor() {
method addEventListener (line 261) | addEventListener(name, handler) {
method on (line 272) | on() {
method bind (line 280) | bind() {
method removeEventListener (line 290) | removeEventListener(name, handler) {
method off (line 324) | off() {
method unbind (line 332) | unbind() {
method dispatchEvent (line 342) | dispatchEvent(name) {
method trigger (line 355) | trigger() {
method listen (line 358) | listen(obj, name, handler) {
method ignore (line 371) | ignore(obj, name, handler) {
method constructor (line 436) | constructor(x = 0, y = 0) {
method add (line 462) | static add(v1, v2) {
method sub (line 473) | static sub(v1, v2) {
method subtract (line 481) | static subtract(v1, v2) {
method ratioBetween (line 491) | static ratioBetween(v1, v2) {
method angleBetween (line 501) | static angleBetween(v1, v2) {
method distanceBetween (line 518) | static distanceBetween(v1, v2) {
method distanceBetweenSquared (line 528) | static distanceBetweenSquared(v1, v2) {
method set (line 540) | set(x, y) {
method copy (line 551) | copy(v) {
method clear (line 561) | clear() {
method clone (line 572) | clone() {
method add (line 597) | add(x, y) {
method addSelf (line 619) | addSelf(v) {
method sub (line 644) | sub(x, y) {
method subtract (line 666) | subtract() {
method subSelf (line 674) | subSelf(v) {
method subtractSelf (line 682) | subtractSelf(v) {
method multiply (line 707) | multiply(x, y) {
method multiplySelf (line 729) | multiplySelf(v) {
method multiplyScalar (line 738) | multiplyScalar(s) {
method divide (line 763) | divide(x, y) {
method divideSelf (line 791) | divideSelf(v) {
method divideScalar (line 800) | divideScalar(s) {
method negate (line 808) | negate() {
method dot (line 817) | dot(v) {
method length (line 826) | length() {
method lengthSquared (line 835) | lengthSquared() {
method normalize (line 843) | normalize() {
method distanceTo (line 852) | distanceTo(v) {
method distanceToSquared (line 861) | distanceToSquared(v) {
method setLength (line 872) | setLength(l) {
method equals (line 883) | equals(v, eps) {
method lerp (line 895) | lerp(v, t) {
method isZero (line 907) | isZero(eps) {
method toString (line 917) | toString() {
method toObject (line 926) | toObject() {
method rotate (line 935) | rotate(radians) {
method constructor (line 979) | constructor(x = 0, y = 0, ax = 0, ay = 0, bx = 0, by = 0, command = Comm...
method makeBroadcast (line 1001) | static makeBroadcast(scope) {
method fromObject (line 1017) | static fromObject(obj) {
method copy (line 1026) | copy(v) {
method clone (line 1066) | clone() {
method toObject (line 1076) | toObject() {
method toString (line 1099) | toString() {
function getComponentOnCubicBezier (line 1425) | function getComponentOnCubicBezier(t, a, b, c, d) {
function subdivide (line 1429) | function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveLength (line 1444) | function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveBoundingBox (line 1457) | function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) {
function integrate (line 1514) | function integrate(f, a, b, n) {
function getCurveFromPoints (line 1522) | function getCurveFromPoints(points, closed2) {
function getControlPoints (line 1535) | function getControlPoints(a, b, c) {
function getReflection (line 1568) | function getReflection(a, b, relative) {
function getAnchorsFromArcData (line 1574) | function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, cc...
function isArrayLike (line 1593) | function isArrayLike(collection) {
function fallbackRequest (line 1681) | function fallbackRequest(callback, element) {
method constructor (line 1709) | constructor(message) {
function getBackingStoreRatio (line 1719) | function getBackingStoreRatio(ctx) {
function getRatio (line 1722) | function getRatio(ctx) {
method constructor (line 1728) | constructor() {
method add (line 1738) | add(id, obj) {
method remove (line 1748) | remove(id) {
method get (line 1759) | get(id) {
method contains (line 1769) | contains(id) {
method constructor (line 1777) | constructor() {
method _events (line 1793) | get _events() {
method _events (line 1796) | set _events(e) {
method _bound (line 1800) | get _bound() {
method _bound (line 1803) | set _bound(v) {
method addEventListener (line 1806) | addEventListener() {
method on (line 1810) | on() {
method bind (line 1814) | bind() {
method removeEventListener (line 1818) | removeEventListener() {
method off (line 1822) | off() {
method unbind (line 1826) | unbind() {
method dispatchEvent (line 1830) | dispatchEvent() {
method trigger (line 1834) | trigger() {
method listen (line 1838) | listen() {
method ignore (line 1842) | ignore() {
method pop (line 1846) | pop() {
method shift (line 1851) | shift() {
method push (line 1856) | push() {
method unshift (line 1861) | unshift() {
method splice (line 1866) | splice() {
method sort (line 1879) | sort() {
method reverse (line 1884) | reverse() {
method indexOf (line 1889) | indexOf() {
method map (line 1892) | map(func, scope) {
method constructor (line 1911) | constructor() {
method fromObject (line 1961) | static fromObject(obj) {
method flagReset (line 1973) | flagReset() {
method copy (line 1977) | copy(element) {
method toObject (line 1986) | toObject() {
method dispose (line 1999) | dispose() {
method constructor (line 2084) | constructor(src, callback) {
method fromObject (line 2200) | fromObject(obj) {
method getAbsoluteURL (line 2213) | static getAbsoluteURL(path) {
method loadHeadlessBuffer (line 2227) | static loadHeadlessBuffer(texture, onLoad) {
method getTag (line 2237) | static getTag(image) {
method getImage (line 2247) | static getImage(src) {
method load (line 2275) | static load(texture, callback) {
method clone (line 2301) | clone() {
method copy (line 2314) | copy(texture) {
method toObject (line 2327) | toObject() {
method _update (line 2344) | _update() {
method flagReset (line 2369) | flagReset() {
method dispose (line 2379) | dispose() {
function FlagOffset (line 2579) | function FlagOffset() {
function FlagScale (line 2582) | function FlagScale() {
method constructor (line 2588) | constructor(offset, color, opacity) {
method fromObject (line 2643) | static fromObject(obj) {
method copy (line 2656) | copy(stop) {
method clone (line 2673) | clone(parent) {
method toObject (line 2693) | toObject() {
method flagReset (line 2711) | flagReset() {
method constructor (line 2772) | constructor(stops) {
method fromObject (line 2800) | static fromObject(obj) {
method clone (line 2818) | clone(parent) {
method copy (line 2841) | copy(gradient) {
method toObject (line 2857) | toObject() {
method _update (line 2880) | _update() {
method flagReset (line 2892) | flagReset() {
method dispose (line 2902) | dispose() {
function FlagStops (line 2962) | function FlagStops() {
function BindStops (line 2965) | function BindStops(items) {
function UnbindStops (line 2973) | function UnbindStops(items) {
method constructor (line 2984) | constructor(x1, y1, x2, y2, stops) {
method fromObject (line 3022) | static fromObject(obj) {
method copy (line 3035) | copy(gradient) {
method clone (line 3052) | clone(parent) {
method toObject (line 3081) | toObject() {
method _update (line 3095) | _update() {
method flagReset (line 3107) | flagReset() {
function FlagEndPoints (line 3150) | function FlagEndPoints() {
method constructor (line 3156) | constructor(cx, cy, r, stops, fx, fy) {
method fromObject (line 3210) | static fromObject(obj) {
method copy (line 3223) | copy(gradient) {
method clone (line 3244) | clone(parent) {
method toObject (line 3274) | toObject() {
method _update (line 3295) | _update() {
method flagReset (line 3307) | flagReset() {
function FlagCenter (line 3364) | function FlagCenter() {
function FlagFocal (line 3367) | function FlagFocal() {
function contains (line 3372) | function contains(path, t) {
function getIdByLength (line 3388) | function getIdByLength(path, target) {
function getCurveLength2 (line 3404) | function getCurveLength2(a, b, limit) {
function getSubdivisions (line 3426) | function getSubdivisions(a, b, limit) {
function getEffectFromObject (line 3448) | function getEffectFromObject(obj) {
method constructor (line 3468) | constructor(a, b, c, d, e, f) {
method Multiply (line 3499) | static Multiply(A, B, C) {
method fromObject (line 3535) | static fromObject(obj) {
method set (line 3558) | set(a, b, c, d, e, f, g, h, i) {
method copy (line 3588) | copy(m) {
method identity (line 3606) | identity() {
method multiply (line 3649) | multiply(a, b, c, d, e, f, g, h, i) {
method inverse (line 3700) | inverse(output) {
method scale (line 3738) | scale(sx, sy) {
method rotate (line 3751) | rotate(n) {
method translate (line 3763) | translate(x, y) {
method skewX (line 3772) | skewX(n) {
method skewY (line 3782) | skewY(n) {
method toString (line 3793) | toString(fullMatrix) {
method toTransformArray (line 3805) | toTransformArray(fullMatrix, output) {
method toArray (line 3858) | toArray(fullMatrix, output) {
method toObject (line 3902) | toObject() {
method clone (line 3914) | clone() {
method constructor (line 3929) | constructor() {
method fromObject (line 4007) | static fromObject(obj) {
method renderer (line 4014) | get renderer() {
method renderer (line 4017) | set renderer(v) {
method translation (line 4024) | get translation() {
method translation (line 4027) | set translation(v) {
method addTo (line 4036) | addTo(group) {
method remove (line 4045) | remove() {
method contains (line 4064) | contains(x, y, options) {
method copy (line 4090) | copy(shape) {
method clone (line 4124) | clone(parent) {
method toObject (line 4145) | toObject() {
method dispose (line 4162) | dispose() {
method _update (line 4179) | _update(bubbles) {
method flagReset (line 4204) | flagReset() {
function FlagMatrix (line 4303) | function FlagMatrix() {
function createPoint (line 4311) | function createPoint(x, y) {
function pointsEqual (line 4314) | function pointsEqual(a, b, epsilon = EPSILON) {
function svgAngle (line 4317) | function svgAngle(ux, uy, vx, vy) {
function sampleArcPoints (line 4326) | function sampleArcPoints(prev, anchor2, precision) {
function buildPathHitParts (line 4410) | function buildPathHitParts(path, precision = DEFAULT_PRECISION) {
function pointInPolygons (line 4500) | function pointInPolygons(polygons, x, y) {
function distanceToSegmentSquared (line 4520) | function distanceToSegmentSquared(x, y, a, b) {
function distanceToSegments (line 4536) | function distanceToSegments(segments, x, y) {
function hasVisibleFill (line 4550) | function hasVisibleFill(shape, override) {
function hasVisibleStroke (line 4563) | function hasVisibleStroke(shape, override) {
function boundsContains (line 4580) | function boundsContains(rect, x, y, tolerance = 0) {
function isRelativeAnchor (line 4593) | function isRelativeAnchor(anchor2) {
function setHandleComponent (line 4596) | function setHandleComponent(anchor2, side, dx, dy) {
function clearHandleComponent (line 4615) | function clearHandleComponent(anchor2, side) {
function getHandleOffset (line 4618) | function getHandleOffset(anchor2, side) {
function hasNonZeroHandle (line 4631) | function hasNonZeroHandle(anchor2, side) {
function updateAnchorCommand (line 4635) | function updateAnchorCommand(anchor2) {
function inheritRelative (line 4641) | function inheritRelative(anchor2, reference) {
function isSegmentCurved (line 4646) | function isSegmentCurved(a, b) {
function lerpPoint (line 4649) | function lerpPoint(a, b, t) {
function getAbsoluteHandle (line 4655) | function getAbsoluteHandle(anchor2, side) {
function splitSubdivisionSegment (line 4665) | function splitSubdivisionSegment(start, end, t) {
function applyGlobalSmooth (line 4689) | function applyGlobalSmooth(vertices, from, to, closed2, loop2, asymmetri...
function applyCatmullRom (line 4756) | function applyCatmullRom(anchor2, prev, next, factor, clampIn, clampOut) {
function applyGeometric (line 4795) | function applyGeometric(anchor2, prev, next, factor, clampIn, clampOut) {
function applyLocalSmooth (line 4828) | function applyLocalSmooth(vertices, from, to, closed2, loop2, options) {
method constructor (line 4862) | constructor(vertices, closed2, curved, manual) {
method fromObject (line 5088) | static fromObject(obj) {
method copy (line 5103) | copy(path) {
method clone (line 5131) | clone(parent) {
method toObject (line 5161) | toObject() {
method dispose (line 5190) | dispose() {
method noFill (line 5231) | noFill() {
method noStroke (line 5240) | noStroke() {
method corner (line 5250) | corner() {
method center (line 5276) | center() {
method getBoundingClientRect (line 5298) | getBoundingClientRect(shallow) {
method contains (line 5387) | contains(x, y, options) {
method getPointAt (line 5442) | getPointAt(t, obj) {
method plot (line 5549) | plot() {
method smooth (line 5568) | smooth(options) {
method subdivide (line 5646) | subdivide(limit) {
method _updateLength (line 5748) | _updateLength(limit, silent) {
method _update (line 5786) | _update() {
method flagReset (line 5879) | flagReset() {
function FlagVertices (line 6152) | function FlagVertices() {
function BindVertices (line 6159) | function BindVertices(items) {
function UnbindVertices (line 6166) | function UnbindVertices(items) {
function FlagFill (line 6173) | function FlagFill() {
function FlagStroke (line 6176) | function FlagStroke() {
method constructor (line 6182) | constructor(x, y, width, height) {
method fromObject (line 6239) | static fromObject(obj) {
method copy (line 6252) | copy(rectangle) {
method _update (line 6274) | _update() {
method flagReset (line 6298) | flagReset() {
method clone (line 6310) | clone(parent) {
method toObject (line 6339) | toObject() {
method constructor (line 6393) | constructor(src, ox, oy, cols, rows, frameRate) {
method fromObject (line 6537) | static fromObject(obj) {
method copy (line 6550) | copy(sprite) {
method play (line 6568) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 6594) | pause() {
method stop (line 6603) | stop() {
method clone (line 6615) | clone(parent) {
method toObject (line 6641) | toObject() {
method dispose (line 6664) | dispose() {
method _update (line 6686) | _update() {
method flagReset (line 6756) | flagReset() {
method constructor (line 6860) | constructor(children) {
method ids (line 6873) | get ids() {
method attach (line 6882) | attach(children) {
method detach (line 6897) | detach(children) {
method constructor (line 6908) | constructor(x, y, ir, or, sa, ea, res) {
method fromObject (line 6995) | static fromObject(obj) {
method copy (line 7008) | copy(arcSegment) {
method _update (line 7026) | _update() {
method flagReset (line 7136) | flagReset() {
method clone (line 7148) | clone(parent) {
method toObject (line 7178) | toObject() {
method constructor (line 7241) | constructor(ox, oy, r, resolution) {
method fromObject (line 7283) | static fromObject(obj) {
method copy (line 7296) | copy(circle) {
method _update (line 7314) | _update() {
method flagReset (line 7348) | flagReset() {
method clone (line 7360) | clone(parent) {
method toObject (line 7385) | toObject() {
method constructor (line 7418) | constructor(x, y, rx, ry, resolution) {
method fromObject (line 7478) | static fromObject(obj) {
method copy (line 7491) | copy(ellipse) {
method _update (line 7509) | _update() {
method flagReset (line 7543) | flagReset() {
method clone (line 7555) | clone(parent) {
method toObject (line 7583) | toObject() {
method constructor (line 7626) | constructor(vertices) {
method fromObject (line 7724) | static fromObject(obj) {
method copy (line 7739) | copy(points) {
method clone (line 7764) | clone(parent) {
method toObject (line 7793) | toObject() {
method dispose (line 7822) | dispose() {
method subdivide (line 7856) | subdivide(limit) {
method _update (line 7883) | _update() {
method flagReset (line 7916) | flagReset() {
method constructor (line 8109) | constructor(x, y, radius, sides) {
method fromObject (line 8182) | static fromObject(obj) {
method copy (line 8195) | copy(polygon) {
method _update (line 8213) | _update() {
method flagReset (line 8244) | flagReset() {
method clone (line 8256) | clone(parent) {
method toObject (line 8283) | toObject() {
method constructor (line 8347) | constructor(x, y, width, height, radius) {
method fromObject (line 8426) | static fromObject(obj) {
method copy (line 8439) | copy(roundedRectangle) {
method _update (line 8462) | _update() {
method flagReset (line 8536) | flagReset() {
method clone (line 8548) | clone(parent) {
method toObject (line 8576) | toObject() {
function FlagRadius (line 8631) | function FlagRadius() {
method constructor (line 8639) | constructor(x, y, innerRadius, outerRadius, sides) {
method fromObject (line 8715) | static fromObject(obj) {
method copy (line 8728) | copy(star) {
method _update (line 8746) | _update() {
method flagReset (line 8778) | flagReset() {
method clone (line 8790) | clone(parent) {
method toObject (line 8818) | toObject() {
method constructor (line 8875) | constructor(message, x, y, styles) {
method Measure (line 9122) | static Measure(text) {
method fromObject (line 9157) | static fromObject(obj) {
method copy (line 9172) | copy(text) {
method clone (line 9189) | clone(parent) {
method toObject (line 9213) | toObject() {
method dispose (line 9231) | dispose() {
method noFill (line 9250) | noFill() {
method noStroke (line 9259) | noStroke() {
method getBoundingClientRect (line 9274) | getBoundingClientRect(shallow) {
method flagReset (line 9326) | flagReset() {
function FlagFill2 (line 9576) | function FlagFill2() {
function FlagStroke2 (line 9579) | function FlagStroke2() {
method constructor (line 9585) | constructor(src, ox, oy, frameRate) {
method fromObject (line 9704) | static fromObject(obj) {
method copy (line 9717) | copy(imageSequence) {
method play (line 9735) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 9761) | pause() {
method stop (line 9770) | stop() {
method clone (line 9782) | clone(parent) {
method toObject (line 9804) | toObject() {
method dispose (line 9827) | dispose() {
method _update (line 9859) | _update() {
method flagReset (line 9927) | flagReset() {
function FlagTextures (line 10016) | function FlagTextures() {
function BindTextures (line 10019) | function BindTextures(items) {
function UnbindTextures (line 10026) | function UnbindTextures(items) {
function GenerateTexture (line 10033) | function GenerateTexture(obj) {
method constructor (line 10060) | constructor(children) {
method InsertChildren (line 10222) | static InsertChildren(children) {
method RemoveChildren (line 10233) | static RemoveChildren(children) {
method OrderChildren (line 10243) | static OrderChildren(children) {
method fromObject (line 10246) | static fromObject(obj) {
method IsVisible (line 10306) | static IsVisible(element, visibleOnly) {
method VisitForHitTest (line 10322) | static VisitForHitTest(group, context, includeGroups, filter, hitOptions...
method copy (line 10385) | copy(group) {
method clone (line 10405) | clone(parent) {
method toObject (line 10433) | toObject() {
method dispose (line 10458) | dispose() {
method getShapesAtPoint (line 10495) | getShapesAtPoint(x, y, options) {
method corner (line 10555) | corner() {
method center (line 10573) | center() {
method getById (line 10596) | getById(id) {
method getByClassName (line 10622) | getByClassName(className) {
method getByType (line 10644) | getByType(type) {
method add (line 10666) | add(objects) {
method remove (line 10691) | remove(objects) {
method getBoundingClientRect (line 10721) | getBoundingClientRect(shallow) {
method noFill (line 10770) | noFill() {
method noStroke (line 10781) | noStroke() {
method subdivide (line 10792) | subdivide() {
method _update (line 10807) | _update() {
method flagReset (line 10846) | flagReset() {
function replaceParent (line 11109) | function replaceParent(child, newParent) {
method constructor (line 11165) | constructor(x1, y1, x2, y2) {
function getAlignment (line 11229) | function getAlignment(anchor2) {
function getBaseline (line 11232) | function getBaseline(node) {
function getTagName (line 11237) | function getTagName(tag) {
function applyTransformsToVector (line 11240) | function applyTransformsToVector(transforms, vector3) {
function extractCSSText (line 11251) | function extractCSSText(text, styles) {
function getSvgStyles (line 11269) | function getSvgStyles(node) {
function getSvgAttributes (line 11285) | function getSvgAttributes(node) {
function applySvgViewBox (line 11296) | function applySvgViewBox(node, value) {
function applySvgAttributes (line 11337) | function applySvgAttributes(node, elem, parentStyles) {
function updateDefsCache (line 11570) | function updateDefsCache(node, defsCache) {
function getScene (line 11579) | function getScene(node) {
function xhr (line 12211) | function xhr(path, callback) {
method constructor (line 12225) | constructor(src, ox, oy, width, height, mode) {
method fromObject (line 12275) | static fromObject(obj) {
method copy (line 12288) | copy(image) {
method clone (line 12305) | clone(parent) {
method toObject (line 12324) | toObject() {
method dispose (line 12340) | dispose() {
method _update (line 12357) | _update() {
method flagReset (line 12415) | flagReset() {
method constructor (line 13239) | constructor(params) {
method setSize (line 13260) | setSize(width, height, ratio) {
method render (line 13279) | render() {
function renderArcEstimate (line 13300) | function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, cl...
function svgAngle2 (line 13335) | function svgAngle2(ux, uy, vx, vy) {
function isDefaultMatrix (line 13344) | function isDefaultMatrix(m) {
method constructor (line 14193) | constructor(params) {
method setSize (line 14212) | setSize(width, height) {
method render (line 14226) | render() {
method constructor (line 15518) | constructor(params) {
method setSize (line 15596) | setSize(width, height, ratio) {
method render (line 15626) | render() {
method constructor (line 15657) | constructor(options) {
method _bound (line 15774) | get _bound() {
method _bound (line 15777) | set _bound(v) {
method addEventListener (line 15780) | addEventListener() {
method on (line 15784) | on() {
method bind (line 15788) | bind() {
method removeEventListener (line 15792) | removeEventListener() {
method off (line 15796) | off() {
method unbind (line 15800) | unbind() {
method dispatchEvent (line 15804) | dispatchEvent() {
method trigger (line 15808) | trigger() {
method listen (line 15812) | listen() {
method ignore (line 15816) | ignore() {
method appendTo (line 15826) | appendTo(elem) {
method play (line 15844) | play() {
method pause (line 15855) | pause() {
method setPlaying (line 15859) | setPlaying(p) {
method release (line 15869) | release(obj) {
method getShapesAtPoint (line 15961) | getShapesAtPoint(x, y, options) {
method update (line 15974) | update() {
method render (line 16001) | render() {
method add (line 16012) | add(objects) {
method remove (line 16025) | remove(objects) {
method clear (line 16037) | clear() {
method makeLine (line 16051) | makeLine(x1, y1, x2, y2) {
method makeArrow (line 16066) | makeArrow(x1, y1, x2, y2, size) {
method makeRectangle (line 16133) | makeRectangle(x, y, width, height) {
method makeRoundedRectangle (line 16149) | makeRoundedRectangle(x, y, width, height, sides) {
method makeCircle (line 16164) | makeCircle(x, y, radius, resolution) {
method makeEllipse (line 16180) | makeEllipse(x, y, rx, ry, resolution) {
method makeStar (line 16196) | makeStar(x, y, outerRadius, innerRadius, sides) {
method makeCurve (line 16210) | makeCurve(points) {
method makePolygon (line 16244) | makePolygon(x, y, radius, sides) {
method makeArcSegment (line 16261) | makeArcSegment(x, y, innerRadius, outerRadius, startAngle, endAngle, res...
method makePoints (line 16282) | makePoints(p) {
method makePath (line 16309) | makePath(p) {
method makeText (line 16348) | makeText(message, x, y, styles) {
method makeLinearGradient (line 16364) | makeLinearGradient(x1, y1, x2, y2) {
method makeRadialGradient (line 16380) | makeRadialGradient(x1, y1, radius) {
method makeSprite (line 16399) | makeSprite(src, x, y, columns, rows, frameRate, autostart) {
method makeImage (line 16419) | makeImage(src, x, y, width, height, mode) {
method makeImageSequence (line 16435) | makeImageSequence(src, x, y, frameRate, autostart) {
method makeTexture (line 16451) | makeTexture(src, callback) {
method makeGroup (line 16462) | makeGroup(objects) {
method interpret (line 16480) | interpret(svg2, shallow, add) {
method load (line 16502) | load(pathOrSVGContent, callback) {
function fitToWindow (line 16615) | function fitToWindow() {
function fitToParent (line 16621) | function fitToParent() {
function updateDimensions (line 16632) | function updateDimensions(width, height) {
function loop (line 16638) | function loop() {
FILE: extras/js/arc.js
class Arc (line 18) | class Arc extends Two.Path {
method constructor (line 29) | constructor(x, y, width, height, startAngle, endAngle, resolution) {
method _update (line 104) | _update() {
method flagReset (line 138) | flagReset() {
method clone (line 157) | clone() {
FILE: extras/js/zui.js
class Surface (line 2) | class Surface {
method constructor (line 3) | constructor(object) {
method limits (line 7) | limits(min, max) {
method apply (line 21) | apply(px, py, s) {
class ZUI (line 34) | class ZUI {
method constructor (line 35) | constructor(group, domElement) {
method Clamp (line 60) | static Clamp(v, min, max) {
method TranslateMatrix (line 76) | static TranslateMatrix(m, x, y) {
method PositionToScale (line 82) | static PositionToScale(pos) {
method ScaleToPosition (line 86) | static ScaleToPosition(scale) {
method add (line 92) | add(surface) {
method addLimits (line 99) | addLimits(min, max) {
method clientToSurface (line 121) | clientToSurface(a, b, c) {
method surfaceToClient (line 140) | surfaceToClient(a, b, c) {
method zoomBy (line 159) | zoomBy(byF, clientX, clientY) {
method zoomSet (line 165) | zoomSet(zoom, clientX, clientY) {
method translateSurface (line 187) | translateSurface(x, y) {
method updateOffset (line 193) | updateOffset() {
method updateSurface (line 206) | updateSurface() {
method reset (line 215) | reset() {
method fitToLimits (line 223) | fitToLimits(s) {
FILE: extras/jsm/arc.js
class Arc (line 22) | class Arc extends Path {
method constructor (line 33) | constructor(x, y, width, height, startAngle, endAngle, resolution) {
method _update (line 108) | _update() {
method flagReset (line 142) | flagReset() {
method clone (line 161) | clone() {
FILE: extras/jsm/zui.d.ts
class ZUI (line 8) | class ZUI {
class Surface (line 57) | class Surface {
FILE: extras/jsm/zui.js
class Surface (line 3) | class Surface {
method constructor (line 4) | constructor(object) {
method limits (line 8) | limits(min, max) {
method apply (line 22) | apply(px, py, s) {
class ZUI (line 36) | class ZUI {
method constructor (line 37) | constructor(group, domElement) {
method Clamp (line 62) | static Clamp(v, min, max) {
method TranslateMatrix (line 78) | static TranslateMatrix(m, x, y) {
method PositionToScale (line 84) | static PositionToScale(pos) {
method ScaleToPosition (line 88) | static ScaleToPosition(scale) {
method add (line 94) | add(surface) {
method addLimits (line 107) | addLimits(min, max) {
method clientToSurface (line 147) | clientToSurface(a, b, c) {
method surfaceToClient (line 184) | surfaceToClient(a, b, c) {
method zoomBy (line 211) | zoomBy(byF, clientX, clientY) {
method zoomSet (line 225) | zoomSet(zoom, clientX, clientY) {
method translateSurface (line 254) | translateSurface(x, y) {
method updateOffset (line 260) | updateOffset() {
method updateSurface (line 273) | updateSurface() {
method reset (line 287) | reset() {
method fitToLimits (line 295) | fitToLimits(s) {
FILE: src/anchor.d.ts
class Anchor (line 15) | class Anchor extends Vector {
FILE: src/anchor.js
class Anchor (line 19) | class Anchor extends Vector {
method constructor (line 33) | constructor(
method makeBroadcast (line 61) | static makeBroadcast(scope) {
method fromObject (line 78) | static fromObject(obj) {
method copy (line 88) | copy(v) {
method clone (line 134) | clone() {
method toObject (line 145) | toObject() {
method toString (line 169) | toString() {
FILE: src/children.d.ts
class Children (line 8) | class Children extends Collection<Shape> {
FILE: src/children.js
class Children (line 10) | class Children extends Collection {
method ids (line 17) | get ids() {
method constructor (line 21) | constructor(children) {
method attach (line 40) | attach(children) {
method detach (line 56) | detach(children) {
FILE: src/collection.d.ts
class Collection (line 8) | class Collection<T = any> extends Array<T> {
FILE: src/collection.js
class Collection (line 10) | class Collection extends Array {
method _events (line 17) | get _events() {
method _events (line 20) | set _events(e) {
method _bound (line 25) | get _bound() {
method _bound (line 28) | set _bound(v) {
method addEventListener (line 32) | addEventListener() {
method on (line 35) | on() {
method bind (line 38) | bind() {
method removeEventListener (line 41) | removeEventListener() {
method off (line 44) | off() {
method unbind (line 47) | unbind() {
method dispatchEvent (line 50) | dispatchEvent() {
method trigger (line 53) | trigger() {
method listen (line 56) | listen() {
method ignore (line 59) | ignore() {
method constructor (line 63) | constructor() {
method pop (line 75) | pop() {
method shift (line 81) | shift() {
method push (line 87) | push() {
method unshift (line 93) | unshift() {
method splice (line 99) | splice() {
method sort (line 113) | sort() {
method reverse (line 119) | reverse() {
method indexOf (line 125) | indexOf() {
method map (line 129) | map(func, scope) {
FILE: src/constants.d.ts
type Constants (line 2) | interface Constants {
FILE: src/effects/gradient.d.ts
type SpreadProperties (line 2) | type SpreadProperties = 'pad' | 'reflect' | 'repeat';
type UnitsProperties (line 3) | type UnitsProperties = 'userSpaceOnUse' | 'objectBoundingBox';
class Gradient (line 10) | class Gradient extends TwoElement {
FILE: src/effects/gradient.js
class Gradient (line 14) | class Gradient extends Element {
method constructor (line 22) | constructor(stops) {
method fromObject (line 77) | static fromObject(obj) {
method clone (line 98) | clone(parent) {
method copy (line 126) | copy(gradient) {
method toObject (line 145) | toObject() {
method _update (line 171) | _update() {
method flagReset (line 185) | flagReset() {
method dispose (line 198) | dispose() {
function FlagStops (line 271) | function FlagStops() {
function BindStops (line 281) | function BindStops(items) {
function UnbindStops (line 299) | function UnbindStops(items) {
FILE: src/effects/image-sequence.d.ts
class ImageSequence (line 12) | class ImageSequence extends Rectangle {
FILE: src/effects/image-sequence.js
class ImageSequence (line 20) | class ImageSequence extends Rectangle {
method constructor (line 123) | constructor(src, ox, oy, frameRate) {
method fromObject (line 198) | static fromObject(obj) {
method copy (line 214) | copy(imageSequence) {
method play (line 235) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 266) | pause() {
method stop (line 276) | stop() {
method clone (line 290) | clone(parent) {
method toObject (line 317) | toObject() {
method dispose (line 341) | dispose() {
method _update (line 385) | _update() {
method flagReset (line 472) | flagReset() {
function FlagTextures (line 564) | function FlagTextures() {
function BindTextures (line 574) | function BindTextures(items) {
function UnbindTextures (line 589) | function UnbindTextures(items) {
function GenerateTexture (line 606) | function GenerateTexture(obj) {
FILE: src/effects/image.d.ts
type ModeProperties (line 2) | type ModeProperties = 'fill' | 'fit' | 'crop' | 'tile' | 'stretch';
class Image (line 14) | class Image extends Rectangle {
FILE: src/effects/image.js
class Image (line 18) | class Image extends Rectangle {
method constructor (line 47) | constructor(src, ox, oy, width, height, mode) {
method fromObject (line 107) | static fromObject(obj) {
method copy (line 123) | copy(image) {
method clone (line 143) | clone(parent) {
method toObject (line 165) | toObject() {
method dispose (line 182) | dispose() {
method _update (line 204) | _update() {
method flagReset (line 281) | flagReset() {
FILE: src/effects/linear-gradient.d.ts
class LinearGradient (line 12) | class LinearGradient extends Gradient {
FILE: src/effects/linear-gradient.js
class LinearGradient (line 19) | class LinearGradient extends Gradient {
method constructor (line 29) | constructor(x1, y1, x2, y2, stops) {
method fromObject (line 80) | static fromObject(obj) {
method copy (line 96) | copy(gradient) {
method clone (line 119) | clone(parent) {
method toObject (line 153) | toObject() {
method _update (line 170) | _update() {
method flagReset (line 184) | flagReset() {
function FlagEndPoints (line 230) | function FlagEndPoints() {
FILE: src/effects/radial-gradient.d.ts
class RadialGradient (line 13) | class RadialGradient extends Gradient {
FILE: src/effects/radial-gradient.js
class RadialGradient (line 20) | class RadialGradient extends Gradient {
method constructor (line 44) | constructor(cx, cy, r, stops, fx, fy) {
method fromObject (line 107) | static fromObject(obj) {
method copy (line 123) | copy(gradient) {
method clone (line 150) | clone(parent) {
method toObject (line 185) | toObject() {
method _update (line 210) | _update() {
method flagReset (line 230) | flagReset() {
function FlagCenter (line 280) | function FlagCenter() {
function FlagFocal (line 284) | function FlagFocal() {
FILE: src/effects/sprite.d.ts
class Sprite (line 14) | class Sprite extends Rectangle {
FILE: src/effects/sprite.js
class Sprite (line 20) | class Sprite extends Rectangle {
method constructor (line 151) | constructor(src, ox, oy, cols, rows, frameRate) {
method fromObject (line 231) | static fromObject(obj) {
method copy (line 247) | copy(sprite) {
method play (line 268) | play(firstFrame, lastFrame, onLastFrame) {
method pause (line 299) | pause() {
method stop (line 309) | stop() {
method clone (line 323) | clone(parent) {
method toObject (line 354) | toObject() {
method dispose (line 378) | dispose() {
method _update (line 411) | _update() {
method flagReset (line 501) | flagReset() {
FILE: src/effects/stop.d.ts
class Stop (line 10) | class Stop extends TwoElement {
FILE: src/effects/stop.js
class Stop (line 13) | class Stop extends Element {
method constructor (line 56) | constructor(offset, color, opacity) {
method fromObject (line 108) | static fromObject(obj) {
method copy (line 124) | copy(stop) {
method clone (line 144) | clone(parent) {
method toObject (line 168) | toObject() {
method flagReset (line 189) | flagReset() {
FILE: src/effects/texture.d.ts
type RepeatProperties (line 2) | type RepeatProperties = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
class Texture (line 11) | class Texture extends TwoElement {
FILE: src/effects/texture.js
class Texture (line 29) | class Texture extends Element {
method constructor (line 121) | constructor(src, callback) {
method fromObject (line 202) | fromObject(obj) {
method getAbsoluteURL (line 231) | static getAbsoluteURL(path) {
method loadHeadlessBuffer (line 247) | static loadHeadlessBuffer(texture, onLoad) {
method getTag (line 258) | static getTag(image) {
method getImage (line 272) | static getImage(src) {
method load (line 424) | static load(texture, callback) {
method clone (line 455) | clone() {
method copy (line 469) | copy(texture) {
method toObject (line 489) | toObject() {
method _update (line 510) | _update() {
method flagReset (line 539) | flagReset() {
method dispose (line 559) | dispose() {
function FlagOffset (line 675) | function FlagOffset() {
function FlagScale (line 684) | function FlagScale() {
FILE: src/element.d.ts
class Element (line 7) | class Element extends Events {
FILE: src/element.js
class Element (line 10) | class Element extends Events {
method constructor (line 53) | constructor() {
method fromObject (line 71) | static fromObject(obj) {
method flagReset (line 84) | flagReset() {
method copy (line 89) | copy(element) {
method toObject (line 101) | toObject() {
method dispose (line 115) | dispose() {
FILE: src/events.d.ts
class Events (line 7) | class Events {
FILE: src/events.js
class Events (line 6) | class Events {
method constructor (line 11) | constructor() {}
method addEventListener (line 20) | addEventListener(name, handler) {
method on (line 35) | on() {
method bind (line 43) | bind() {
method removeEventListener (line 54) | removeEventListener(name, handler) {
method off (line 95) | off() {
method unbind (line 103) | unbind() {
method dispatchEvent (line 114) | dispatchEvent(name) {
method trigger (line 133) | trigger() {
method listen (line 137) | listen(obj, name, handler) {
method ignore (line 160) | ignore(obj, name, handler) {
FILE: src/group.d.ts
type ChildParams (line 2) | type ChildParams =
class Group (line 13) | class Group extends Shape {
FILE: src/group.js
class Group (line 51) | class Group extends Shape {
method constructor (line 224) | constructor(children) {
method InsertChildren (line 268) | static InsertChildren(children) {
method RemoveChildren (line 280) | static RemoveChildren(children) {
method OrderChildren (line 291) | static OrderChildren(children) {
method fromObject (line 312) | static fromObject(obj) {
method IsVisible (line 382) | static IsVisible(element, visibleOnly) {
method VisitForHitTest (line 401) | static VisitForHitTest(
method copy (line 494) | copy(group) {
method clone (line 515) | clone(parent) {
method toObject (line 557) | toObject() {
method dispose (line 586) | dispose() {
method getShapesAtPoint (line 631) | getShapesAtPoint(x, y, options) {
method corner (line 700) | corner() {
method center (line 722) | center() {
method getById (line 749) | getById(id) {
method getByClassName (line 776) | getByClassName(className) {
method getByType (line 799) | getByType(type) {
method add (line 822) | add(objects) {
method remove (line 854) | remove(objects) {
method getBoundingClientRect (line 896) | getBoundingClientRect(shallow) {
method noFill (line 975) | noFill() {
method noStroke (line 987) | noStroke() {
method subdivide (line 999) | subdivide() {
method _update (line 1015) | _update() {
method flagReset (line 1061) | flagReset() {
function replaceParent (line 1330) | function replaceParent(child, newParent) {
FILE: src/matrix.d.ts
class Matrix (line 17) | class Matrix extends Events {
FILE: src/matrix.js
class Matrix (line 26) | class Matrix extends Events {
method constructor (line 40) | constructor(a, b, c, d, e, f) {
method Multiply (line 73) | static Multiply(A, B, C) {
method fromObject (line 137) | static fromObject(obj) {
method set (line 162) | set(a, b, c, d, e, f, g, h, i) {
method copy (line 195) | copy(m) {
method identity (line 216) | identity() {
method multiply (line 263) | multiply(a, b, c, d, e, f, g, h, i) {
method inverse (line 348) | inverse(output) {
method scale (line 402) | scale(sx, sy) {
method rotate (line 417) | rotate(n) {
method translate (line 431) | translate(x, y) {
method skewX (line 441) | skewX(n) {
method skewY (line 453) | skewY(n) {
method toString (line 466) | toString(fullMatrix) {
method toTransformArray (line 480) | toTransformArray(fullMatrix, output) {
method toArray (line 539) | toArray(fullMatrix, output) {
method toObject (line 590) | toObject() {
method clone (line 603) | clone() {
FILE: src/path.d.ts
type CapProperties (line 2) | type CapProperties = 'butt' | 'round' | 'square';
type JoinProperties (line 3) | type JoinProperties = 'miter' | 'round' | 'bevel';
class Path (line 14) | class Path extends Shape {
class FlagVertices (line 502) | class FlagVertices {
class FlagFill (line 527) | class FlagFill {
class FlagStroke (line 537) | class FlagStroke {
FILE: src/path.js
class Path (line 65) | class Path extends Shape {
method constructor (line 285) | constructor(vertices, closed, curved, manual) {
method fromObject (line 457) | static fromObject(obj) {
method copy (line 479) | copy(path) {
method clone (line 511) | clone(parent) {
method toObject (line 549) | toObject() {
method dispose (line 582) | dispose() {
method noFill (line 650) | noFill() {
method noStroke (line 660) | noStroke() {
method corner (line 671) | corner() {
method center (line 701) | center() {
method getBoundingClientRect (line 728) | getBoundingClientRect(shallow) {
method contains (line 848) | contains(x, y, options) {
method getPointAt (line 933) | getPointAt(t, obj) {
method plot (line 1065) | plot() {
method smooth (line 1087) | smooth(options) {
method subdivide (line 1181) | subdivide(limit) {
method _updateLength (line 1304) | _updateLength(limit, silent) {
method _update (line 1352) | _update() {
method flagReset (line 1480) | flagReset() {
function FlagVertices (line 1805) | function FlagVertices() {
function BindVertices (line 1819) | function BindVertices(items) {
function UnbindVertices (line 1836) | function UnbindVertices(items) {
function FlagFill (line 1851) | function FlagFill() {
function FlagStroke (line 1861) | function FlagStroke() {
FILE: src/registry.d.ts
class Registry (line 7) | class Registry {
FILE: src/registry.js
class Registry (line 6) | class Registry {
method constructor (line 10) | constructor() {}
method add (line 19) | add(id, obj) {
method remove (line 30) | remove(id) {
method get (line 42) | get(id) {
method contains (line 53) | contains(id) {
FILE: src/renderers/canvas.d.ts
class Renderer (line 12) | class Renderer extends Events {
FILE: src/renderers/canvas.js
class Renderer (line 1090) | class Renderer extends Events {
method constructor (line 1091) | constructor(params) {
method setSize (line 1143) | setSize(width, height, ratio) {
method render (line 1167) | render() {
function renderArcEstimate (line 1189) | function renderArcEstimate(
function svgAngle (line 1246) | function svgAngle(ux, uy, vx, vy) {
function isDefaultMatrix (line 1259) | function isDefaultMatrix(m) {
FILE: src/renderers/svg.d.ts
class Renderer (line 10) | class Renderer extends Events {
FILE: src/renderers/svg.js
class Renderer (line 1186) | class Renderer extends Events {
method constructor (line 1187) | constructor(params) {
method setSize (line 1228) | setSize(width, height) {
method render (line 1245) | render() {
FILE: src/renderers/webgl.d.ts
class Renderer (line 13) | class Renderer extends Events {
FILE: src/renderers/webgl.js
class Renderer (line 1722) | class Renderer extends Events {
method constructor (line 1723) | constructor(params) {
method setSize (line 1864) | setSize(width, height, ratio) {
method render (line 1909) | render() {
FILE: src/shape.d.ts
type ShapeHitTestOptions (line 2) | interface ShapeHitTestOptions {
class Shape (line 15) | class Shape extends TwoElement {
FILE: src/shape.js
class Shape (line 13) | class Shape extends Element {
method constructor (line 79) | constructor() {
method fromObject (line 162) | static fromObject(obj) {
method renderer (line 172) | get renderer() {
method renderer (line 175) | set renderer(v) {
method translation (line 183) | get translation() {
method translation (line 186) | set translation(v) {
method addTo (line 196) | addTo(group) {
method remove (line 206) | remove() {
method contains (line 228) | contains(x, y, options) {
method copy (line 273) | copy(shape) {
method clone (line 314) | clone(parent) {
method toObject (line 340) | toObject() {
method dispose (line 359) | dispose() {
method _update (line 385) | _update(bubbles) {
method flagReset (line 415) | flagReset() {
function FlagMatrix (line 515) | function FlagMatrix() {
FILE: src/shapes/arc-segment.d.ts
class ArcSegment (line 13) | class ArcSegment extends Path {
FILE: src/shapes/arc-segment.js
class ArcSegment (line 20) | class ArcSegment extends Path {
method constructor (line 71) | constructor(x, y, ir, or, sa, ea, res) {
method fromObject (line 142) | static fromObject(obj) {
method copy (line 158) | copy(arcSegment) {
method _update (line 179) | _update() {
method flagReset (line 325) | flagReset() {
method clone (line 344) | clone(parent) {
method toObject (line 381) | toObject() {
FILE: src/shapes/circle.d.ts
class Circle (line 10) | class Circle extends Path {
FILE: src/shapes/circle.js
class Circle (line 19) | class Circle extends Path {
method constructor (line 34) | constructor(ox, oy, r, resolution) {
method fromObject (line 82) | static fromObject(obj) {
method copy (line 98) | copy(circle) {
method _update (line 119) | _update() {
method flagReset (line 164) | flagReset() {
method clone (line 178) | clone(parent) {
method toObject (line 209) | toObject() {
FILE: src/shapes/ellipse.d.ts
class Ellipse (line 11) | class Ellipse extends Path {
FILE: src/shapes/ellipse.js
class Ellipse (line 20) | class Ellipse extends Path {
method constructor (line 47) | constructor(x, y, rx, ry, resolution) {
method fromObject (line 107) | static fromObject(obj) {
method copy (line 123) | copy(ellipse) {
method _update (line 144) | _update() {
method flagReset (line 189) | flagReset() {
method clone (line 203) | clone(parent) {
method toObject (line 237) | toObject() {
FILE: src/shapes/line.d.ts
class Line (line 11) | class Line extends Path {
FILE: src/shapes/line.js
class Line (line 17) | class Line extends Path {
method constructor (line 18) | constructor(x1, y1, x2, y2) {
FILE: src/shapes/points.d.ts
class Points (line 8) | class Points extends Shape {
FILE: src/shapes/points.js
class Points (line 34) | class Points extends Shape {
method constructor (line 59) | constructor(vertices) {
method fromObject (line 196) | static fromObject(obj) {
method copy (line 218) | copy(points) {
method clone (line 247) | clone(parent) {
method toObject (line 284) | toObject() {
method dispose (line 317) | dispose() {
method subdivide (line 411) | subdivide(limit) {
method _update (line 454) | _update() {
method flagReset (line 497) | flagReset() {
FILE: src/shapes/polygon.d.ts
class Polygon (line 10) | class Polygon extends Path {
FILE: src/shapes/polygon.js
class Polygon (line 19) | class Polygon extends Path {
method constructor (line 64) | constructor(x, y, radius, sides) {
method fromObject (line 131) | static fromObject(obj) {
method copy (line 147) | copy(polygon) {
method _update (line 168) | _update() {
method flagReset (line 210) | flagReset() {
method clone (line 224) | clone(parent) {
method toObject (line 257) | toObject() {
FILE: src/shapes/rectangle.d.ts
class Rectangle (line 10) | class Rectangle extends Path {
FILE: src/shapes/rectangle.js
class Rectangle (line 17) | class Rectangle extends Path {
method constructor (line 18) | constructor(x, y, width, height) {
method fromObject (line 76) | static fromObject(obj) {
method copy (line 92) | copy(rectangle) {
method _update (line 145) | _update() {
method flagReset (line 176) | flagReset() {
method clone (line 190) | clone(parent) {
method toObject (line 225) | toObject() {
FILE: src/shapes/rounded-rectangle.d.ts
class RoundedRectangle (line 13) | class RoundedRectangle extends Path {
FILE: src/shapes/rounded-rectangle.js
class RoundedRectangle (line 19) | class RoundedRectangle extends Path {
method constructor (line 58) | constructor(x, y, width, height, radius) {
method fromObject (line 137) | static fromObject(obj) {
method copy (line 153) | copy(roundedRectangle) {
method _update (line 182) | _update() {
method flagReset (line 285) | flagReset() {
method clone (line 299) | clone(parent) {
method toObject (line 334) | toObject() {
function FlagRadius (line 398) | function FlagRadius() {
FILE: src/shapes/star.d.ts
class Star (line 11) | class Star extends Path {
FILE: src/shapes/star.js
class Star (line 20) | class Star extends Path {
method constructor (line 59) | constructor(x, y, innerRadius, outerRadius, sides) {
method fromObject (line 128) | static fromObject(obj) {
method copy (line 144) | copy(star) {
method _update (line 165) | _update() {
method flagReset (line 209) | flagReset() {
method clone (line 223) | clone(parent) {
method toObject (line 258) | toObject() {
FILE: src/text.d.ts
type AlignmentProperties (line 2) | type AlignmentProperties = 'left' | 'center' | 'right';
type StyleProperties (line 3) | type StyleProperties = 'normal' | 'italic';
type DecorationProperties (line 4) | type DecorationProperties = 'underline' | 'strikethrough' | 'none';
type DirectionProperties (line 5) | type DirectionProperties = 'ltr' | 'rtl';
type BaselineProperties (line 6) | type BaselineProperties = 'top' | 'middle' | 'bottom' | 'baseline';
class Text (line 17) | class Text extends Shape {
FILE: src/text.js
class Text (line 32) | class Text extends Shape {
method constructor (line 284) | constructor(message, x, y, styles) {
method Measure (line 367) | static Measure(text) {
method fromObject (line 404) | static fromObject(obj) {
method copy (line 426) | copy(text) {
method clone (line 446) | clone(parent) {
method toObject (line 475) | toObject() {
method dispose (line 496) | dispose() {
method noFill (line 534) | noFill() {
method noStroke (line 544) | noStroke() {
method getBoundingClientRect (line 561) | getBoundingClientRect(shallow) {
method flagReset (line 623) | flagReset() {
function FlagFill (line 895) | function FlagFill() {
function FlagStroke (line 905) | function FlagStroke() {
FILE: src/two.d.ts
class Two (line 17) | class Two {
type BoundingBox (line 697) | type BoundingBox = {
type Dimensions (line 704) | type Dimensions = {
type SceneHitTestOptions (line 709) | interface SceneHitTestOptions extends ShapeHitTestOptions {
FILE: src/two.js
class Two (line 87) | class Two {
method _bound (line 95) | get _bound() {
method _bound (line 98) | set _bound(v) {
method addEventListener (line 102) | addEventListener() {
method on (line 105) | on() {
method bind (line 108) | bind() {
method removeEventListener (line 111) | removeEventListener() {
method off (line 114) | off() {
method unbind (line 117) | unbind() {
method dispatchEvent (line 120) | dispatchEvent() {
method trigger (line 123) | trigger() {
method listen (line 126) | listen() {
method ignore (line 129) | ignore() {
method constructor (line 181) | constructor(options) {
method appendTo (line 383) | appendTo(elem) {
method play (line 404) | play() {
method pause (line 416) | pause() {
method setPlaying (line 421) | setPlaying(p) {
method release (line 432) | release(obj) {
method getShapesAtPoint (line 556) | getShapesAtPoint(x, y, options) {
method update (line 570) | update() {
method render (line 605) | render() {
method add (line 618) | add(objects) {
method remove (line 633) | remove(objects) {
method clear (line 648) | clear() {
method makeLine (line 663) | makeLine(x1, y1, x2, y2) {
method makeArrow (line 680) | makeArrow(x1, y1, x2, y2, size) {
method makeRectangle (line 754) | makeRectangle(x, y, width, height) {
method makeRoundedRectangle (line 772) | makeRoundedRectangle(x, y, width, height, sides) {
method makeCircle (line 789) | makeCircle(x, y, radius, resolution) {
method makeEllipse (line 807) | makeEllipse(x, y, rx, ry, resolution) {
method makeStar (line 825) | makeStar(x, y, outerRadius, innerRadius, sides) {
method makeCurve (line 841) | makeCurve(points) {
method makePolygon (line 882) | makePolygon(x, y, radius, sides) {
method makeArcSegment (line 901) | makeArcSegment(
method makePoints (line 931) | makePoints(p) {
method makePath (line 963) | makePath(p) {
method makeText (line 1014) | makeText(message, x, y, styles) {
method makeLinearGradient (line 1031) | makeLinearGradient(x1, y1, x2, y2 /* stops */) {
method makeRadialGradient (line 1050) | makeRadialGradient(x1, y1, radius /* stops */) {
method makeSprite (line 1072) | makeSprite(src, x, y, columns, rows, frameRate, autostart) {
method makeImage (line 1094) | makeImage(src, x, y, width, height, mode) {
method makeImageSequence (line 1112) | makeImageSequence(src, x, y, frameRate, autostart) {
method makeTexture (line 1130) | makeTexture(src, callback) {
method makeGroup (line 1142) | makeGroup(objects) {
method interpret (line 1163) | interpret(svg, shallow, add) {
method load (line 1193) | load(pathOrSVGContent, callback) {
function fitToWindow (line 1229) | function fitToWindow() {
function fitToParent (line 1238) | function fitToParent() {
function updateDimensions (line 1252) | function updateDimensions(width, height) {
function loop (line 1262) | function loop() {
FILE: src/utils/canvas-polyfill.d.ts
type CanvasPolyfill (line 2) | interface CanvasPolyfill {
FILE: src/utils/curves.d.ts
type Curve (line 2) | interface Curve {
FILE: src/utils/curves.js
function getComponentOnCubicBezier (line 120) | function getComponentOnCubicBezier(t, a, b, c, d) {
function subdivide (line 140) | function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveLength (line 177) | function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
function getCurveBoundingBox (line 218) | function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) {
function integrate (line 299) | function integrate(f, a, b, n) {
function getCurveFromPoints (line 321) | function getCurveFromPoints(points, closed) {
function getControlPoints (line 349) | function getControlPoints(a, b, c) {
function getReflection (line 404) | function getReflection(a, b, relative) {
function getAnchorsFromArcData (line 422) | function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, cc...
FILE: src/utils/device-pixel-ratio.js
function getBackingStoreRatio (line 5) | function getBackingStoreRatio(ctx) {
function getRatio (line 20) | function getRatio(ctx) {
FILE: src/utils/dom.d.ts
type dom (line 2) | interface dom {
FILE: src/utils/dom.js
function fallbackRequest (line 43) | function fallbackRequest(callback, element) {
FILE: src/utils/error.d.ts
class TwoError (line 7) | class TwoError extends Error {
FILE: src/utils/error.js
class TwoError (line 6) | class TwoError extends Error {
method constructor (line 11) | constructor(message) {
FILE: src/utils/hit-test.js
constant TRANSPARENT_REGEX (line 6) | const TRANSPARENT_REGEX = /^(?:none|transparent)$/i;
constant DEFAULT_PRECISION (line 7) | const DEFAULT_PRECISION = 8;
constant EPSILON (line 8) | const EPSILON = Number.EPSILON;
function createPoint (line 10) | function createPoint(x, y) {
function pointsEqual (line 14) | function pointsEqual(a, b, epsilon = EPSILON) {
function svgAngle (line 18) | function svgAngle(ux, uy, vx, vy) {
function sampleArcPoints (line 29) | function sampleArcPoints(prev, anchor, precision) {
function buildPathHitParts (line 144) | function buildPathHitParts(path, precision = DEFAULT_PRECISION) {
function pointInPolygons (line 271) | function pointInPolygons(polygons, x, y) {
function distanceToSegmentSquared (line 301) | function distanceToSegmentSquared(x, y, a, b) {
function distanceToSegments (line 322) | function distanceToSegments(segments, x, y) {
function hasVisibleFill (line 340) | function hasVisibleFill(shape, override) {
function hasVisibleStroke (line 358) | function hasVisibleStroke(shape, override) {
function boundsContains (line 385) | function boundsContains(rect, x, y, tolerance = 0) {
FILE: src/utils/interpret-svg.js
function getAlignment (line 59) | function getAlignment(anchor) {
function getBaseline (line 63) | function getBaseline(node) {
function getTagName (line 69) | function getTagName(tag) {
function applyTransformsToVector (line 73) | function applyTransformsToVector(transforms, vector) {
function extractCSSText (line 96) | function extractCSSText(text, styles) {
function getSvgStyles (line 127) | function getSvgStyles(node) {
function getSvgAttributes (line 147) | function getSvgAttributes(node) {
function applySvgViewBox (line 169) | function applySvgViewBox(node, value) {
function applySvgAttributes (line 226) | function applySvgAttributes(node, elem, parentStyles) {
function updateDefsCache (line 538) | function updateDefsCache(node, defsCache) {
function getScene (line 556) | function getScene(node) {
FILE: src/utils/math.d.ts
type DecomposedMatrix (line 2) | interface DecomposedMatrix {
FILE: src/utils/math.js
constant TWO_PI (line 4) | const TWO_PI = Math.PI * 2;
constant HALF_PI (line 5) | const HALF_PI = Math.PI * 0.5;
function decomposeMatrix (line 14) | function decomposeMatrix(matrix, b, c, d, e, f) {
function setMatrix (line 43) | function setMatrix(matrix) {
function getComputedMatrix (line 55) | function getComputedMatrix(object, matrix) {
function lerp (line 90) | function lerp(a, b, t) {
function getPoT (line 102) | function getPoT(value) {
function mod (line 118) | function mod(v, l) {
function toFixed (line 139) | function toFixed(v) {
function getEffectiveStrokeWidth (line 151) | function getEffectiveStrokeWidth(object, worldMatrix) {
FILE: src/utils/path-commands.d.ts
type Commands (line 2) | interface Commands {
FILE: src/utils/path.js
constant EPSILON (line 7) | const EPSILON = Number.EPSILON;
function isRelativeAnchor (line 9) | function isRelativeAnchor(anchor) {
function setHandleComponent (line 13) | function setHandleComponent(anchor, side, dx, dy) {
function clearHandleComponent (line 35) | function clearHandleComponent(anchor, side) {
function getHandleOffset (line 39) | function getHandleOffset(anchor, side) {
function hasNonZeroHandle (line 55) | function hasNonZeroHandle(anchor, side) {
function updateAnchorCommand (line 60) | function updateAnchorCommand(anchor) {
function inheritRelative (line 71) | function inheritRelative(anchor, reference) {
function isSegmentCurved (line 77) | function isSegmentCurved(a, b) {
function lerpPoint (line 88) | function lerpPoint(a, b, t) {
function getAbsoluteHandle (line 95) | function getAbsoluteHandle(anchor, side) {
function splitSubdivisionSegment (line 106) | function splitSubdivisionSegment(start, end, t) {
function applyGlobalSmooth (line 137) | function applyGlobalSmooth(vertices, from, to, closed, loop, asymmetric) {
function applyCatmullRom (line 218) | function applyCatmullRom(anchor, prev, next, factor, clampIn, clampOut) {
function applyGeometric (line 261) | function applyGeometric(anchor, prev, next, factor, clampIn, clampOut) {
function applyLocalSmooth (line 299) | function applyLocalSmooth(vertices, from, to, closed, loop, options) {
FILE: src/utils/shaders.d.ts
type shaders (line 2) | interface shaders {
FILE: src/utils/shape.js
function contains (line 14) | function contains(path, t) {
function getIdByLength (line 41) | function getIdByLength(path, target) {
function getCurveLength (line 62) | function getCurveLength(a, b, limit) {
function getSubdivisions (line 91) | function getSubdivisions(a, b, limit) {
function getEffectFromObject (line 120) | function getEffectFromObject(obj) {
FILE: src/utils/underscore.d.ts
type _ (line 2) | interface _ {
FILE: src/utils/underscore.js
function isArrayLike (line 5) | function isArrayLike(collection) {
FILE: src/utils/xhr.js
function xhr (line 9) | function xhr(path, callback) {
FILE: src/vector.d.ts
class Vector (line 10) | class Vector extends Events {
FILE: src/vector.js
class Vector (line 43) | class Vector extends Events {
method constructor (line 55) | constructor(x = 0, y = 0) {
method add (line 120) | static add(v1, v2) {
method sub (line 132) | static sub(v1, v2) {
method subtract (line 141) | static subtract(v1, v2) {
method ratioBetween (line 152) | static ratioBetween(v1, v2) {
method angleBetween (line 163) | static angleBetween(v1, v2) {
method distanceBetween (line 184) | static distanceBetween(v1, v2) {
method distanceBetweenSquared (line 195) | static distanceBetweenSquared(v1, v2) {
method set (line 210) | set(x, y) {
method copy (line 222) | copy(v) {
method clear (line 233) | clear() {
method clone (line 245) | clone() {
method add (line 273) | add(x, y) {
method addSelf (line 296) | addSelf(v) {
method sub (line 324) | sub(x, y) {
method subtract (line 347) | subtract() {
method subSelf (line 356) | subSelf(v) {
method subtractSelf (line 365) | subtractSelf(v) {
method multiply (line 393) | multiply(x, y) {
method multiplySelf (line 416) | multiplySelf(v) {
method multiplyScalar (line 426) | multiplyScalar(s) {
method divide (line 454) | divide(x, y) {
method divideSelf (line 483) | divideSelf(v) {
method divideScalar (line 493) | divideScalar(s) {
method negate (line 502) | negate() {
method dot (line 512) | dot(v) {
method length (line 522) | length() {
method lengthSquared (line 532) | lengthSquared() {
method normalize (line 541) | normalize() {
method distanceTo (line 551) | distanceTo(v) {
method distanceToSquared (line 561) | distanceToSquared(v) {
method setLength (line 573) | setLength(l) {
method equals (line 585) | equals(v, eps) {
method lerp (line 598) | lerp(v, t) {
method isZero (line 611) | isZero(eps) {
method toString (line 622) | toString() {
method toObject (line 632) | toObject() {
method rotate (line 642) | rotate(radians) {
FILE: utils/build.js
function buildModules (line 17) | async function buildModules() {
function template (line 71) | function template(buffer, isExposed) {
function publishModule (line 84) | function publishModule() {
function getFileSize (line 100) | function getFileSize(filename) {
function formatFileSize (line 105) | function formatFileSize(v) {
function build (line 115) | async function build() {
function getJSON (line 140) | function getJSON(filename) {
FILE: utils/document.js
function preprocess (line 32) | function preprocess() {
function process (line 53) | function process() {
function getHref (line 161) | function getHref(name) {
function getRoot (line 179) | function getRoot(citations, shouldSplice) {
function expandSee (line 194) | function expandSee(see) {
function expandTag (line 198) | function expandTag(tag) {
function expandParam (line 211) | function expandParam(param) {
function expandLink (line 215) | function expandLink(object, property) {
function getDirectoryMatch (line 262) | function getDirectoryMatch(str) {
FILE: wiki/.vuepress/config.js
function getJSON (line 37) | function getJSON(filename) {
Condensed preview — 207 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,904K chars).
[
{
"path": ".eslintignore",
"chars": 10,
"preview": "/**/*.d.ts"
},
{
"path": ".eslintrc.json",
"chars": 776,
"preview": "{\n\t\"parser\": \"babel-eslint\",\n\t\"extends\": \"eslint:recommended\",\n\t\"env\": {\n\t\t\"browser\": true,\n\t\t\"commonjs\": true,\n\t\t\"amd\":"
},
{
"path": ".gitattributes",
"chars": 542,
"preview": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text=auto\n\n# Explicitly declare text files yo"
},
{
"path": ".github/FUNDING.yml",
"chars": 520,
"preview": "# These are supported funding model platforms\n\ngithub: [jonobr1] # Replace with up to 4 GitHub Sponsors-enabled username"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 1061,
"preview": "---\nname: Bug report\nabout: Create a report to help improve Two.js\ntitle: \"[Bug]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Desc"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 625,
"preview": "---\nname: Feature request\nabout: Suggest an idea or enhancement to Two.js\ntitle: \"[Enhancement]\"\nlabels: enhancement\nass"
},
{
"path": ".github/ISSUE_TEMPLATE/output.md",
"chars": 789,
"preview": "---\nname: Output\nabout: Share what you have made with Two.js\ntitle: \"[Output]\"\nlabels: output\nassignees: ''\n\n---\n\n**What"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 890,
"preview": "---\nname: Question\nabout: Ask a question about Two.js\ntitle: \"[Question]\"\nlabels: question\nassignees: ''\n\n---\n\n**Describ"
},
{
"path": ".github/workflows/codeql.yml",
"chars": 1616,
"preview": "name: \"CodeQL\"\n\non:\n push:\n branches: [ \"dev\" ]\n pull_request:\n branches: [ \"dev\" ]\n schedule:\n - cron: \"22 "
},
{
"path": ".github/workflows/lint.yml",
"chars": 277,
"preview": "name: Lint\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n # checkout@v5\n - uses:"
},
{
"path": ".github/workflows/publish.yml",
"chars": 689,
"preview": "name: Publish Package\n\non:\n push:\n tags:\n - 'v*'\n\npermissions:\n id-token: write # Required for OIDC\n content"
},
{
"path": ".gitignore",
"chars": 168,
"preview": "node_modules\n*.DS_Store\njunk/\n*.log\ndocs.json\ndist\n.idea\n.codacy\ntests/typescript/package-lock.json\n\n#Ignore vscode AI r"
},
{
"path": ".npmrc",
"chars": 21,
"preview": "package-lock = false\n"
},
{
"path": ".nvmrc",
"chars": 7,
"preview": "v14.7.0"
},
{
"path": "CLAUDE.md",
"chars": 8060,
"preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3357,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 2311,
"preview": "## How to contribute to Two.js\n\n#### **Do you have a question?**\n\n* All questions answered by Two.js maintainers are in "
},
{
"path": "LICENSE",
"chars": 1090,
"preview": "MIT License\n\nCopyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi\n\nPermission is hereby granted, free of charge, to any "
},
{
"path": "README.md",
"chars": 6966,
"preview": "# Two.js\n\n[![NPM Package][npm]][npm-url]\n[![Build Size][build-size]][build-size-url]\n[![NPM Downloads][npm-downloads]][n"
},
{
"path": "SECURITY.md",
"chars": 1391,
"preview": "# Security Policy\n\nIf you have discovered a security vulnerability in this project, please report it privately. **Do not"
},
{
"path": "build/two.js",
"chars": 539450,
"preview": "/*\nMIT License\n\nCopyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi\n\nPermission is hereby granted, free of charge, to a"
},
{
"path": "build/two.module.js",
"chars": 518344,
"preview": "/*\nMIT License\n\nCopyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi\n\nPermission is hereby granted, free of charge, to a"
},
{
"path": "deploy.sh",
"chars": 319,
"preview": "#!/usr/bin/env sh\n\n# abort on errors\nset -e\n\n# build\nnpm run docs:build\n\n# navigate into the build output directory\ncd w"
},
{
"path": "extras/js/arc.js",
"chars": 6244,
"preview": "(function () {\n const TWO_PI = Math.PI * 2;\n const cos = Math.cos,\n sin = Math.sin;\n\n /**\n * @name Two.Arc\n * "
},
{
"path": "extras/js/zui.js",
"chars": 5522,
"preview": "(function () {\n class Surface {\n constructor(object) {\n this.object = object;\n }\n\n limits(min, max) {\n "
},
{
"path": "extras/jsm/arc.js",
"chars": 5942,
"preview": "import { TWO_PI } from '../../src/utils/math.js';\nimport { Constants } from '../../src/constants.js';\n\nimport { Anchor }"
},
{
"path": "extras/jsm/zui.d.ts",
"chars": 1854,
"preview": "declare module 'two.js/extras/jsm/zui' {\n /**\n * @name Two.ZUI\n * @class\n * @param {Group} group - The scene or g"
},
{
"path": "extras/jsm/zui.js",
"chars": 8365,
"preview": "import { Matrix } from '../../src/matrix.js';\n\nclass Surface {\n constructor(object) {\n this.object = object;\n }\n\n "
},
{
"path": "package.json",
"chars": 1904,
"preview": "{\n \"name\": \"two.js\",\n \"version\": \"v0.8.23\",\n \"description\": \"A renderer agnostic two-dimensional drawing api for the "
},
{
"path": "src/anchor.d.ts",
"chars": 3716,
"preview": "declare module 'two.js/src/anchor' {\n /**\n * @class\n * @name Two.Anchor\n * @param {Number} [x=0] - The x po"
},
{
"path": "src/anchor.js",
"chars": 7150,
"preview": "import { Commands } from './utils/path-commands.js';\nimport { Events } from './events.js';\nimport { Vector } from './vec"
},
{
"path": "src/children.d.ts",
"chars": 1102,
"preview": "declare module 'two.js/src/children' {\n /**\n * @class\n * @name Two.Group.Children\n\n * @description A childr"
},
{
"path": "src/children.js",
"chars": 1559,
"preview": "import { Events } from './events.js';\nimport { Collection } from './collection.js';\n\n/**\n * @class\n * @name Two.Group.Ch"
},
{
"path": "src/collection.d.ts",
"chars": 946,
"preview": "declare module 'two.js/src/collection' {\n /**\n * @name Two.Collection\n * @class\n\n * @description An `Array`"
},
{
"path": "src/collection.js",
"chars": 3419,
"preview": "import { Events } from './events.js';\n\n/**\n * @name Two.Collection\n * @class\n * @extends Two.Events\n * @description An `"
},
{
"path": "src/constants.d.ts",
"chars": 422,
"preview": "declare module 'two.js/src/constants' {\n export interface Constants {\n NextFrameId: number;\n Types: {\n webgl"
},
{
"path": "src/constants.js",
"chars": 2005,
"preview": "let count = 0;\n\nexport const Constants = {\n /**\n * @name Two.NextFrameId\n * @property {Number}\n * @description Th"
},
{
"path": "src/effects/gradient.d.ts",
"chars": 5140,
"preview": "declare module 'two.js/src/effects/gradient' {\n type SpreadProperties = 'pad' | 'reflect' | 'repeat';\n type UnitsPrope"
},
{
"path": "src/effects/gradient.js",
"chars": 7988,
"preview": "import { Collection } from '../collection.js';\nimport { Events } from '../events.js';\nimport { Element } from '../elemen"
},
{
"path": "src/effects/image-sequence.d.ts",
"chars": 7008,
"preview": "declare module 'two.js/src/effects/image-sequence' {\n /**\n * @name Two.ImageSequence\n * @class\n\n * @param {"
},
{
"path": "src/effects/image-sequence.js",
"chars": 16554,
"preview": "import { Collection } from '../collection.js';\nimport { Events } from '../events.js';\nimport { lerp } from '../utils/mat"
},
{
"path": "src/effects/image.d.ts",
"chars": 3995,
"preview": "declare module 'two.js/src/effects/image' {\n export type ModeProperties = 'fill' | 'fit' | 'crop' | 'tile' | 'stretch';"
},
{
"path": "src/effects/image.js",
"chars": 8868,
"preview": "import { Vector } from '../vector.js';\nimport { Rectangle } from '../shapes/rectangle.js';\nimport { Texture } from './te"
},
{
"path": "src/effects/linear-gradient.d.ts",
"chars": 3951,
"preview": "declare module 'two.js/src/effects/linear-gradient' {\n /**\n * @name Two.LinearGradient\n * @class\n * @param {Numbe"
},
{
"path": "src/effects/linear-gradient.js",
"chars": 6341,
"preview": "import { Events } from '../events.js';\nimport { _ } from '../utils/underscore.js';\n\nimport { Stop } from './stop.js';\nim"
},
{
"path": "src/effects/radial-gradient.d.ts",
"chars": 4531,
"preview": "declare module 'two.js/src/effects/radial-gradient' {\n /**\n * @name Two.RadialGradient\n * @class\n * @param {Numbe"
},
{
"path": "src/effects/radial-gradient.js",
"chars": 7614,
"preview": "import { Events } from '../events.js';\nimport { _ } from '../utils/underscore.js';\n\nimport { Stop } from './stop.js';\nim"
},
{
"path": "src/effects/sprite.d.ts",
"chars": 7427,
"preview": "declare module 'two.js/src/effects/sprite' {\n /**\n * @name Two.Sprite\n * @class\n\n * @param {String|Texture}"
},
{
"path": "src/effects/sprite.js",
"chars": 14943,
"preview": "import { lerp } from '../utils/math.js';\nimport { _ } from '../utils/underscore.js';\n\nimport { Vector } from '../vector."
},
{
"path": "src/effects/stop.d.ts",
"chars": 4075,
"preview": "declare module 'two.js/src/effects/stop' {\n /**\n * @name Two.Stop\n * @class\n * @param {Number} [offset] - The off"
},
{
"path": "src/effects/stop.js",
"chars": 5813,
"preview": "import { _ } from '../utils/underscore.js';\nimport { Element } from '../element.js';\n\n/**\n * @name Two.Stop\n * @class\n *"
},
{
"path": "src/effects/texture.d.ts",
"chars": 9486,
"preview": "declare module 'two.js/src/effects/texture' {\n type RepeatProperties = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat'"
},
{
"path": "src/effects/texture.js",
"chars": 19208,
"preview": "import { root } from '../utils/root.js';\nimport { Events } from '../events.js';\nimport { Element } from '../element.js';"
},
{
"path": "src/element.d.ts",
"chars": 3296,
"preview": "declare module 'two.js/src/element' {\n /**\n * @name Two.Element\n * @class\n * @description The foundational object"
},
{
"path": "src/element.js",
"chars": 5533,
"preview": "import { Events } from './events.js';\nimport { Constants } from './constants.js';\n\n/**\n * @name Two.Element\n * @class\n *"
},
{
"path": "src/events.d.ts",
"chars": 3154,
"preview": "declare module 'two.js/src/events' {\n /**\n * @name Two.Events\n * @class\n * @description Object inherited by many "
},
{
"path": "src/events.js",
"chars": 4383,
"preview": "/**\n * @name Two.Events\n * @class\n * @description Object inherited by many Two.js objects in order to facilitate custom "
},
{
"path": "src/group.d.ts",
"chars": 15442,
"preview": "declare module 'two.js/src/group' {\n type ChildParams =\n | Parameters<typeof Path.fromObject>[0]\n | Parameters<ty"
},
{
"path": "src/group.js",
"chars": 38063,
"preview": "import { Events } from './events.js';\nimport { _ } from './utils/underscore.js';\nimport { getEffectFromObject } from './"
},
{
"path": "src/matrix.d.ts",
"chars": 10192,
"preview": "declare module 'two.js/src/matrix' {\n /**\n * @name Two.Matrix\n * @class\n * @param {Number} [a=1] - The value for "
},
{
"path": "src/matrix.js",
"chars": 17166,
"preview": "import { NumArray, toFixed, setMatrix } from './utils/math.js';\nimport { Events } from './events.js';\n\n// Constants\n\ncon"
},
{
"path": "src/path.d.ts",
"chars": 19283,
"preview": "declare module 'two.js/src/path' {\n export type CapProperties = 'butt' | 'round' | 'square';\n export type JoinProperti"
},
{
"path": "src/path.js",
"chars": 48839,
"preview": "import { Commands } from './utils/path-commands.js';\nimport { Collection } from './collection.js';\nimport { lerp, mod, d"
},
{
"path": "src/registry.d.ts",
"chars": 1070,
"preview": "declare module 'two.js/src/registry' {\n /**\n * @name Two.Registry\n * @class\n * @description An arbitrary class to"
},
{
"path": "src/registry.js",
"chars": 1324,
"preview": "/**\n * @name Two.Registry\n * @class\n * @description An arbitrary class to manage a directory of things. Mainly used for "
},
{
"path": "src/renderers/canvas.d.ts",
"chars": 3651,
"preview": "declare module 'two.js/src/renderers/canvas' {\n /**\n * @name Two.CanvasRenderer\n * @class\n\n * @param {Objec"
},
{
"path": "src/renderers/canvas.js",
"chars": 32422,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport {\n decomposeMatrix,\n mod,\n TWO_PI,\n getEffectiveStrokeW"
},
{
"path": "src/renderers/svg.d.ts",
"chars": 3098,
"preview": "declare module 'two.js/src/renderers/svg' {\n /**\n * @name Two.SVGRenderer\n * @class\n\n * @param {Object} [pa"
},
{
"path": "src/renderers/svg.js",
"chars": 34326,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { decomposeMatrix, mod, toFixed, getEffectiveStrokeWidth } "
},
{
"path": "src/renderers/webgl.d.ts",
"chars": 4579,
"preview": "declare module 'two.js/src/renderers/webgl' {\n /**\n * @name Two.WebGLRenderer\n * @class\n\n * @param {Object}"
},
{
"path": "src/renderers/webgl.js",
"chars": 56324,
"preview": "import { Commands } from '../utils/path-commands.js';\n\nimport { root } from '../utils/root.js';\nimport {\n getPoT,\n mod"
},
{
"path": "src/shape.d.ts",
"chars": 7968,
"preview": "declare module 'two.js/src/shape' {\n export interface ShapeHitTestOptions {\n precision?: number;\n tolerance?: num"
},
{
"path": "src/shape.js",
"chars": 13329,
"preview": "import { Events } from './events.js';\nimport { Element } from './element.js';\nimport { Matrix } from './matrix.js';\nimpo"
},
{
"path": "src/shapes/arc-segment.d.ts",
"chars": 4311,
"preview": "declare module 'two.js/src/shapes/arc-segment' {\n /**\n * @name Two.ArcSegment\n * @class\n * @param {Number} [x=0] "
},
{
"path": "src/shapes/arc-segment.js",
"chars": 11448,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { mod, HALF_PI, TWO_PI } from '../utils/math.js';\n\nimport {"
},
{
"path": "src/shapes/circle.d.ts",
"chars": 2255,
"preview": "declare module 'two.js/src/shapes/circle' {\n /**\n * @name Two.Circle\n * @class\n * @param {Number} [x=0] - The x p"
},
{
"path": "src/shapes/circle.js",
"chars": 5964,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { HALF_PI, TWO_PI } from '../utils/math.js';\n\nimport { Path"
},
{
"path": "src/shapes/ellipse.d.ts",
"chars": 2302,
"preview": "declare module 'two.js/src/shapes/ellipse' {\n /**\n * @name Two.Ellipse\n * @class\n * @param {Number} [x=0] - The x"
},
{
"path": "src/shapes/ellipse.js",
"chars": 6998,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { HALF_PI, TWO_PI } from '../utils/math.js';\n\nimport { Path"
},
{
"path": "src/shapes/line.d.ts",
"chars": 910,
"preview": "declare module 'two.js/src/shapes/line' {\n /**\n * @name Two.Line\n * @class\n\n * @param {Number} [x1=0] - The"
},
{
"path": "src/shapes/line.js",
"chars": 1805,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { TwoError } from '../utils/error.js';\nimport { _ } from '."
},
{
"path": "src/shapes/points.d.ts",
"chars": 10042,
"preview": "declare module 'two.js/src/shapes/points' {\n /**\n * @name Two.Points\n * @class\n * @param {Vector[]} [vertices] - "
},
{
"path": "src/shapes/points.js",
"chars": 20374,
"preview": "import { subdivide } from '../utils/curves.js';\nimport { getIdByLength } from '../utils/shape.js';\nimport { _ } from '.."
},
{
"path": "src/shapes/polygon.d.ts",
"chars": 2908,
"preview": "declare module 'two.js/src/shapes/polygon' {\n /**\n * @name Two.Polygon\n * @class\n * @param {Number} [x=0] - The x"
},
{
"path": "src/shapes/polygon.js",
"chars": 8110,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { TWO_PI } from '../utils/math.js';\n\nimport { Path } from '"
},
{
"path": "src/shapes/rectangle.d.ts",
"chars": 3140,
"preview": "declare module 'two.js/src/shapes/rectangle' {\n /**\n * @name Two.Rectangle\n * @class\n * @param {Number} [x=0] - T"
},
{
"path": "src/shapes/rectangle.js",
"chars": 7269,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { Events } from '../events.js';\n\nimport { Path } from '../p"
},
{
"path": "src/shapes/rounded-rectangle.d.ts",
"chars": 3305,
"preview": "declare module 'two.js/src/shapes/rounded-rectangle' {\n /**\n * @name Two.RoundedRectangle\n * @class\n\n * @pa"
},
{
"path": "src/shapes/rounded-rectangle.js",
"chars": 10068,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { Events } from '../events.js';\n\nimport { Path } from '../p"
},
{
"path": "src/shapes/star.d.ts",
"chars": 3341,
"preview": "declare module 'two.js/src/shapes/star' {\n /**\n * @name Two.Star\n * @class\n * @param {Number} [x=0] - The x posit"
},
{
"path": "src/shapes/star.js",
"chars": 7390,
"preview": "import { Commands } from '../utils/path-commands.js';\nimport { TWO_PI } from '../utils/math.js';\n\nimport { Path } from '"
},
{
"path": "src/text.d.ts",
"chars": 13942,
"preview": "declare module 'two.js/src/text' {\n export type AlignmentProperties = 'left' | 'center' | 'right';\n export type StyleP"
},
{
"path": "src/text.js",
"chars": 23955,
"preview": "import { Events } from './events.js';\nimport { _ } from './utils/underscore.js';\n\nimport { Shape } from './shape.js';\n\ni"
},
{
"path": "src/two.d.ts",
"chars": 26609,
"preview": "declare module 'two.js' {\n /**\n * @name Two\n * @class\n * @global\n\n * @param {Object} [options]\n * @"
},
{
"path": "src/two.js",
"chars": 37514,
"preview": "// Utils\n\nimport { CanvasPolyfill } from './utils/canvas-polyfill.js';\nimport * as Curves from './utils/curves.js';\nimpo"
},
{
"path": "src/utils/canvas-polyfill.d.ts",
"chars": 295,
"preview": "declare module 'two.js/src/utils/canvas-polyfill' {\n export interface CanvasPolyfill {\n Image: any;\n isHeadless: "
},
{
"path": "src/utils/canvas-polyfill.js",
"chars": 1775,
"preview": "export const CanvasPolyfill = {\n /**\n * @param {Image}\n */\n Image: null,\n\n /**\n * @param {Boolean}\n */\n isHe"
},
{
"path": "src/utils/curves.d.ts",
"chars": 6737,
"preview": "declare module 'two.js/src/utils/curves' {\n export interface Curve {\n CollinearityEpsilon: number;\n RecursionLimi"
},
{
"path": "src/utils/curves.js",
"chars": 14269,
"preview": "import { mod, HALF_PI } from './math.js';\nimport { Commands } from './path-commands.js';\n\nimport { Anchor } from '../anc"
},
{
"path": "src/utils/device-pixel-ratio.d.ts",
"chars": 406,
"preview": "declare module 'two.js/src/utils/device-pixel-ratio' {\n /**\n * @name Two.Utils.getRatio\n * @function\n * @param {C"
},
{
"path": "src/utils/device-pixel-ratio.js",
"chars": 691,
"preview": "import { root } from './root.js';\n\nconst devicePixelRatio = root.devicePixelRatio || 1;\n\nfunction getBackingStoreRatio(c"
},
{
"path": "src/utils/dom.d.ts",
"chars": 97,
"preview": "declare module 'two.js/src/utils/dom' {\n export interface dom {\n temp: HTMLDivElement;\n }\n}\n"
},
{
"path": "src/utils/dom.js",
"chars": 1710,
"preview": "import { root } from './root.js';\nimport { _ } from './underscore.js';\n\nexport const dom = {\n\n hasEventListeners: typeo"
},
{
"path": "src/utils/error.d.ts",
"chars": 249,
"preview": "declare module 'two.js/src/utils/error' {\n /**\n * @name Two.Utils.Error\n * @class\n * @description Custom error th"
},
{
"path": "src/utils/error.js",
"chars": 260,
"preview": "/**\n * @name Two.Utils.Error\n * @class\n * @description Custom error throwing for Two.js specific identification.\n */\nexp"
},
{
"path": "src/utils/hit-test.js",
"chars": 9255,
"preview": "import { Commands } from './path-commands.js';\nimport { getSubdivisions } from './shape.js';\nimport { Constants } from '"
},
{
"path": "src/utils/interpret-svg.d.ts",
"chars": 1817,
"preview": "declare module 'two.js/src/utils/interpret-svg' {\n /**\n * @name Two.Utils.read\n * @property {Object} read - A map o"
},
{
"path": "src/utils/interpret-svg.js",
"chars": 38244,
"preview": "import { root } from './root.js';\nimport { Commands } from './path-commands.js';\nimport { decomposeMatrix } from './math"
},
{
"path": "src/utils/math.d.ts",
"chars": 3296,
"preview": "declare module 'two.js/src/utils/math' {\n export interface DecomposedMatrix {\n translateX: number;\n translateY: n"
},
{
"path": "src/utils/math.js",
"chars": 5438,
"preview": "import { root } from './root.js';\n\nlet Matrix;\nconst TWO_PI = Math.PI * 2;\nconst HALF_PI = Math.PI * 0.5;\n\n/**\n * @name "
},
{
"path": "src/utils/path-commands.d.ts",
"chars": 162,
"preview": "declare module 'two.js/src/utils/path-commands' {\n export interface Commands {\n move: 'M';\n line: 'L';\n curve:"
},
{
"path": "src/utils/path-commands.js",
"chars": 94,
"preview": "export const Commands = {\n move: 'M',\n line: 'L',\n curve: 'C',\n arc: 'A',\n close: 'Z'\n};\n"
},
{
"path": "src/utils/path.js",
"chars": 9081,
"preview": "import { lerp, mod } from './math.js';\nimport { Commands } from './path-commands.js';\n\nimport { Vector } from '../vector"
},
{
"path": "src/utils/root.d.ts",
"chars": 81,
"preview": "declare module 'two.js/src/utils/root' {\n export let root: typeof globalThis;\n}\n"
},
{
"path": "src/utils/root.js",
"chars": 204,
"preview": "\nlet root;\n\nif (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = g"
},
{
"path": "src/utils/shaders.d.ts",
"chars": 327,
"preview": "declare module 'two.js/src/utils/shaders' {\n export interface shaders {\n create(gl: any, source: any, type: any): an"
},
{
"path": "src/utils/shaders.js",
"chars": 2307,
"preview": "import { TwoError } from './error.js';\n\nexport const shaders = {\n\n create: function(gl, source, type) {\n\n const shad"
},
{
"path": "src/utils/shape.d.ts",
"chars": 799,
"preview": "declare module 'two.js/src/utils/shape' {\n /**\n * @private\n * @param {Path} path - The path to analyze against.\n "
},
{
"path": "src/utils/shape.js",
"chars": 2946,
"preview": "import { Texture } from '../effects/texture.js';\nimport { subdivide, getCurveLength as gcl } from './curves.js';\nimport "
},
{
"path": "src/utils/underscore.d.ts",
"chars": 357,
"preview": "declare module 'two.js/src/utils/underscore' {\n export interface _ {\n isNaN(obj: any): boolean;\n isElement(obj: a"
},
{
"path": "src/utils/underscore.js",
"chars": 1909,
"preview": "import { root } from './root.js';\n\nconst slice = Array.prototype.slice;\n\nfunction isArrayLike(collection) {\n if (collec"
},
{
"path": "src/utils/xhr.d.ts",
"chars": 460,
"preview": "declare module 'two.js/src/utils/xhr' {\n /**\n * @name Two.Utils.xhr\n * @function\n * @param {String} path\n * @pa"
},
{
"path": "src/utils/xhr.js",
"chars": 555,
"preview": "/**\n * @name Two.Utils.xhr\n * @function\n * @param {String} path\n * @param {Function} callback\n * @returns {XMLHttpReques"
},
{
"path": "src/vector.d.ts",
"chars": 11671,
"preview": "declare module 'two.js/src/vector' {\n /**\n * @name Two.Vector\n * @class\n\n * @param {Number} [x=0] - Any num"
},
{
"path": "src/vector.js",
"chars": 16354,
"preview": "import { Events } from './events.js';\nimport { toFixed } from './utils/math.js';\n\nconst proto = {\n x: {\n enumerable:"
},
{
"path": "tests/index.html",
"chars": 1152,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <title>Two.js Tests</title>\n <link\n rel=\"styles"
},
{
"path": "tests/noWebGL.html",
"chars": 1000,
"preview": "<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>Two.js Tests sans WebGL</title>\n <link rel=\"sty"
},
{
"path": "tests/src/utils.js",
"chars": 6280,
"preview": "/**\n * Convenience properties and methods for QUnit testing within two.js\n */\n\n(function () {\n var root = this;\n var Q"
},
{
"path": "tests/suite/bounding-box.js",
"chars": 8135,
"preview": "/**\n * Tests Two.js Utilities related to getBoundingClientRect methods:\n * + polygon._matrix transformations\n * + Two.ge"
},
{
"path": "tests/suite/canvas.js",
"chars": 17546,
"preview": "/**\n * Tests Two.js Canvas Rendering Functionality:\n */\n\n(function () {\n QUnit.module('CanvasRenderer');\n\n var getRati"
},
{
"path": "tests/suite/core.js",
"chars": 33963,
"preview": "/**\n * Tests Two.js Core Classes Functionality:\n * + Two.Utils ( Underscore Methods )\n * + Two.Events\n * + Two.Vector\n *"
},
{
"path": "tests/suite/dispose.js",
"chars": 40288,
"preview": "/**\n * Tests Two.js dispose() Methods:\n * Comprehensive testing of dispose() functionality across the class hierarchy.\n "
},
{
"path": "tests/suite/hit-test.js",
"chars": 2861,
"preview": "QUnit.module('Hit Testing');\n\nQUnit.test('Shape.contains evaluates fill and stroke geometry', function (assert) {\n asse"
},
{
"path": "tests/suite/release.js",
"chars": 11669,
"preview": "/**\n * Tests Two.js release() Method Enhanced Functionality:\n * + Basic release functionality\n * + SVG DOM element clean"
},
{
"path": "tests/suite/shapes.js",
"chars": 27684,
"preview": "QUnit.module('Primitives');\n\nQUnit.test('Two.Points', function (assert) {\n var props = Two.Points.Properties.slice(0, 7"
},
{
"path": "tests/suite/svg-interpreter.js",
"chars": 154906,
"preview": "/**\n * Tests Two.js Utilities related to Svg Interpretation:\n * + two.load()\n * + two.interpret()\n * + polygon.subdivide"
},
{
"path": "tests/suite/svg.js",
"chars": 25033,
"preview": "/**\n * Tests Two.js Svg Rendering Functionality:\n */\n\n(function () {\n QUnit.module('SVGRenderer');\n\n QUnit.test('Two.m"
},
{
"path": "tests/suite/webgl.js",
"chars": 17547,
"preview": "/**\n * Tests Two.js WebGl Rendering Functionality:\n */\n\n(function () {\n QUnit.module('WebGLRenderer');\n\n var getRatio "
},
{
"path": "tests/typescript/index.js",
"chars": 1353,
"preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar two_js_1 = require(\"two.js\");\nvar two ="
},
{
"path": "tests/typescript/index.ts",
"chars": 1050,
"preview": "import Two from 'two.js';\n\nconst two = new Two({\n fullscreen: true,\n autostart: false,\n});\n\nlet path;\n\npath = Two.Circ"
},
{
"path": "tests/typescript/package.json",
"chars": 286,
"preview": "{\n \"name\": \"typescript\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"e"
},
{
"path": "utils/INSTRUCTIONS.md",
"chars": 1177,
"preview": "# TypeScript Types Declaration Build Instructions\n\n1. Remove all @extends commands from `/src` and `/extras`\n2. Run `npm"
},
{
"path": "utils/build.js",
"chars": 3591,
"preview": "const esbuild = require('esbuild');\nconst fs = require('fs');\nconst path = require('path');\nconst _ = require('underscor"
},
{
"path": "utils/docs.template",
"chars": 3784,
"preview": "---\ntitle: <%= root.longname %>\npageClass: docs\nlang: en-US\n---\n\n# <%= root.longname %>\n\n<% if (root.augments) { %>\n<div"
},
{
"path": "utils/document.js",
"chars": 6976,
"preview": "var _ = require('underscore');\nvar fs = require('fs');\nvar path = require('path');\nvar compiler = require('jsdoc-api');\n"
},
{
"path": "utils/file-sizes.json",
"chars": 42,
"preview": "{\"development\":\"94KB\",\"production\":\"50KB\"}"
},
{
"path": "utils/source-files.js",
"chars": 1111,
"preview": "var sourceFiles = [\n 'src/two.js',\n 'src/registry.js',\n 'src/collection.js',\n 'src/children.js',\n 'src/events.js',\n"
},
{
"path": "wiki/.vuepress/components/carbon-ads.vue",
"chars": 2245,
"preview": "<script>\n export default {\n name: 'carbon-ads',\n watch: {\n '$route' (to, from) {\n if (\n to.p"
},
{
"path": "wiki/.vuepress/components/custom-button.vue",
"chars": 2597,
"preview": "<template>\n <a ref=\"link\" class=\"button\" :class=\"type\" :href=\"href\">\n <span ref=\"icon\" class=\"icon\" :class=\"type\"></"
},
{
"path": "wiki/.vuepress/components/example-card.vue",
"chars": 4492,
"preview": "<template>\n <div class=\"example\">\n\n <h2 ref=\"h2\">{{ title }}</h2>\n\n <a class=\"cover\" :href=\"href\" target=\"_blank\""
},
{
"path": "wiki/.vuepress/components/inline-editor.vue",
"chars": 2062,
"preview": "<template>\n <div\n :data-prefill=\"prefill\"\n data-default-tab=\"js,result\"\n data-editable=\"true\"\n data-theme-i"
},
{
"path": "wiki/.vuepress/components/redirect-page.vue",
"chars": 364,
"preview": "<template>\n <div></div>\n</template>\n\n<script>\n module.exports = {\n name: 'redirect-page',\n props: {\n src: S"
},
{
"path": "wiki/.vuepress/components/version-link.vue",
"chars": 373,
"preview": "<template>\n <a class=\"version\" target=\"_blank\" rel=\"noopener noreferrer\" :href=\"'https://github.com/jonobr1/two.js/rele"
},
{
"path": "wiki/.vuepress/config.js",
"chars": 3559,
"preview": "var fs = require('fs');\nvar path = require('path');\n\nvar sourceFiles = require('../../utils/source-files');\nvar fileSize"
},
{
"path": "wiki/.vuepress/enhanceApp.js",
"chars": 160,
"preview": "export default ({ router }) => {\n router.addRoutes([\n { path: '/projects/', redirect: '/examples/' },\n { path: '/"
},
{
"path": "wiki/.vuepress/plugins/search/SearchBox.vue",
"chars": 7592,
"preview": "<template>\n <div class=\"search-box\">\n <input\n ref=\"input\"\n aria-label=\"Search\"\n :value=\"query\"\n "
},
{
"path": "wiki/.vuepress/plugins/search/match-query.js",
"chars": 1464,
"preview": "import get from 'lodash/get';\n\nexport default (query, page, additionalStr = null) => {\n let domain = get(page, 'title',"
},
{
"path": "wiki/.vuepress/styles/index.styl",
"chars": 11618,
"preview": "body {\n font-family: $fontFamily;\n font-size: 1rem;\n line-height: 1.5rem;\n // word-spacing: 0.1875rem;\n color: $tex"
},
{
"path": "wiki/.vuepress/styles/palette.styl",
"chars": 820,
"preview": "$black = #333;\n$grey = #eee;\n$gray = $grey;\n$white = #fff;\n\n$red = rgb(255, 64, 64);\n$orange = rgb(255, 128, 0);\n$blue ="
},
{
"path": "wiki/.vuepress/theme/components/Navbar.vue",
"chars": 6149,
"preview": "<template>\n <header class=\"navbar\" ref=\"header\" :class=\"{ 'has-sidebar': hasSidebar }\">\n <SidebarButton @toggle-side"
},
{
"path": "wiki/.vuepress/theme/components/Sidebar.vue",
"chars": 2676,
"preview": "<template>\n <aside class=\"sidebar\">\n\n <RouterLink\n :to=\"$localePath\"\n class=\"home-link\"\n >\n <img\n "
},
{
"path": "wiki/.vuepress/theme/index.js",
"chars": 331,
"preview": "module.exports = function() {\n return {\n extend: '@vuepress/theme-default',\n plugins: {\n '@vuepress/search':"
},
{
"path": "wiki/.vuepress/theme/layouts/NotFound.vue",
"chars": 529,
"preview": "<template>\n <div class=\"theme-container\">\n <div class=\"theme-default-content\">\n <h1>404</h1>\n\n <blockquote"
},
{
"path": "wiki/README.md",
"chars": 9844,
"preview": "---\ntitle: Two.js • Homepage\nlang: en-US\n---\n\n# Two.js\n\nA two-dimensional drawing api geared towards modern web browsers"
},
{
"path": "wiki/change-log/README.md",
"chars": 50,
"preview": "<redirect-page src=\"/changelog/\"></redirect-page>\n"
},
{
"path": "wiki/changelog/README.md",
"chars": 31547,
"preview": "---\npageClass: change-log\nsidebarDepth: 3\ntitle: Two.js Changelog\nlang: en-US\n---\n\n# Changelog\n\nAll notable changes to t"
},
{
"path": "wiki/docs/README.md",
"chars": 49,
"preview": "<redirect-page src=\"/docs/two/\"></redirect-page>\n"
},
{
"path": "wiki/docs/anchor/README.md",
"chars": 4847,
"preview": "---\ntitle: Two.Anchor\npageClass: docs\nlang: en-US\n---\n\n# Two.Anchor\n\n\n<div class=\"extends\">\n\nExtends: [Two.Vector](/docs"
},
{
"path": "wiki/docs/children/README.md",
"chars": 2249,
"preview": "---\ntitle: Two.Group.Children\npageClass: docs\nlang: en-US\n---\n\n# Two.Group.Children\n\n\n<div class=\"extends\">\n\nExtends: [T"
},
{
"path": "wiki/docs/collection/README.md",
"chars": 572,
"preview": "---\ntitle: Two.Collection\npageClass: docs\nlang: en-US\n---\n\n# Two.Collection\n\n\n<div class=\"extends\">\n\nExtends: [Two.Event"
},
{
"path": "wiki/docs/effects/gradient/README.md",
"chars": 7465,
"preview": "---\ntitle: Two.Gradient\npageClass: docs\nlang: en-US\n---\n\n# Two.Gradient\n\n\n<div class=\"extends\">\n\nExtends: [Two.Element]("
},
{
"path": "wiki/docs/effects/image/README.md",
"chars": 6704,
"preview": "---\ntitle: Two.Image\npageClass: docs\nlang: en-US\n---\n\n# Two.Image\n\n\n<div class=\"extends\">\n\nExtends: [Two.Rectangle](/doc"
},
{
"path": "wiki/docs/effects/image-sequence/README.md",
"chars": 9874,
"preview": "---\ntitle: Two.ImageSequence\npageClass: docs\nlang: en-US\n---\n\n# Two.ImageSequence\n\n\n<div class=\"extends\">\n\nExtends: [Two"
},
{
"path": "wiki/docs/effects/linear-gradient/README.md",
"chars": 5580,
"preview": "---\ntitle: Two.LinearGradient\npageClass: docs\nlang: en-US\n---\n\n# Two.LinearGradient\n\n\n<div class=\"extends\">\n\nExtends: [T"
},
{
"path": "wiki/docs/effects/radial-gradient/README.md",
"chars": 6300,
"preview": "---\ntitle: Two.RadialGradient\npageClass: docs\nlang: en-US\n---\n\n# Two.RadialGradient\n\n\n<div class=\"extends\">\n\nExtends: [T"
},
{
"path": "wiki/docs/effects/sprite/README.md",
"chars": 10055,
"preview": "---\ntitle: Two.Sprite\npageClass: docs\nlang: en-US\n---\n\n# Two.Sprite\n\n\n<div class=\"extends\">\n\nExtends: [Two.Rectangle](/d"
},
{
"path": "wiki/docs/effects/stop/README.md",
"chars": 6335,
"preview": "---\ntitle: Two.Stop\npageClass: docs\nlang: en-US\n---\n\n# Two.Stop\n\n\n<div class=\"extends\">\n\nExtends: [Two.Element](/docs/el"
},
{
"path": "wiki/docs/effects/texture/README.md",
"chars": 15070,
"preview": "---\ntitle: Two.Texture\npageClass: docs\nlang: en-US\n---\n\n# Two.Texture\n\n\n<div class=\"extends\">\n\nExtends: [Two.Element](/d"
},
{
"path": "wiki/docs/element/README.md",
"chars": 5033,
"preview": "---\ntitle: Two.Element\npageClass: docs\nlang: en-US\n---\n\n# Two.Element\n\n\n<div class=\"extends\">\n\nExtends: [Two.Events](/do"
},
{
"path": "wiki/docs/events/README.md",
"chars": 5338,
"preview": "---\ntitle: Two.Events\npageClass: docs\nlang: en-US\n---\n\n# Two.Events\n\n\n\nObject inherited by many Two.js objects in order "
},
{
"path": "wiki/docs/extras/arc/README.md",
"chars": 3960,
"preview": "---\ntitle: Two.Arc\npageClass: docs\nlang: en-US\n---\n\n# Two.Arc\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs/path/)\n"
},
{
"path": "wiki/docs/extras/zui/README.md",
"chars": 7835,
"preview": "---\ntitle: Two.ZUI\npageClass: docs\nlang: en-US\n---\n\n# Two.ZUI\n\n\n\n[Two.ZUI](/docs/two/#zui) is an extra class to turn you"
},
{
"path": "wiki/docs/group/README.md",
"chars": 26765,
"preview": "---\ntitle: Two.Group\npageClass: docs\nlang: en-US\n---\n\n# Two.Group\n\n\n<div class=\"extends\">\n\nExtends: [Two.Shape](/docs/sh"
},
{
"path": "wiki/docs/matrix/README.md",
"chars": 18547,
"preview": "---\ntitle: Two.Matrix\npageClass: docs\nlang: en-US\n---\n\n# Two.Matrix\n\n\n\nA class to store 3 x 3 transformation matrix info"
},
{
"path": "wiki/docs/path/README.md",
"chars": 26357,
"preview": "---\ntitle: Two.Path\npageClass: docs\nlang: en-US\n---\n\n# Two.Path\n\n\n<div class=\"extends\">\n\nExtends: [Two.Shape](/docs/shap"
},
{
"path": "wiki/docs/registry/README.md",
"chars": 3028,
"preview": "---\ntitle: Two.Registry\npageClass: docs\nlang: en-US\n---\n\n# Two.Registry\n\n\n\nAn arbitrary class to manage a directory of t"
},
{
"path": "wiki/docs/renderers/canvas/README.md",
"chars": 5088,
"preview": "---\ntitle: Two.CanvasRenderer\npageClass: docs\nlang: en-US\n---\n\n# Two.CanvasRenderer\n\n\n<div class=\"extends\">\n\nExtends: [T"
},
{
"path": "wiki/docs/renderers/svg/README.md",
"chars": 4045,
"preview": "---\ntitle: Two.SVGRenderer\npageClass: docs\nlang: en-US\n---\n\n# Two.SVGRenderer\n\n\n<div class=\"extends\">\n\nExtends: [Two.Eve"
},
{
"path": "wiki/docs/renderers/webgl/README.md",
"chars": 6066,
"preview": "---\ntitle: Two.WebGLRenderer\npageClass: docs\nlang: en-US\n---\n\n# Two.WebGLRenderer\n\n\n<div class=\"extends\">\n\nExtends: [Two"
},
{
"path": "wiki/docs/shape/README.md",
"chars": 11681,
"preview": "---\ntitle: Two.Shape\npageClass: docs\nlang: en-US\n---\n\n# Two.Shape\n\n\n<div class=\"extends\">\n\nExtends: [Two.Element](/docs/"
},
{
"path": "wiki/docs/shapes/arc-segment/README.md",
"chars": 6516,
"preview": "---\ntitle: Two.ArcSegment\npageClass: docs\nlang: en-US\n---\n\n# Two.ArcSegment\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path]"
},
{
"path": "wiki/docs/shapes/circle/README.md",
"chars": 4519,
"preview": "---\ntitle: Two.Circle\npageClass: docs\nlang: en-US\n---\n\n# Two.Circle\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs/p"
},
{
"path": "wiki/docs/shapes/ellipse/README.md",
"chars": 5106,
"preview": "---\ntitle: Two.Ellipse\npageClass: docs\nlang: en-US\n---\n\n# Two.Ellipse\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs"
},
{
"path": "wiki/docs/shapes/line/README.md",
"chars": 606,
"preview": "---\ntitle: Two.Line\npageClass: docs\nlang: en-US\n---\n\n# Two.Line\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs/path/"
},
{
"path": "wiki/docs/shapes/points/README.md",
"chars": 19079,
"preview": "---\ntitle: Two.Points\npageClass: docs\nlang: en-US\n---\n\n# Two.Points\n\n\n<div class=\"extends\">\n\nExtends: [Two.Shape](/docs/"
},
{
"path": "wiki/docs/shapes/polygon/README.md",
"chars": 6801,
"preview": "---\ntitle: Two.Polygon\npageClass: docs\nlang: en-US\n---\n\n# Two.Polygon\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs"
},
{
"path": "wiki/docs/shapes/rectangle/README.md",
"chars": 5671,
"preview": "---\ntitle: Two.Rectangle\npageClass: docs\nlang: en-US\n---\n\n# Two.Rectangle\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/"
},
{
"path": "wiki/docs/shapes/rounded-rectangle/README.md",
"chars": 6146,
"preview": "---\ntitle: Two.RoundedRectangle\npageClass: docs\nlang: en-US\n---\n\n# Two.RoundedRectangle\n\n\n<div class=\"extends\">\n\nExtends"
},
{
"path": "wiki/docs/shapes/star/README.md",
"chars": 5487,
"preview": "---\ntitle: Two.Star\npageClass: docs\nlang: en-US\n---\n\n# Two.Star\n\n\n<div class=\"extends\">\n\nExtends: [Two.Path](/docs/path/"
},
{
"path": "wiki/docs/text/README.md",
"chars": 20880,
"preview": "---\ntitle: Two.Text\npageClass: docs\nlang: en-US\n---\n\n# Two.Text\n\n\n<div class=\"extends\">\n\nExtends: [Two.Shape](/docs/shap"
}
]
// ... and 7 more files (download for full content)
About this extraction
This page contains the full source code of the jonobr1/two.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 207 files (2.6 MB), approximately 700.8k tokens, and a symbol index with 1558 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.