Search results

Integration with Toolbar in React Signature component

18 May 2022 / 5 minutes to read

The Signature component integrates with the toolbar and the interaction performed using the change event of the toolbar. In that, canUndo, canRedo and isEmpty methods were used to enable/disable undo, redo, and clear buttons.

Source
Preview
index.jsx
index.html
index.tsx
Copied to clipboard
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { ColorPickerComponent } from '@syncfusion/ej2-react-inputs';
import { SignatureComponent } from '@syncfusion/ej2-react-inputs';
import { getComponent, createElement, addClass } from '@syncfusion/ej2-base';
import { ItemDirective, ItemsDirective, ToolbarComponent } from '@syncfusion/ej2-react-navigations';
import { CheckBox } from '@syncfusion/ej2-buttons';
import { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
class App extends React.Component {
    constructor(props) {
        super(props);
        this.disabledTemplate = new CheckBox({ label: 'Disabled', checked: false, change: this.change });
    }
    change(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        signature.disabled = args.checked;
    }
    onCreated() {
        let strokeColor = getComponent(document.getElementById('stroke-color'), 'colorpicker');
        let bgColor = getComponent(document.getElementById('bg-color'), 'colorpicker');
        addClass([strokeColor.element.nextElementSibling.querySelector('.e-selected-color')], 'e-sign-icons');
        addClass([bgColor.element.nextElementSibling.querySelector('.e-selected-color')], 'e-sign-icons');
        document.getElementById('save-option').addEventListener('click', this.saveBtnClick);
        this.clearButton();
        let toolbarlItems = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
        for (var i = 0; i < toolbarlItems.length; i++) {
            if (toolbarlItems[i].children[0].classList.contains('e-undo')) {
                let undoButton = getComponent(toolbarlItems[i], 'btn');
                undoButton.disabled = true;
            }
            if (toolbarlItems[i].children[0].classList.contains('e-redo')) {
                let redoButton = getComponent(toolbarlItems[i], 'btn');
                redoButton.disabled = true;
            }
        }
    }
    onClicked(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let saveBtn = getComponent(document.getElementById("save-option"), 'split-btn');
        if (signature.disabled && args.item.tooltipText != 'Disabled') {
            return;
        }
        switch (args.item.tooltipText) {
            case 'Undo (Ctrl + Z)':
                if (signature.canUndo()) {
                    signature.undo();
                    this.updateUndoRedo();
                    this.updateSaveBtn();
                }
                break;
            case 'Redo (Ctrl + Y)':
                if (signature.canRedo()) {
                    signature.redo();
                    this.updateUndoRedo();
                    this.updateSaveBtn();
                }
                break;
            case 'Clear':
                signature.clear();
                if (signature.isEmpty()) {
                    this.clearButton();
                    saveBtn.disabled = true;
                }
                break;
        }
    }
    onChange() {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let saveBtn = getComponent(document.getElementById("save-option"), 'split-btn');
        if (!signature.isEmpty()) {
            this.clearButton();
            saveBtn.disabled = false;
        }
        this.updateUndoRedo();
    }
    saveBtnClick() {
        let signature = getComponent(document.getElementById("signature"), 'signature');
        signature.save();
    }
    clearButton() {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let tlItems = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
        for (var i = 0; i < tlItems.length; i++) {
            if (tlItems[i].children[0].classList.contains('e-clear')) {
                let clrBtn = getComponent(tlItems[i], 'btn');
                if (signature.isEmpty()) {
                    clrBtn.disabled = true;
                }
                else {
                    clrBtn.disabled = false;
                }
            }
        }
    }
    updateSaveBtn() {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let saveBtn = getComponent(document.getElementById("save-option"), 'split-btn');
        if (signature.isEmpty()) {
            saveBtn.disabled = true;
        }
        else {
            saveBtn.disabled = false;
        }
    }
    updateUndoRedo() {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let undoButton;
        let redoButton;
        let tlItems = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
        for (var i = 0; i < tlItems.length; i++) {
            if (tlItems[i].children[0].classList.contains('e-undo')) {
                undoButton = getComponent(tlItems[i], 'btn');
            }
            if (tlItems[i].children[0].classList.contains('e-redo')) {
                redoButton = getComponent(tlItems[i], 'btn');
            }
        }
        if (signature.canUndo()) {
            undoButton.disabled = false;
        }
        else {
            undoButton.disabled = true;
        }
        if (signature.canRedo()) {
            redoButton.disabled = false;
        }
        else {
            redoButton.disabled = true;
        }
    }
    saveTemplate(props) {
        return (<SaveTemplate {...props}/>);
    }
    strokeColorTemplate(props) {
        return (<StrokeColorTemplate {...props}/>);
    }
    bgColorTemplate(props) {
        return (<BgColorTemplate {...props}/>);
    }
    strokeWidthTemplate(props) {
        return (<StrokeWidthTemplate {...props}/>);
    }
    render() {
        return (<div id="signature-toolbar-control">
              <ToolbarComponent id='toolbar' created={this.onCreated.bind(this)} clicked={this.onClicked.bind(this)}>
                <ItemsDirective>
                  <ItemDirective text='Undo' prefixIcon='e-icons e-undo' tooltipText='Undo (Ctrl + Z)'/>
                  <ItemDirective text='Redo' prefixIcon='e-icons e-redo' tooltipText='Redo (Ctrl + Y)'/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText='Save (Ctrl + S)' type='Button' template={this.saveTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText='Stroke Color' template={this.strokeColorTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText='Background Color' template={this.bgColorTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText='Stroke Width' template={this.strokeWidthTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective text='Clear' prefixIcon='e-sign-icons e-clear' tooltipText='Clear'/>
                  <ItemDirective tooltipText='Disabled' type='Input' template={this.disabledTemplate} align='Right'/>
                </ItemsDirective>
              </ToolbarComponent>
              <div id="signature-control">
                <SignatureComponent maxStrokeWidth={2} id="signature" change={this.onChange.bind(this)}></SignatureComponent>
              </div>
          </div>);
    }
}
export class SaveTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.items = [
            {
                text: 'Png'
            },
            {
                text: 'Jpeg'
            },
            {
                text: 'Svg'
            }
        ];
    }
    onSelect(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        signature.save(args.item.text, 'Signature');
    }
    render() {
        return (<div>
        <SplitButtonComponent content="Save" id="save-option" items={this.items} iconCss='e-sign-icons e-save' select={this.onSelect.bind(this)} disabled={true}/>
      </div>);
    }
}
export class StrokeColorTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.presets = {
            'custom': ['#000000', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4',
                '#009688', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107']
        };
    }
    tileRender(args) {
        args.element.classList.add('e-circle-palette');
        args.element.appendChild(createElement('span', { className: 'e-circle-selection' }));
    }
    strokeColorChanged(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let strokeColor = getComponent(document.getElementById('stroke-color'), 'colorpicker');
        if (signature.disabled) {
            return;
        }
        let selElem = strokeColor.element.nextElementSibling.querySelector('.e-selected-color');
        selElem.style.borderBottomColor = args.currentValue.rgba;
        signature.strokeColor = args.currentValue.rgba;
    }
    render() {
        return (<div>
        <ColorPickerComponent id="stroke-color" mode='Palette' cssClass='e-stroke-color' modeSwitcher={false} showButtons={false} columns={4} presetColors={this.presets} beforeTileRender={this.tileRender.bind(this)} change={this.strokeColorChanged.bind(this)}></ColorPickerComponent>
      </div>);
    }
}
export class BgColorTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.presets = {
            'custom': ['#ffffff', '#f44336', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4',
                '#009688', '#8bc34a', '#cddc39', '#ffeb3b']
        };
    }
    beforeTileRender(args) {
        args.element.classList.add('e-circle-palette');
        args.element.appendChild(createElement('span', { className: 'e-circle-selection' }));
    }
    bgColorChanged(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        let bgColor = getComponent(document.getElementById('bg-color'), 'colorpicker');
        if (signature.disabled) {
            return;
        }
        let selElem = bgColor.element.nextElementSibling.querySelector('.e-selected-color');
        signature.backgroundColor = args.currentValue.rgba;
        selElem.style.borderBottomColor = args.currentValue.rgba;
    }
    render() {
        return (<div>
        <ColorPickerComponent id="bg-color" noColor={true} mode='Palette' cssClass='e-bg-color' modeSwitcher={false} showButtons={false} columns={4} presetColors={this.presets} beforeTileRender={this.beforeTileRender.bind(this)} change={this.bgColorChanged.bind(this)}></ColorPickerComponent>
      </div>);
    }
}
export class StrokeWidthTemplate extends React.Component {
    constructor(props) {
        super(props);
        this.data = [1, 2, 3, 4, 5];
        this.value = 2;
    }
    strokeWidthChanged(args) {
        let signature = getComponent(document.getElementById('signature'), 'signature');
        signature.maxStrokeWidth = args.value;
    }
    render() {
        const args = this.state;
        return (<div>
        <DropDownListComponent id="ddlelement" dataSource={this.data} value={this.value} width="60" change={this.strokeWidthChanged.bind(this)}/>
      </div>);
    }
}
;
ReactDOM.render(<App />, document.getElementById('element'));
Copied to clipboard
<!DOCTYPE html>
<html lang="en">

