# 🖋️ ngx-scribbly

`ngx-scribbly` is an Angular directive that allows users to **draw resizable, absolutely positioned components or templates** inside any container, with full support for aspect ratio locking, dynamic component rendering, and bounding detection.

Perfect for apps like image annotation tools, design systems, or content creation overlays.

---

## 📦 Installation

```bash
npm i @vi5hnuu/ngx-scribbly
```

---

## 🚀 Features

* Draw Angular components or templates dynamically
* Emits `ScribbleConfig` with exact placement and size
* Maintains aspect ratio (optional)
* Blocks drawing outside host element bounds
* Supports both `ComponentType` and `TemplateRef`
* Reactive `isDrawing` output for external tools

---

## 🔧 Usage

### 1. **Import `ScribbleDirective`**

```ts
import {ScribbleDirective,ScribbleConfig} from '@vi5hnuu/ngx-scribbly'

@Component({
  selector: "app-root",
  standalone: true,
  imports: [ScribbleDirective],
  templateUrl: "./app.component.html",
  styleUrl: "./app.component.css",
})
export class AppComponent {
  title = "scribble-app"
}

```

---

### 2. **Apply `scribble` directive to any container**

```html
<div scribble
     [active]="allowShapeDraw"
     [miniSize]="{width:50,height:50}"
     (rendered)="onRender($event)"
     (isDrawing)="isDrawing($event)"
     [selectedMapping]="'star'"
     [maintainAspect]="returnNumberOrBooleanFn"
     [typeMapping]="{'star':StarTemplate}">
</div>

<ng-template #StarTemplate>
  <div class="shape">
    <img class="image" src="star.png" alt="shape"/>
  </div>
</ng-template>
```

---

### 3. **Inputs and Outputs**

#### 🏷️ Inputs

| Input             | Type                                                                | Description                                              |
| ----------------- | ------------------------------------------------------------------- | -------------------------------------------------------- |
| `typeMapping`     | TypeMappings         | Map of available drawing elements                        |
| `selectedMapping` | `string \| null`                                                    | Key to use from `typeMapping`                            |
| `maintainAspect`  | `(event: MouseEvent) => { maintainAspectRatio: boolean \| number }` | Lock aspect ratio. Use a number for fixed (e.g., `16/9`) |

```ts
export interface TypeMappings { [key:string]:TypeMapping}

export interface TypeMapping{type:ComponentType<any>|TemplateRef<any>,args?:{[key:string]:any}}
```

#### 📤 Outputs

| Output      | Type                           | Description                       |
| ----------- | ------------------------------ | --------------------------------- |
| `rendered`  | `EventEmitter<ScribbleConfig>` | Emits when an element is rendered |
| `isDrawing` | `EventEmitter<boolean>`        | Emits drawing state               |

---

### 4. **ScribbleConfig**

```ts
export interface ScribbleConfig {
  info: {
    left: number;
    top: number;
    width: number;
    height: number;
  }; // Relative to host
  createdEl: HTMLElement;  // Rendered element
  mapping: string;         // Mapping key used
  event: Readonly<MouseEvent>; // Final mouseup event
}
```

---

## 🧠 Example

```ts
@Component({...})
export class EditorComponent {
  selectedMapping = 'textBox';

  typeMapping = {
    textBox: TextComponent,
    shapeBox: this.tpl,
  };

  @ViewChild('shapeTpl', { read: TemplateRef }) tpl!: TemplateRef<any>;

  aspectFn = (event: MouseEvent) => ({ maintainAspectRatio: true });

  onRendered(config: ScribbleConfig) {
    console.log('Drawn:', config);
  }

  onIsDrawing(is: boolean) {
    console.log('Drawing mode:', is);
  }
}
```

```html
<ng-template #shapeTpl>
  <div style="border: 2px dashed red; background: rgba(0,0,0,0.1);"></div>
</ng-template>
```

---

## 📏 Behavior Notes

* Drawing is allowed **only within host boundaries**
* Aspect ratio locks width and adjust height to maintain aspect
* Resets rendering if mapping changes mid-draw [abort drawing]
* Multiple root nodes in `TemplateRef` are not allowed

---

## 🧹 Cleanup

Directive automatically unsubscribes from observables on destroy.

---

## ✅ License

MIT License. Created by [Vishnu kumar](https://github.com/vi5hnuu).

---

## 🔗 Connect with Me
Feel free to connect with me on social media:
* [Portfolio](http://dev-vishnu.laxmi.solutions/)
* [GitHub](https://github.com/vi5hnuu)
* [LinkedIn](https://www.linkedin.com/in/vi5hnukumar/)
* [PlayStore](https://play.google.com/store/apps/dev?id=7222030998756299864)

---