<head>
    <title>EJ2 React Signature</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="React Signature Component" />
    <meta name="author" content="Syncfusion" />
    <link href="styles.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/20.1.55/ej2-popups/styles/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
Copied to clipboard
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { ColorPicker, ColorPickerComponent, ColorPickerEventArgs, PaletteTileEventArgs } from '@syncfusion/ej2-react-inputs';
import { SignatureFileType, Signature, SignatureComponent } from '@syncfusion/ej2-react-inputs';
import { Button} from '@syncfusion/ej2-react-buttons';
import { getComponent, createElement, addClass } from '@syncfusion/ej2-base';
import { ClickEventArgs, ItemDirective, ItemsDirective, ToolbarComponent } from '@syncfusion/ej2-react-navigations';
import { ChangeEventArgs, CheckBox } from '@syncfusion/ej2-buttons';
import { MenuEventArgs, SplitButton, SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';

class App extends React.Component<{}, {}> {
    public signature: SignatureComponent;
    public disabledTemplate: CheckBox;

  constructor(props) {
    super(props);
    this.disabledTemplate = new CheckBox({ label: 'Disabled', checked: false , change: this.change});
  }

  change(args: ChangeEventArgs): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    signature.disabled = args.checked;
  }

  onCreated(): void {
    let strokeColor: ColorPicker = getComponent(document.getElementById('stroke-color'), 'colorpicker');
    let bgColor: ColorPicker = getComponent(document.getElementById('bg-color'), 'colorpicker');
    addClass([strokeColor.element.nextElementSibling.querySelector('.e-selected-color')], 'e-sign-icons');
    addClass([bgColor.element.nextElementSibling.querySelector('.e-selected-color')], 'e-sign-icons');
    document.getElementById('save-option').addEventListener('click', this.saveBtnClick);
    this.clearButton();
    let toolbarlItems: NodeListOf<Element> = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
    for (var i = 0; i < toolbarlItems.length; i++) {
      if (toolbarlItems[i].children[0].classList.contains('e-undo')) {
        let undoButton: Button = getComponent(toolbarlItems[i] as HTMLElement, 'btn');
        undoButton.disabled = true;
      }
      if (toolbarlItems[i].children[0].classList.contains('e-redo')) {
        let redoButton: Button = getComponent(toolbarlItems[i] as HTMLElement, 'btn');
        redoButton.disabled = true;
      }
    }
  }

  onClicked(args: ClickEventArgs): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let saveBtn: SplitButton = getComponent(document.getElementById("save-option"), 'split-btn');
    if (signature.disabled && args.item.tooltipText != 'Disabled') {
      return;
    }
    switch (args.item.tooltipText) {
      case 'Undo (Ctrl + Z)':
        if (signature.canUndo()) {
          signature.undo();
          this.updateUndoRedo();
          this.updateSaveBtn();
      }
        break;
      case 'Redo (Ctrl + Y)':
        if (signature.canRedo()) {
          signature.redo();
          this.updateUndoRedo();
          this.updateSaveBtn();
        }
        break;
      case 'Clear':
        signature.clear();
        if (signature.isEmpty()) {
          this.clearButton();
          saveBtn.disabled = true;
        }
        break;
    }
  }

  onChange() {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let saveBtn: SplitButton = getComponent(document.getElementById("save-option"), 'split-btn');
    if (!signature.isEmpty()) {
      this.clearButton();
      saveBtn.disabled = false;
    }
    this.updateUndoRedo();
  }

  saveBtnClick(): void {
    let signature: Signature = getComponent(document.getElementById("signature"), 'signature');
    signature.save();
  }

  clearButton() {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let tlItems: NodeListOf<Element> = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
    for (var i = 0; i < tlItems.length; i++) {
      if (tlItems[i].children[0].classList.contains('e-clear')) {
        let clrBtn: Button = getComponent(tlItems[i] as HTMLElement, 'btn');
        if (signature.isEmpty()) {
          clrBtn.disabled = true;
        } else {
          clrBtn.disabled = false;
        }
      }
    }
  }

  updateSaveBtn() {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let saveBtn: SplitButton = getComponent(document.getElementById("save-option"), 'split-btn');
    if (signature.isEmpty()) {
        saveBtn.disabled = true;
    } else {
      saveBtn.disabled = false;
    }
  }

  updateUndoRedo() {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let undoButton: Button; let redoButton: Button
    let tlItems: NodeListOf<Element> = document.querySelectorAll('.e-toolbar .e-toolbar-items .e-toolbar-item .e-tbar-btn.e-tbtn-txt');
    for (var i = 0; i < tlItems.length; i++) {
      if (tlItems[i].children[0].classList.contains('e-undo')) {
        undoButton = getComponent(tlItems[i] as HTMLElement, 'btn');
      }
      if (tlItems[i].children[0].classList.contains('e-redo')) {
        redoButton = getComponent(tlItems[i] as HTMLElement, 'btn');
      }
    }
    if (signature.canUndo()) {
      undoButton.disabled = false;
    } else {
      undoButton.disabled = true;
    }
    if (signature.canRedo()) {
      redoButton.disabled = false;
    } else {
      redoButton.disabled = true;
    }
  }

  saveTemplate(props) {
    return (<SaveTemplate {...props}/>);
  }

  strokeColorTemplate(props) {
    return (<StrokeColorTemplate {...props}/>);
  }
  bgColorTemplate(props) {
    return (<BgColorTemplate {...props}/>);
  }
  strokeWidthTemplate(props) {
    return (<StrokeWidthTemplate {...props}/>);
  }

  render() {
    return (
            <div id="signature-toolbar-control">
              <ToolbarComponent id='toolbar' created={this.onCreated.bind(this)} clicked={this.onClicked.bind(this)}>
                <ItemsDirective>
                  <ItemDirective text='Undo' prefixIcon='e-icons e-undo' tooltipText='Undo (Ctrl + Z)'/>
                  <ItemDirective text='Redo' prefixIcon='e-icons e-redo' tooltipText='Redo (Ctrl + Y)'/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText= 'Save (Ctrl + S)' type='Button' template= {this.saveTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText= 'Stroke Color' template= {this.strokeColorTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText= 'Background Color' template= {this.bgColorTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective tooltipText= 'Stroke Width' template= {this.strokeWidthTemplate}/>
                  <ItemDirective type='Separator'/>
                  <ItemDirective text= 'Clear' prefixIcon= 'e-sign-icons e-clear' tooltipText= 'Clear'/>
                  <ItemDirective tooltipText= 'Disabled' type='Input' template= {this.disabledTemplate} align='Right'/>
                </ItemsDirective>
              </ToolbarComponent>
              <div id="signature-control">
                <SignatureComponent maxStrokeWidth= {2} id="signature" change={this.onChange.bind(this)}></SignatureComponent>
              </div>
          </div>
    )
  }
}


export class SaveTemplate extends React.Component {
  public items: { text: string; }[];
  constructor(props) {
      super(props);
      this.items = [
        {
            text: 'Png'
        },
        {
            text: 'Jpeg'
        },
        {
            text: 'Svg'
        }
      ];
  }
  onSelect(args:MenuEventArgs ): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    signature.save(args.item.text as SignatureFileType, 'Signature');
  }

  render() {
      return (<div >
        <SplitButtonComponent content="Save" id="save-option" items={this.items} iconCss='e-sign-icons e-save' select={this.onSelect.bind(this)} disabled={true}/>
      </div>);
  }
}

export class StrokeColorTemplate extends React.Component {
  public presets: any;
  constructor(props) {
      super(props);
      this.presets = {
        'custom': ['#000000', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4',
        '#009688', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107']
      };  
  }
  
  tileRender(args: PaletteTileEventArgs): void {
    args.element.classList.add('e-circle-palette');
    args.element.appendChild(createElement('span', { className: 'e-circle-selection' }));
  }

  strokeColorChanged(args: ColorPickerEventArgs): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let strokeColor: ColorPicker = getComponent(document.getElementById('stroke-color'), 'colorpicker');
    if (signature.disabled) {
      return;
    }
    let selElem: HTMLElement = strokeColor.element.nextElementSibling.querySelector('.e-selected-color') as HTMLElement;
    selElem.style.borderBottomColor = args.currentValue.rgba;
    signature.strokeColor = args.currentValue.rgba;
  }

  render() {
      return (<div >
        <ColorPickerComponent id="stroke-color" mode='Palette' cssClass= 'e-stroke-color' modeSwitcher={false} showButtons={false} columns={4} presetColors={this.presets} beforeTileRender={this.tileRender.bind(this)} change={this.strokeColorChanged.bind(this)}></ColorPickerComponent>
      </div>);
  }
}

export class BgColorTemplate extends React.Component {
  public presets: any;
  constructor(props) {
      super(props);
      this.presets = {
        'custom': ['#ffffff', '#f44336', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4',
        '#009688', '#8bc34a', '#cddc39', '#ffeb3b']
      };  
  }
  
  beforeTileRender(args: PaletteTileEventArgs): void {
    args.element.classList.add('e-circle-palette');
    args.element.appendChild(createElement('span', { className: 'e-circle-selection' }));

  }

  bgColorChanged(args: ColorPickerEventArgs ): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    let bgColor: ColorPicker = getComponent(document.getElementById('bg-color'), 'colorpicker');
    if (signature.disabled) {
      return;
    }
    let selElem: HTMLElement = bgColor.element.nextElementSibling.querySelector('.e-selected-color') as HTMLElement;
    signature.backgroundColor = args.currentValue.rgba;
    selElem.style.borderBottomColor = args.currentValue.rgba;
  }

  render() {
      return (<div >
        <ColorPickerComponent id="bg-color" noColor={true} mode='Palette' cssClass= 'e-bg-color' modeSwitcher={false} showButtons={false} columns={4} presetColors={this.presets} beforeTileRender={this.beforeTileRender.bind(this)} change={this.bgColorChanged.bind(this)}></ColorPickerComponent>
      </div>);
  }
}

export class StrokeWidthTemplate extends React.Component {
  private data: any = [1, 2, 3, 4, 5];
  private value: any = 2;
  constructor(props) {
      super(props);
  }

  strokeWidthChanged(args: any): void {
    let signature: Signature = getComponent(document.getElementById('signature'), 'signature');
    signature.maxStrokeWidth = args.value;
  }

  render() {
      const args: any = this.state;
      return (<div >
        <DropDownListComponent id="ddlelement" dataSource={this.data} value={this.value} width="60" change={this.strokeWidthChanged.bind(this)} />
      </div>);
  }
};
ReactDOM.render(<App />, document.getElementById('element'));