diff --git a/fabricjs/fabricjs.d.ts b/fabricjs/fabricjs.d.ts
new file mode 100644
index 0000000000..30b9606c1e
--- /dev/null
+++ b/fabricjs/fabricjs.d.ts
@@ -0,0 +1,825 @@
+// Type definitions for FabricJS
+// Project: http://fabricjs.com/
+// Definitions by: Oliver Klemencic
+
+/*
+USAGE
+///
+*/
+
+declare module fabric {
+
+ function createCanvasForNode(width: number, height: number): ICanvas;
+ function getCSSRules(doc: SVGDocument);
+ function getGradientDefs(doc: SVGDocument);
+ function loadSVGFromString(text: string, callback: (results: IObject[], options) => void , reviver?: (el, obj) => void );
+ function loadSVGFromURL(url, callback: (results: IObject[], options) => void , reviver?: (el, obj) => void );
+ function log(values);
+ function parseAttributes(element, attributes: any[]): any;
+ function parseElements(elements: any[], callback, options, reviver);
+ function parsePointsAttribute(points: string): any[];
+ function parseStyleAttribute(element: SVGElement);
+ function parseSVGDocument(doc: SVGDocument, callback: (results, options) => void , reviver?: (el, obj) => void );
+ function parseTransformAttribute(attributeValue: string);
+ function warn(values);
+
+ var isLikelyNode: bool;
+ var isTouchSupported: bool;
+
+ export interface IObservable {
+ observe(eventCollection: IEventList);
+ on(eventCollection: IEventList);
+
+ observe(eventName: string, handler: (e) => any);
+ on(eventName: string, handler: (e) => any);
+
+ fire(eventName: string, options);
+ stopObserving(eventName: string, handler: (e) => any);
+
+ off(eventName, handler);
+ }
+
+ export interface IFilter {
+ new (): IFilter;
+ new (options: any): IFilter;
+ }
+
+ export interface IEventList {
+ [index: string]: (e: Event) => void;
+ }
+
+ export interface IObjectOptions {
+ angle?: number;
+ borderColor?: string;
+ borderOpacityWhenMoving?: number;
+ borderScaleFactor?: number;
+ cornerColor?: string;
+ cornersize?: number;
+ fill?: string;
+ fillRule?: string;
+ flipX?: bool;
+ flipY?: bool;
+ hasBorders?: bool;
+ hasControls?: bool;
+ hasRotatingPoint?: bool;
+ height?: number;
+ includeDefaultValues?: bool;
+ left?: number;
+ lockMovementX?: bool;
+ lockMovementY?: bool;
+ lockScalingX?: bool;
+ lockScalingY?: bool;
+ lockUniScaling?: bool;
+ lockRotation?: bool;
+ opacity?: number;
+ overlayFill?: string;
+ padding?: number;
+ perPixelTargetFind?: bool;
+ rotatingPointOffset?: number;
+ scaleX?: number;
+ scaleY?: number;
+ selectable?: bool;
+ stateProperties?: any[];
+ stroke?: string;
+ strokeDashArray?: any[];
+ strokeWidth?: number;
+ top?: number;
+ transformMatrix?: any[];
+ transparentCorners?: bool;
+ type?: string;
+ width?: number;
+ }
+
+ export interface ITextOptions extends IObjectOptions {
+ fontSize?: number;
+ fontWeight?: any;
+ fontFamily?: string;
+ textDecoration?: string;
+ textShadow?: string;
+ textAlign?: string;
+ fontStyle?: string;
+ lineHeight?: number;
+ strokeStyle?: string;
+ strokeWidth?: number;
+ backgroundColor?: string;
+ textBackgroundColor?: string;
+ path?: string;
+ type?: string;
+ useNative?: Boolean;
+ }
+
+ export interface ICircleOptions extends IObjectOptions {
+ radius?: number;
+ }
+
+ export interface IPoint {
+ add(that: IPoint): IPoint;
+ addEquals(that: IPoint): IPoint;
+ distanceFrom(that: IPoint);
+ divide(scalar: number);
+ divideEquals(scalar: number);
+ eq(that: IPoint);
+ gt(that: IPoint);
+ gte(that: IPoint);
+ init(x, y);
+ lerp(that: IPoint, t);
+ lt(that: IPoint);
+ lte(that: IPoint);
+ max(that: IPoint);
+ min(that: IPoint);
+ multiply(scalar);
+ multiplyEquals(scalar);
+ scalarAdd(scalar): IPoint;
+ scalarAddEquals(scalar: number, thisArg: IPoint);
+ scalarSubtract(scalar: number);
+ scalarSubtractEquals(scalar);
+ setFromPoint(that: IPoint);
+ setXY(x, y);
+ subtract(that: IPoint): IPoint;
+ subtractEquals(that: IPoint): IPoint;
+ swap(that: IPoint);
+ tostring(): string;
+ }
+
+ export interface IRect extends IObject {
+ x: number;
+ y: number;
+ rx: number;
+ ry: number;
+
+ complexity(): number;
+ initialize(points: number[], options: any): IRect;
+ toObject(propertiesToInclude: any[]): any;
+ toSVG(): string;
+ }
+
+ export interface IText extends IObject {
+ fontSize: number;
+ fontWeight: any;
+ fontFamily: string;
+ text: string;
+ textDecoration: string;
+ textShadow?: string;
+ textAlign: string;
+ fontStyle: string;
+ lineHeight: number;
+ strokeStyle: string;
+ strokeWidth: number;
+ backgroundColor: string;
+ textBackgroundColor: string;
+ path?: string;
+ type: string;
+ useNative: Boolean;
+
+ initialize(text: string, options: any): IText;
+ toString(): string;
+ render(ctx: CanvasRenderingContext2D, noTransform: bool);
+ toObject(propertiesToInclude: any[]): IObject;
+ toSVG(): string;
+ setColor(value: string): IText;
+ setFontsize(value: number): IText;
+ getText(): string;
+ setText(value: string): IText;
+ }
+
+ export interface ITriangle extends IObject {
+ complexity(): number;
+ initialize(options: any): ITriangle;
+ toSVG(): string;
+ }
+
+ export interface IEllipse {
+ initialize(options: any): any;
+ toObject(propertiesToInclude: any[]): any;
+ toSVG(): string;
+ render(ctx: CanvasRenderingContext2D, noTransform: bool);
+ complexity(): number;
+ }
+
+ export interface IGradient {
+ initialize(options): any;
+ toObject(): any;
+ toLiveGradient(ctx: CanvasRenderingContext2D): any;
+ }
+
+ export interface IColor {
+ getSource(): any[];
+ setSource(source: any[]): any;
+ toRgb(): string;
+ toRgba(): string;
+ toHex(): string;
+ getAlpha(): number;
+ setAlpha(alpha: number): IColor;
+ toGrayscale(): IColor;
+ toBlackWhite(threshold): IColor;
+ overlayWith(otherColor: string): IColor;
+ overlayWith(otherColor: IColor): IColor;
+ }
+
+ export interface IElement {
+ }
+
+ export interface IObject extends IObservable {
+
+ // constraint properties
+ lockMovementX: bool;
+ lockMovementY: bool;
+ lockScalingX: bool;
+ lockScalingY: bool;
+ lockScaling: bool;
+ lockUniScaling: bool;
+ lockRotation: bool;
+
+ getCurrentWidth(): number;
+ getCurrentHeight(): number;
+
+ angle: number;
+ getAngle(): number;
+ setAngle(value: number): IObject;
+
+ borderColor: string;
+ getBorderColor(): string;
+ setBorderColor(value: string): IObject;
+
+ borderOpacityWhenMoving: number;
+ borderScaleFactor: number;
+ getBorderScaleFactor(): number;
+
+ cornerColor: string;
+
+ cornersize: number;
+ getCornersize(): number;
+ setCornersize(value: number): IObject;
+
+ fill: string;
+ getFill(): string;
+ setFill(value: string): IObject;
+
+ fillRule: string;
+ getFillRule(): string;
+ setFillRule(value: string): IObject;
+
+ flipX: bool;
+ getFlipX(): bool;
+ setFlipX(value: bool): IObject;
+
+ flipY: bool;
+ getFlipY(): bool;
+ setFlipY(value: bool): IObject;
+
+ hasBorders: bool;
+
+ hasControls: bool;
+ hasRotatingPoint: bool;
+
+ height: number;
+ getHeight(): number;
+ setHeight(value: number): IObject;
+
+ includeDefaultValues: bool;
+
+ left: number;
+ getLeft(): number;
+ setLeft(value: number): IObject;
+
+ opacity: number;
+ getOpacity(): number;
+ setOpacity(value: number): IObject;
+
+ overlayFill: string;
+ getOverlayFill(): string;
+ setOverlayFill(value: string): IObject;
+
+ padding: number;
+ perPixelTargetFind: bool;
+ rotatingPointOffset: number;
+
+ scaleX: number;
+ getScaleX(): number;
+ setScaleX(value: number): IObject;
+
+ scaleY: number;
+ getScaleY(): number;
+ setScaleY(value: number): IObject;
+
+ selectable: bool;
+ stateProperties: any[];
+ stroke: string;
+ strokeDashArray: any[];
+ strokeWidth: number;
+
+ top: number;
+ getTop(): number;
+ setTop(value: number): IObject;
+
+ transformMatrix: any[];
+ transparentCorners: bool;
+ type: string;
+
+ width: number;
+ getWidth(): number;
+ setWidth(value: number): IObject;
+
+ // methods
+ bringForward(): IObject;
+ bringToFront(): IObject;
+ center(): IObject;
+ centerH(): IObject;
+ centerV(): IObject;
+ clone(callback?, propertiesToInclude?): IObject;
+ cloneAsImage(callback): IObject;
+ complexity(): number;
+ drawBorders(context: CanvasRenderingContext2D): IObject;
+ drawCorners(context: CanvasRenderingContext2D): IObject;
+ get (property: string): any;
+ getBoundingRectHeight(): number;
+ getBoundingRectWidth(): number;
+ getSvgStyles(): string;
+ getSvgTransform(): string;
+ hasStateChanged(): bool;
+ initialize(options: any);
+ intersectsWithObject(other: IObject): bool;
+ intersectsWithRect(selectionTL: any, selectionBR: any): bool;
+ isActive(): bool;
+ isContainedWithinObject(other: IObject): bool;
+ isContainedWithinRect(selectionTL: any, selectionBR: any): bool;
+ isType(type: string): bool;
+ remove(): IObject;
+ render(ctx: CanvasRenderingContext2D, noTransform: bool);
+ rotate(value: number): IObject;
+ saveState(): IObject;
+ scale(value: number): IObject;
+ scaleToHeight(value: number): IObject;
+ scaleToWidth(value: number): IObject;
+ sendBackwards(): IObject;
+ sendToBack(): IObject;
+
+ set (properties: IObjectOptions): IObject;
+ set (name: string, value: any): IObject;
+ setActive(active: bool): IObject;
+ setCoords();
+ setGradientFill(options);
+ setOptions(options: any);
+ setSourcePath(value: string): IObject;
+ toDatalessObject(propertiesToInclude): any;
+ toDataURL(callback): string;
+ toggle(property): IObject;
+ toGrayscale(): IObject;
+ toJSON(propertiesToInclude): string;
+ toObject(propertiesToInclude): any;
+ tostring(): string;
+ transform(ctx: CanvasRenderingContext2D);
+ }
+
+ export interface IGroup {
+ type: string;
+
+ activateAllObjects(): IGroup;
+ add(object): IGroup;
+ addWithUpdate(object): IGroup;
+ complexity(): number;
+ contains(object): bool;
+ containsPoint(point): bool;
+ destroy(): IGroup;
+ getObjects(): IObject[];
+ hasMoved(): bool;
+ initialize(objects, options): any;
+ item(index): IObject;
+ remove(object): IGroup;
+ removeWithUpdate(object): IGroup;
+ render(ctx, noTransform): void;
+ saveCoords(): IGroup;
+ setObjectsCoords(): IGroup;
+ size(): number;
+ toGrayscale(): void;
+ toObject(propertiesToInclude: any[]): any;
+ tostring(): string;
+ toSVG(): string;
+ }
+
+
+ export interface ILine extends IObject {
+ x1: number;
+ x2: number;
+ y1: number;
+ y2: number;
+
+ complexity(): number;
+ initialize(points: number[], options: any): ILine;
+ toObject(propertiesToInclude: any[]): any;
+ toSVG(): string;
+ }
+
+ export interface IIntersection {
+ appendPoint(status: string);
+ appendPoints(status: string);
+ init(status: string);
+ }
+
+ export interface IImage extends IObject {
+ filters: any;
+
+ applyFilters(callback);
+ clone(propertiesToInclude, callback);
+ complexity(): number;
+ getElement(): HTMLImageElement;
+ getOriginalSize(): { width: number; height: number; };
+ getSrc(): string;
+ initialize(element: string, options: any);
+ initialize(element: HTMLImageElement, options: any);
+ render(ctx: CanvasRenderingContext2D, noTransform: bool);
+ setElement(element): IImage;
+ toObject(propertiesToInclude): any;
+ tostring(): string;
+ toSVG(): string;
+ }
+
+ export interface ICircle extends IObject {
+ // methods
+ complexity(): number;
+ getRadiusX(): number;
+ getRadiusY(): number;
+ initialize(options: ICircleOptions): ICircle;
+ setRadius(value: number): number;
+ toObject(propertiesToInclude): any;
+ toSVG(): string;
+ }
+
+
+
+ export interface IPath extends IObject {
+ complexity(): number;
+ initialize(path, options);
+ render(ctx: CanvasRenderingContext2D, noTransform: bool);
+ toDatalessObject(propertiesToInclude): any;
+ toObject(propertiesToInclude): any;
+ tostring(): string;
+ toSVG(): string;
+ }
+
+ export interface IPolygon extends IObject {
+ complexity(): number;
+ initialize(points, options);
+ toObject(propertiesToInclude): any;
+ toSVG(): string;
+ }
+
+ export interface IPolyline extends IObject {
+ complexity(): number;
+ initialize(points, options);
+ toObject(propertiesToInclude): any;
+ toSVG(): string;
+ }
+
+ export interface IPathGroup extends IObject {
+ complexity(): number;
+ initialize(paths, options);
+ isSameColor(): bool;
+ render(ctx: CanvasRenderingContext2D);
+ toDatalessObject(propertiesToInclude): any;
+ toGrayscale();
+ toObject(propertiesToInclude): any;
+ tostring(): string;
+ toSVG(): string;
+ }
+
+ export interface IStaticCanvas extends IObservable {
+
+ // fields
+ backgroundColor: string;
+ backgroundImage: string;
+ backgroundImageOpacity: number;
+ backgroundImageStretch: number;
+ clipTo(clipFunction: (context: CanvasRenderingContext2D) => void );
+ controlsAboveOverlay: bool;
+ includeDefaultValues: bool;
+ overlayImage: string;
+ overlayImageLeft: number;
+ overlayImageTop: number;
+ renderOnAddition: bool;
+ stateful: bool;
+
+ // static
+ EMPTY_JSON: string;
+ supports(methodName: string): bool;
+
+ // methods
+ add(...object: IObject[]): ICanvas;
+ bringForward(object: IObject): ICanvas;
+ calcOffset(): ICanvas;
+ centerObject(object: IObject): ICanvas;
+ centerObjectH(object: IObject): ICanvas;
+ centerObjectV(object: IObject): ICanvas;
+ clear(): ICanvas;
+ clearContext(context: CanvasRenderingContext2D): ICanvas;
+ complexity(): number;
+ dispose(): ICanvas;
+ drawControls();
+ forEachObject(callback: (object: IObject) => void , context?: CanvasRenderingContext2D): ICanvas;
+ getActiveGroup(): IGroup;
+ getActiveObject(): IObject;
+ getCenter(): IObject;
+ getContext(): CanvasRenderingContext2D;
+ getElement(): HTMLCanvasElement;
+ getHeight(): number;
+ getWidth(): number;
+ insertAt(object: IObject, index: number, nonSplicing: bool): ICanvas;
+ isEmpty(): bool;
+ item(index: number): IObject;
+ onBeforeScaleRotate(target: IObject);
+ remove(object: IObject): IObject;
+ renderAll(allOnTop?: bool): ICanvas;
+ renderTop(): ICanvas;
+
+ sendBackwards(object: IObject): ICanvas;
+ sendToBack(object: IObject): ICanvas;
+ setBackgroundImage(object: IObject): ICanvas;
+ setDimensions(object: { width: number; height: number; }): ICanvas;
+ setHeight(height: number): ICanvas;
+ setOverlayImage(url: string, callback: () => any, options): ICanvas;
+ setWidth(width: number): ICanvas;
+ toDatalessJSON(propertiesToInclude: any[]): string;
+ toDatalessObject(propertiesToInclude: any[]): string;
+ toDataURL(format: string, quality?: number): string;
+ toDataURLWithMultiplier(propertiesToInclude: any[]): string;
+ toGrayscale(propertiesToInclude: any[]): string;
+ toJSON(propertiesToInclude: any[]): string;
+ toObject(propertiesToInclude: any[]): string;
+ tostring(): string;
+ toSVG(): string;
+ }
+
+ export interface ICanvas extends IStaticCanvas {
+
+ // constructors
+ (element: HTMLCanvasElement): ICanvas;
+ (element: string): ICanvas;
+
+ // fields
+ containerClass: string;
+ defaultCursor: string;
+ freeDrawingColor: string;
+ freeDrawingLineWidth: number;
+ hoverCursor: string;
+ interactive: bool;
+ moveCursor: string;
+ perPixelTargetFind: bool;
+ rotationCursor: string;
+ selection: bool;
+ selectionBorderColor: string;
+ selectionColor: string;
+ selectionDashArray: number[];
+ selectionLineWidth: number;
+ targetFindTolerance: number;
+
+ // methods
+ containsPoint(e: Event, target: IObject): bool;
+ deactivateAll(): ICanvas;
+ deactivateAllWithDispatch(): ICanvas;
+ discardActiveGroup(): ICanvas;
+ discardActiveObject(): ICanvas;
+ drawDashedLine(ctx: CanvasRenderingContext2D, x: number, y: number, x2: number, y2: number, dashArray: number[]): ICanvas;
+ findTarget(e: MouseEvent, skipGroup: bool): ICanvas;
+ getActiveGroup(): IGroup;
+ getActiveObject(): IObject;
+ getPointer(e): { x: number; y: number; };
+ getSelectionContext(): CanvasRenderingContext2D;
+ getSelectionElement(): HTMLCanvasElement;
+ setActiveGroup(group: IGroup): ICanvas;
+ setActiveObject(object: IObject, e?): ICanvas;
+ }
+
+ export interface IBrightnessFilter {
+ }
+ export interface IInvertFilter {
+ }
+ export interface IRemoveWhiteFilter {
+ }
+ export interface IGrayscaleFilter {
+ }
+ export interface ISepiaFilter {
+ }
+ export interface ISepia2Filter {
+ }
+ export interface INoiseFilter {
+ }
+ export interface IGradientTransparencyFilter {
+ }
+ export interface IPixelateFilter {
+ }
+ export interface IConvoluteFilter {
+ }
+
+ export interface ICanvasOptions {
+ containerClass?: string;
+ defaultCursor?: string;
+ freeDrawingColor?: string;
+ freeDrawingLineWidth?: number;
+ hoverCursor?: string;
+ interactive?: bool;
+ moveCursor?: string;
+ perPixelTargetFind?: bool;
+ rotationCursor?: string;
+ selection?: bool;
+ selectionBorderColor?: string;
+ selectionColor?: string;
+ selectionDashArray?: number[];
+ selectionLineWidth?: number;
+ targetFindTolerance?: number;
+
+ backgroundColor?: string;
+ backgroundImage?: string;
+ backgroundImageOpacity?: number;
+ backgroundImageStretch?: number;
+ controlsAboveOverlay?: bool;
+ includeDefaultValues?: bool;
+ overlayImage?: string;
+ overlayImageLeft?: number;
+ overlayImageTop?: number;
+ renderOnAddition?: bool;
+ stateful?: bool;
+ }
+
+ export interface IRectOptions extends IObjectOptions {
+ x?: number;
+ y?: number;
+ rx?: number;
+ ry?: number;
+ }
+
+ export interface ITriangleOptions extends IObjectOptions {
+ }
+
+ declare var Rect: {
+ fromElement(element: SVGElement, options: IRectOptions): IRect;
+ fromObject(object): IRect;
+ new (options?: IRectOptions): IRect;
+ prototype: any;
+ }
+
+ declare var Triangle: {
+ new (options?: ITriangleOptions): ITriangle;
+ }
+
+ declare var Canvas: {
+ new (element: HTMLCanvasElement, options?: ICanvasOptions): ICanvas;
+ new (element: string, options?: ICanvasOptions): ICanvas;
+
+ EMPTY_JSON: string;
+ supports(methodName: string): bool;
+ prototype: any;
+ }
+
+ declare var Circle: {
+ ATTRIBUTE_NAMES: string[];
+ fromElement(element: SVGElement, options: ICircleOptions): ICircle;
+ fromObject(object): ICircle;
+ new (options?: ICircleOptions): ICircle;
+ prototype: any;
+ }
+
+ declare var Line: {
+ ATTRIBUTE_NAMES: string[];
+ fromElement(element: SVGElement, options): ILine;
+ fromObject(object): ILine;
+ prototype: any;
+ new (points: number[], objObjects?: IObjectOptions): ILine;
+ }
+
+ declare var Intersection: {
+ intersectLineLine(a1, a2, b1, b2);
+ intersectLinePolygon(a1, a2, points);
+ intersectPolygonPolygon(points1, points2);
+ intersectPolygonRectangle(points, r1, r2);
+ }
+
+ declare var Path: {
+ fromElement(element: SVGElement, options): IPath;
+ fromObject(object): IPath;
+ new (): IPath;
+ }
+
+ declare var PathGroup: {
+ fromObject(object): IPathGroup;
+ new (): IPathGroup;
+ prototype: any;
+ }
+
+ declare var Point: {
+ new (x, y): IPoint;
+ prototype: any;
+ }
+
+ declare var Object: {
+ prototype: any;
+ }
+
+ declare var Polygon: {
+ fromObject(object): IPolygon;
+ fromElement(element: SVGElement, options): IPolygon;
+ new (): IPolygon;
+ prototype: any;
+ }
+
+ declare var Polyline: {
+ fromObject(object): IPolyline;
+ fromElement(element: SVGElement, options): IPolyline;
+ new (): IPolyline;
+ prototype: any;
+ }
+
+ declare var Text: {
+ new (text: string, options?: ITextOptions): IText;
+ }
+
+ declare var Image: {
+ fromURL(url: string): IImage;
+ fromURL(url: string, callback: (image: IImage) => any): IImage;
+ fromURL(url: string, callback: (image: IImage) => any, objObjects: IObjectOptions): IImage;
+ prototype: any;
+
+ filters:
+ {
+ Grayscale: {
+ new (): IGrayscaleFilter;
+ };
+ Brightness: {
+ new (options?: { brightness: number; }): IBrightnessFilter;
+ };
+ RemoveWhite: {
+ new (options?: {
+ threshold?: string; // TODO: Check this
+ distance?: string; // TODO: Check this
+ }): IRemoveWhiteFilter;
+ };
+ Invert: {
+ new (): IInvertFilter;
+ };
+ Sepia: {
+ new (): ISepiaFilter;
+ };
+ Sepia2: {
+ new (): ISepia2Filter;
+ };
+ Noise: {
+ new (options?: {
+ noise?: number;
+ }): INoiseFilter;
+ };
+ GradientTransparency: {
+ new (options?: {
+ threshold?: number;
+ }): IGradientTransparencyFilter;
+ };
+ Pixelate: {
+ new (options?: {
+ color?: any;
+ }): IPixelateFilter;
+ };
+ Convolute: {
+ new (options?: {
+ matrix: any;
+ }): IConvoluteFilter;
+ };
+ };
+
+ }
+
+ declare var util: {
+ addClass(element: HTMLElement, className: string);
+ addListener(element, eventName: string, handler);
+ animate(options: {
+ onChange?: (value: number) => void;
+ onComplete?: () => void;
+ startValue?: number;
+ endValue?: number;
+ byValue?: number;
+ easing?: (currentTime, startValue, byValue, duration) => number;
+ duration?: number;
+ });
+ createClass(parent, properties);
+ degreesToRadians(degrees: number): number;
+ falseFunction(): () => bool;
+ getById(id: HTMLElement): HTMLElement;
+ getById(id: string): HTMLElement;
+ getElementOffset(element): { left: number; top: number; };
+ getPointer(event: Event);
+ getRandomInt(min: number, max: number);
+ getScript(url: string, callback);
+ groupSVGElements(elements: any[], options, path?: string);
+ loadImage(url, callback, context);
+ makeElement(tagName: string, attributes);
+ makeElementSelectable(element: HTMLElement);
+ makeElementUnselectable(element: HTMLElement);
+ populateWithProperties(source, destination, properties): any[];
+ radiansToDegrees(radians: number): number;
+ removeFromArray(array: any[], value);
+ removeListener(element: HTMLElement, eventName, handler);
+ request(url, options);
+ requestAnimFrame(callback, element);
+ setStyle(element: HTMLElement, styles);
+ toArray(arrayLike): any[];
+ toFixed(number, fractionDigits);
+ wrapElement(element: HTMLElement, wrapper, attributes);
+ }
+};
\ No newline at end of file
diff --git a/fabricjs/tests/sample1.ts b/fabricjs/tests/sample1.ts
new file mode 100644
index 0000000000..f494d84cec
--- /dev/null
+++ b/fabricjs/tests/sample1.ts
@@ -0,0 +1,33 @@
+///
+
+var canvas = new fabric.Canvas('c', {
+ hoverCursor: 'pointer',
+ selection: false,
+});
+
+canvas.on({
+ 'object:moving': function(e) {
+ e.target.opacity = 0.5;
+ },
+ 'object:modified': function(e) {
+ e.target.opacity = 1;
+ }
+});
+
+for (var i = 0, len = 15; i < len; i++) {
+ fabric.Image.fromURL('../assets/ladybug.png', function(img) {
+ img.set({
+ left: fabric.util.getRandomInt(0, 600),
+ top: fabric.util.getRandomInt(0, 500),
+ angle: fabric.util.getRandomInt(0, 90)
+ });
+
+ img.perPixelTargetFind = true;
+ // img.targetFindTolerance = 4;
+ img.hasControls = img.hasBorders = false;
+
+ img.scale(fabric.util.getRandomInt(50, 100) / 100);
+
+ canvas.add(img);
+ });
+}
\ No newline at end of file
diff --git a/fabricjs/tests/sample2.ts b/fabricjs/tests/sample2.ts
new file mode 100644
index 0000000000..a04f2d1b8c
--- /dev/null
+++ b/fabricjs/tests/sample2.ts
@@ -0,0 +1,53 @@
+///
+
+var dot, i,
+ t1, t2,
+ startTimer = function() {
+ t1 = new Date().getTime();
+ return t1;
+ },
+ stopTimer = function() {
+ t2 = new Date().getTime();
+ return t2 - t1;
+ },
+ getRandomInt = fabric.util.getRandomInt,
+ rainbow = ["#ffcc66", "#ccff66", "#66ccff", "#ff6fcf", "#ff6666"],
+ rainbowEnd = rainbow.length - 1;
+
+//
+// Rendering canvas #1
+//
+var canvas1 = new fabric.Canvas('c1', { backgroundColor: "#000" }),
+ results1 = document.getElementById('results-c1');
+
+startTimer();
+for (i = 100; i >= 0; i--) {
+ dot = new fabric.Circle({
+ left: getRandomInt(0, 400),
+ top: getRandomInt(0, 350),
+ radius: 3,
+ fill: rainbow[getRandomInt(0, rainbowEnd)]
+ });
+ canvas1.add(dot);
+}
+results1.innerHTML = 'Regular rendering of 100 elements in ' + stopTimer() + 'ms';
+
+
+//
+// Rendering canvas #2
+//
+var canvas2 = new fabric.Canvas('c2', { backgroundColor: "#000", renderOnAddition: false }),
+ results2 = document.getElementById('results-c2');
+
+startTimer();
+for (i = 1000; i >= 0; i--) {
+ dot = new fabric.Circle({
+ left: getRandomInt(0, 400),
+ top: getRandomInt(0, 350),
+ radius: 3,
+ fill: rainbow[getRandomInt(0, rainbowEnd)]
+ });
+ canvas2.add(dot);
+}
+canvas2.renderAll(); // Note, calling renderAll() is important in this case
+results2.innerHTML = 'Rendering 1000 elements using canvas.renderOnAddition = false in ' + stopTimer() + 'ms';
\ No newline at end of file
diff --git a/fabricjs/tests/sample3.ts b/fabricjs/tests/sample3.ts
new file mode 100644
index 0000000000..5393f6c64e
--- /dev/null
+++ b/fabricjs/tests/sample3.ts
@@ -0,0 +1,122 @@
+///
+
+var $ = function(id){return document.getElementById(id)};
+
+function applyFilter(index, filter) {
+ var obj = canvas.getActiveObject();
+ obj.filters[index] = filter;
+ obj.applyFilters(canvas.renderAll.bind(canvas));
+}
+
+function applyFilterValue(index, prop, value) {
+ var obj = canvas.getActiveObject();
+ if (obj.filters[index]) {
+ obj.filters[index][prop] = value;
+ obj.applyFilters(canvas.renderAll.bind(canvas));
+ }
+}
+
+var canvas = new fabric.Canvas('c', { backgroundImage: '../lib/bg.png' }),
+ f = fabric.Image.filters;
+
+canvas.on({
+ 'object:selected': function() {
+ fabric.util.toArray(document.getElementsByTagName('input')).forEach(function(el){ el.disabled = false; })
+
+ var filters = ['grayscale', 'invert', 'remove-white', 'sepia', 'sepia2', 'brightness',
+ 'noise', 'gradient-transparency', 'pixelate', 'blur', 'sharpen'];
+
+ for (var i = 0; i < filters.length; i++) {
+ var checkBox = $(filters[i]);
+ var image = canvas.getActiveObject();
+ checkBox.checked = !!image.filters[i];
+ }
+ },
+ 'selection:cleared': function() {
+ fabric.util.toArray(document.getElementsByTagName('input')).forEach(function(el){ el.disabled = true; })
+ }
+});
+
+fabric.Image.fromURL('../assets/printio.png', function(img) {
+ var oImg = img.set({ left: 300, top: 300, angle: -15 }).scale(0.9);
+ canvas.add(oImg).renderAll();
+ canvas.setActiveObject(oImg);
+});
+
+$('grayscale').onclick = function() {
+ applyFilter(0, this.checked && new f.Grayscale());
+};
+$('invert').onclick = function() {
+ applyFilter(1, this.checked && new f.Invert());
+};
+$('remove-white').onclick = function () {
+ applyFilter(2, this.checked && new f.RemoveWhite({
+ threshold: ($('remove-white-threshold')).value,
+ distance: ($('remove-white-distance')).value
+ }));
+};
+$('remove-white-threshold').onchange = function() {
+ applyFilterValue(2, 'threshold', this.value);
+};
+$('remove-white-distance').onchange = function() {
+ applyFilterValue(2, 'distance', this.value);
+};
+$('sepia').onclick = function() {
+ applyFilter(3, this.checked && new f.Sepia());
+};
+$('sepia2').onclick = function() {
+ applyFilter(4, this.checked && new f.Sepia2());
+};
+$('brightness').onclick = function () {
+ applyFilter(5, this.checked && new f.Brightness({
+ brightness: parseInt(($('brightness-value')).value, 10)
+ }));
+};
+$('brightness-value').onchange = function() {
+ applyFilterValue(5, 'brightness', parseInt(this.value, 10));
+};
+$('noise').onclick = function () {
+ applyFilter(6, this.checked && new f.Noise({
+ noise: parseInt(($('noise-value')).value, 10)
+ }));
+};
+$('noise-value').onchange = function() {
+ applyFilterValue(6, 'noise', parseInt(this.value, 10));
+};
+$('gradient-transparency').onclick = function () {
+ applyFilter(7, this.checked && new f.GradientTransparency({
+ threshold: parseInt(($('gradient-transparency-value')).value, 10)
+ }));
+};
+$('gradient-transparency-value').onchange = function() {
+ applyFilterValue(7, 'threshold', parseInt(this.value, 10));
+};
+$('pixelate').onclick = function() {
+ applyFilter(8, this.checked && new f.Pixelate({
+ blocksize: parseInt(($('pixelate-value')).value, 10)
+ }));
+};
+$('pixelate-value').onchange = function() {
+ applyFilterValue(8, 'blocksize', parseInt(this.value, 10));
+};
+$('blur').onclick = function() {
+ applyFilter(9, this.checked && new f.Convolute({
+ matrix: [ 1/9, 1/9, 1/9,
+ 1/9, 1/9, 1/9,
+ 1/9, 1/9, 1/9 ]
+ }));
+};
+$('sharpen').onclick = function() {
+ applyFilter(10, this.checked && new f.Convolute({
+ matrix: [ 0, -1, 0,
+ -1, 5, -1,
+ 0, -1, 0 ]
+ }));
+};
+$('emboss').onclick = function() {
+ applyFilter(11, this.checked && new f.Convolute({
+ matrix: [ 1, 1, 1,
+ 1, 0.7, -1,
+ -1, -1, -1 ]
+ }));
+};
\ No newline at end of file
diff --git a/fabricjs/tests/sample4.ts b/fabricjs/tests/sample4.ts
new file mode 100644
index 0000000000..a1cfd0e4c2
--- /dev/null
+++ b/fabricjs/tests/sample4.ts
@@ -0,0 +1,51 @@
+///
+
+var canvas = new fabric.Canvas('c');
+var $ = function (id) { return document.getElementById(id); };
+
+var rect = new fabric.Rect({
+ width: 100,
+ height: 100,
+ top: 150,
+ left: 150,
+ fill: 'rgba(255,0,0,0.5)'
+});
+
+canvas.add(rect);
+
+var angleControl = $('angle-control');
+angleControl.onchange = function() {
+ rect.setAngle(this.value).setCoords();
+ canvas.renderAll();
+};
+
+var scaleControl = $('scale-control');
+scaleControl.onchange = function() {
+ rect.scale(this.value).setCoords();
+ canvas.renderAll();
+};
+
+var topControl = $('top-control');
+topControl.onchange = function() {
+ rect.setTop(this.value).setCoords();
+ canvas.renderAll();
+};
+
+var leftControl = $('left-control');
+leftControl.onchange = function() {
+ rect.setLeft(this.value).setCoords();
+ canvas.renderAll();
+};
+
+function updateControls() {
+
+ scaleControl.value = rect.getScaleX().toString();
+ angleControl.value = rect.getAngle().toString();
+ leftControl.value = rect.getLeft().toString();
+ topControl.value = rect.getTop().toString();
+}
+canvas.on({
+ 'object:moving': updateControls,
+ 'object:scaling': updateControls,
+ 'object:resizing': updateControls
+});
diff --git a/fabricjs/tests/sample5.ts b/fabricjs/tests/sample5.ts
new file mode 100644
index 0000000000..399f32ad98
--- /dev/null
+++ b/fabricjs/tests/sample5.ts
@@ -0,0 +1,66 @@
+///
+
+module fabric {
+ export interface CircleWithLineInfos extends ICircle {
+ line1?: ILine;
+ line2?: ILine;
+ line3?: ILine;
+ line4?: ILine;
+ }
+}
+
+var makeCircle = function(left: number, top: number, line1?: fabric.ILine, line2?: fabric.ILine, line3?: fabric.ILine, line4?: fabric.ILine): fabric.ICircle {
+ var c = new fabric.Circle({
+ left: left,
+ top: top,
+ strokeWidth: 5,
+ radius: 12,
+ fill: '#fff',
+ stroke: '#666'
+ });
+
+ c.line1 = line1;
+ c.line2 = line2;
+ c.line3 = line3;
+ c.line4 = line4;
+ c.hasControls = c.hasBorders = false;
+ return c;
+}
+
+function makeLine(coords: number[]) {
+ return new fabric.Line(coords, {
+ fill: 'red',
+ strokeWidth: 5,
+ selectable: false
+ });
+}
+
+var canvas = new fabric.Canvas('c', { selection: false });
+
+var line = makeLine([ 250, 125, 250, 175 ]),
+ line2 = makeLine([ 250, 175, 250, 250 ]),
+ line3 = makeLine([ 250, 250, 300, 350]),
+ line4 = makeLine([ 250, 250, 200, 350]),
+ line5 = makeLine([ 250, 175, 175, 225 ]),
+ line6 = makeLine([ 250, 175, 325, 225 ]);
+
+canvas.add(line, line2, line3, line4, line5, line6);
+
+canvas.add(
+ makeCircle(line.x1, line.y1, null, line),
+ makeCircle(line.x2, line.y2, line, line2, line5, line6),
+ makeCircle(line2.x2, line2.y2, line2, line3, line4),
+ makeCircle(line3.x2, line3.y2, line3),
+ makeCircle(line4.x2, line4.y2, line4),
+ makeCircle(line5.x2, line5.y2, line5),
+ makeCircle(line6.x2, line6.y2, line6)
+);
+
+canvas.on('object:moving', function(e) {
+ var p = e.target;
+ p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
+ p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
+ p.line3 && p.line3.set({ 'x1': p.left, 'y1': p.top });
+ p.line4 && p.line4.set({ 'x1': p.left, 'y1': p.top });
+ canvas.renderAll();
+});
\ No newline at end of file
diff --git a/fabricjs/tests/sample6.ts b/fabricjs/tests/sample6.ts
new file mode 100644
index 0000000000..48123ce626
--- /dev/null
+++ b/fabricjs/tests/sample6.ts
@@ -0,0 +1,26 @@
+///
+
+var canvas = new fabric.Canvas('c');
+fabric.loadSVGFromURL('../assets/135.svg', function (objects) {
+ var obj = objects[0].scale(0.25);
+ canvas.centerObject(obj);
+ canvas.add(obj);
+
+ canvas.add(obj.clone().set({ left: 100, top: 100, angle: -15 }));
+ canvas.add(obj.clone().set({ left: 480, top: 100, angle: 15 }));
+ canvas.add(obj.clone().set({ left: 100, top: 400, angle: -15 }));
+ canvas.add(obj.clone().set({ left: 480, top: 400, angle: 15 }));
+
+ canvas.on('mouse:move', function (options) {
+ var p = canvas.getPointer(options.e);
+
+ canvas.forEachObject(function (obj) {
+ var distX = Math.abs(p.x - obj.left),
+ distY = Math.abs(p.y - obj.top),
+ dist = Math.round(Math.sqrt(Math.pow(distX, 2) + Math.pow(distY, 2)));
+ obj.setOpacity(1 / (dist / 20));
+ });
+
+ });
+
+});
\ No newline at end of file
diff --git a/fabricjs/tests/sample7.ts b/fabricjs/tests/sample7.ts
new file mode 100644
index 0000000000..2fe0c74bac
--- /dev/null
+++ b/fabricjs/tests/sample7.ts
@@ -0,0 +1,37 @@
+///
+
+module fabric {
+ export interface ImageWithInfo extends IImage {
+ movingLeft: bool;
+ }
+}
+
+var canvas = new fabric.Canvas('c', { selection: false });
+
+setInterval(function() {
+ fabric.Image.fromURL('../assets/ladybug.png', function(obj) {
+ var img = obj;
+ img.set('left', fabric.util.getRandomInt(200, 600)).set('top', -50);
+ img.movingLeft = !!Math.round(Math.random());
+ canvas.add(img);
+ });
+}, 1000);
+
+
+var animate = (function animate() {
+ canvas.forEachObject(function (obj) {
+ var img = obj;
+ img.left += (img.movingLeft ? -1 : 1);
+ img.top += 1;
+ if (img.left > 900 || img.top > 500) {
+ canvas.remove(img);
+ }
+ else {
+ img.setAngle(img.getAngle() + 2);
+ }
+ });
+ canvas.renderAll();
+ window.requestAnimationFrame(animate);
+});
+
+animate();
\ No newline at end of file
diff --git a/fabricjs/tests/sample8.ts b/fabricjs/tests/sample8.ts
new file mode 100644
index 0000000000..a8d8ef4812
--- /dev/null
+++ b/fabricjs/tests/sample8.ts
@@ -0,0 +1,667 @@
+///
+
+module fabric {
+ export interface ImageWithInfo extends IImage {
+ movingLeft: bool;
+ }
+}
+
+function pad(str: string, length: number): string {
+ while (str.length < length) {
+ str = '0' + str;
+ }
+ return str;
+};
+
+var getRandomInt = fabric.util.getRandomInt;
+
+function getRandomColor() {
+ return (
+ pad(getRandomInt(0, 255).toString(16), 2) +
+ pad(getRandomInt(0, 255).toString(16), 2) +
+ pad(getRandomInt(0, 255).toString(16), 2)
+ );
+}
+
+function getRandomNum(min: number, max: number): number {
+ return Math.random() * (max - min) + min;
+ }
+
+if (/(iPhone|iPod|iPad)/i.test(navigator.userAgent)) {
+ fabric.Object.prototype.cornersize = 30;
+}
+
+var canvas = new fabric.Canvas('canvas');
+// canvas.controlsAboveOverlay = true;
+
+function updateComplexity() {
+ setTimeout(function() {
+ var element = document.getElementById('complexity').childNodes[1];
+ element.innerHTML = ' ' + canvas.complexity();
+ }, 100);
+}
+
+document.getElementById('commands').onclick = function (ev) {
+ var ev: any = ev || window.event;
+
+ if (ev.preventDefault) {
+ ev.preventDefault()
+ }
+ else if (ev.returnValue) {
+ ev.returnValue = false;
+ }
+
+ var element: any = ev.target || ev.srcElement;
+ if (element.nodeName.toLowerCase() === 'strong') {
+ element = element.parentNode;
+ }
+
+ var className = element.className,
+ offset = 50,
+ left = fabric.util.getRandomInt(0 + offset, 700 - offset),
+ top = fabric.util.getRandomInt(0 + offset, 500 - offset),
+ angle = fabric.util.getRandomInt(-20, 40),
+ width = fabric.util.getRandomInt(30, 50),
+ opacity = (function(min, max){ return Math.random() * (max - min) + min; })(0.5, 1);
+
+
+ switch (className) {
+ case 'rect':
+ canvas.add(new fabric.Rect({
+ left: left,
+ top: top,
+ fill: '#' + getRandomColor(),
+ width: 50,
+ height: 50,
+ opacity: 0.8
+ }));
+ break;
+
+ case 'circle':
+ canvas.add(new fabric.Circle({
+ left: left,
+ top: top,
+ fill: '#' + getRandomColor(),
+ radius: 50,
+ opacity: 0.8
+ }));
+ break;
+
+ case 'triangle':
+ canvas.add(new fabric.Triangle({
+ left: left,
+ top: top,
+ fill: '#' + getRandomColor(),
+ width: 50,
+ height: 50,
+ opacity: 0.8
+ }));
+ break;
+
+ case 'image1':
+ fabric.Image.fromURL('../assets/pug.jpg', function(image) {
+ image.set({
+ left: left,
+ top: top,
+ angle: angle,
+ padding: 10,
+ cornersize: 10
+ });
+ image.scale(getRandomNum(0.1, 0.25)).setCoords();
+ canvas.add(image);
+ });
+ break;
+
+ case 'image2':
+ fabric.Image.fromURL('../assets/logo.png', function(image) {
+ image.set({
+ left: left,
+ top: top,
+ angle: angle,
+ padding: 10,
+ cornersize: 10
+ });
+ image.scale(getRandomNum(0.1, 1)).setCoords();
+ canvas.add(image);
+ updateComplexity();
+ });
+ break;
+
+ case 'shape':
+ var id = element.id, match;
+ if (match = /\d+$/.exec(id)) {
+ fabric.loadSVGFromURL('../assets/' + match[0] + '.svg', function(objects, options) {
+ var loadedObject = fabric.util.groupSVGElements(objects, options);
+
+ loadedObject.set({
+ left: left,
+ top: top,
+ angle: angle,
+ padding: 10,
+ cornersize: 10
+ });
+ loadedObject/*.scaleToWidth(300)*/.setCoords();
+
+ // loadedObject.hasRotatingPoint = true;
+
+ canvas.add(loadedObject);
+ updateComplexity();
+ canvas.calcOffset();
+ });
+ }
+ break;
+
+ case 'clear':
+ if (confirm('Are you sure?')) {
+ canvas.clear();
+ }
+ }
+ updateComplexity();
+};
+
+document.getElementById('execute').onclick = function() {
+ var code = (document.getElementById('canvas-console')).value;
+ if (!(/^\s+$/).test(code)) {
+ eval(code);
+ }
+};
+
+
+document.getElementById('rasterize').onclick = function() {
+ if (!fabric.Canvas.supports('toDataURL')) {
+ alert('This browser doesn\'t provide means to serialize canvas to an image');
+ }
+ else {
+ window.open(canvas.toDataURL('png'));
+ }
+};
+
+var removeSelectedEl = document.getElementById('remove-selected');
+ removeSelectedEl.onclick = function() {
+ var activeObject = canvas.getActiveObject(),
+ activeGroup = canvas.getActiveGroup();
+ if (activeObject) {
+ canvas.remove(activeObject);
+ }
+ else if (activeGroup) {
+ var objectsInGroup = activeGroup.getObjects();
+ canvas.discardActiveGroup();
+ objectsInGroup.forEach(function(object) {
+ canvas.remove(object);
+ });
+ }
+ };
+
+var supportsInputOfType = function(type) {
+ return function() {
+ var el = document.createElement('input');
+ try {
+ el.type = type;
+ }
+ catch(err) { }
+ return el.type === type;
+ };
+ };
+
+ var supportsSlider = supportsInputOfType('range'),
+ supportsColorpicker = supportsInputOfType('color');
+
+ if (supportsSlider()) {
+ (function(){
+ var controls = document.getElementById('controls');
+
+ var sliderLabel = document.createElement('label');
+ sliderLabel.htmlFor = 'opacity';
+ sliderLabel.innerHTML = 'Opacity: ';
+
+ var slider = document.createElement('input');
+
+ try { slider.type = 'range'; } catch(err) { }
+
+ slider.id = 'opacity';
+ slider.value = "100";
+
+ controls.appendChild(sliderLabel);
+ controls.appendChild(slider);
+
+ canvas.calcOffset();
+
+ slider.onchange = function() {
+ var activeObject = canvas.getActiveObject(),
+ activeGroup = canvas.getActiveGroup();
+
+ if (activeObject || activeGroup) {
+ (activeObject || activeGroup).setOpacity(parseInt(this.value, 10) / 100);
+ canvas.renderAll();
+ }
+ };
+ })();
+ }
+
+if (supportsColorpicker()) {
+ (function(){
+ var controls = document.getElementById('controls');
+
+ var label = document.createElement('label');
+ label.htmlFor = 'color';
+ label.innerHTML = 'Color: ';
+ label.style.marginLeft = '10px';
+
+ var colorpicker = document.createElement('input');
+ colorpicker.type = 'color';
+ colorpicker.id = 'color';
+ colorpicker.style.width = '40px';
+
+ controls.appendChild(label);
+ controls.appendChild(colorpicker);
+
+ canvas.calcOffset();
+
+ colorpicker.onchange = function() {
+ var activeObject = canvas.getActiveObject(),
+ activeGroup = canvas.getActiveGroup();
+
+ if (activeObject || activeGroup) {
+ (activeObject || activeGroup).setFill(this.value);
+ canvas.renderAll();
+ }
+ };
+ })();
+ }
+
+ var lockHorizontallyEl = document.getElementById('lock-horizontally');
+ lockHorizontallyEl.onclick = function() {
+ var activeObject: any = canvas.getActiveObject();
+ if (activeObject) {
+ activeObject.lockMovementX = !activeObject.lockMovementX;
+ lockHorizontallyEl.innerHTML = activeObject.lockMovementX
+ ? 'Unlock horizontal movement'
+ : 'Lock horizontal movement';
+ }
+ };
+
+ var lockVerticallyEl = document.getElementById('lock-vertically');
+ lockVerticallyEl.onclick = function() {
+ var activeObject: any = canvas.getActiveObject();
+ if (activeObject) {
+ activeObject.lockMovementY = !activeObject.lockMovementY;
+ lockVerticallyEl.innerHTML = activeObject.lockMovementY
+ ? 'Unlock vertical movement'
+ : 'Lock vertical movement';
+ }
+ };
+
+ var lockScalingXEl = document.getElementById('lock-scaling-x');
+ lockScalingXEl.onclick = function() {
+ var activeObject: any = canvas.getActiveObject();
+ if (activeObject) {
+ activeObject.lockScalingX = !activeObject.lockScalingX;
+ lockScalingXEl.innerHTML = activeObject.lockScalingX
+ ? 'Unlock horizontal scaling'
+ : 'Lock horizontal scaling';
+ }
+ };
+
+ var lockScalingYEl = document.getElementById('lock-scaling-y');
+ lockScalingYEl.onclick = function() {
+ var activeObject: any = canvas.getActiveObject();
+ if (activeObject) {
+ activeObject.lockScalingY = !activeObject.lockScalingY;
+ lockScalingYEl.innerHTML = activeObject.lockScalingY
+ ? 'Unlock vertical scaling'
+ : 'Lock vertical scaling';
+ }
+ };
+
+ var lockRotationEl = document.getElementById('lock-rotation');
+ lockRotationEl.onclick = function() {
+ var activeObject: any = canvas.getActiveObject();
+ if (activeObject) {
+ activeObject.lockRotation = !activeObject.lockRotation;
+ lockRotationEl.innerHTML = activeObject.lockRotation
+ ? 'Unlock rotation'
+ : 'Lock rotation';
+ }
+ };
+
+ var gradientifyBtn = document.getElementById('gradientify');
+
+ var activeObjectButtons = [
+ lockHorizontallyEl,
+ lockVerticallyEl,
+ lockScalingXEl,
+ lockScalingYEl,
+ lockRotationEl,
+ removeSelectedEl,
+ gradientifyBtn
+ ];
+
+ var opacityEl = document.getElementById('opacity');
+ if (opacityEl) {
+ activeObjectButtons.push(opacityEl);
+ }
+ var colorEl = document.getElementById('color');
+ if (colorEl) {
+ activeObjectButtons.push(colorEl);
+ }
+
+ for (var i = activeObjectButtons.length; i--; ) {
+ activeObjectButtons[i].disabled = true;
+ }
+
+ canvas.on('object:selected', onObjectSelected);
+ canvas.on('group:selected', onObjectSelected);
+
+ function onObjectSelected(e) {
+ var selectedObject = e.target;
+
+ for (var i = activeObjectButtons.length; i--; ) {
+ activeObjectButtons[i].disabled = false;
+ }
+
+ lockHorizontallyEl.innerHTML = (selectedObject.lockMovementX ? 'Unlock horizontal movement' : 'Lock horizontal movement');
+ lockVerticallyEl.innerHTML = (selectedObject.lockMovementY ? 'Unlock vertical movement' : 'Lock vertical movement');
+ lockScalingXEl.innerHTML = (selectedObject.lockScalingX ? 'Unlock horizontal scaling' : 'Lock horizontal scaling');
+ lockScalingYEl.innerHTML = (selectedObject.lockScalingY ? 'Unlock vertical scaling' : 'Lock vertical scaling');
+ lockRotationEl.innerHTML = (selectedObject.lockRotation ? 'Unlock rotation' : 'Lock rotation');
+ }
+
+ canvas.on('selection:cleared', function(e) {
+ for (var i = activeObjectButtons.length; i--; ) {
+ activeObjectButtons[i].disabled = true;
+ }
+ });
+
+ var drawingModeEl = document.getElementById('drawing-mode'),
+ drawingOptionsEl = document.getElementById('drawing-mode-options'),
+ drawingColorEl = document.getElementById('drawing-color'),
+ drawingLineWidthEl = document.getElementById('drawing-line-width');
+
+ drawingModeEl.onclick = function() {
+ var canvasWithDrawingMode: any = canvas;
+ canvasWithDrawingMode.isDrawingMode = !canvasWithDrawingMode.isDrawingMode;
+ if (canvasWithDrawingMode.isDrawingMode) {
+ drawingModeEl.innerHTML = 'Cancel drawing mode';
+ drawingModeEl.className = 'is-drawing';
+ drawingOptionsEl.style.display = '';
+ }
+ else {
+ drawingModeEl.innerHTML = 'Enter drawing mode';
+ drawingModeEl.className = '';
+ drawingOptionsEl.style.display = 'none';
+ }
+ };
+
+ canvas.on('path:created', function() {
+ updateComplexity();
+ });
+
+ drawingColorEl.onchange = function() {
+ canvas.freeDrawingColor = drawingColorEl.value;
+ };
+ drawingLineWidthEl.onchange = function() {
+ canvas.freeDrawingLineWidth = parseInt(drawingLineWidthEl.value, 10) || 1; // disallow 0, NaN, etc.
+ };
+
+ canvas.freeDrawingColor = drawingColorEl.value;
+ canvas.freeDrawingLineWidth = parseInt(drawingLineWidthEl.value, 10) || 1;
+
+
+ var text = 'Lorem ipsum dolor sit amet,\nconsectetur adipisicing elit,\nsed do eiusmod tempor incididunt\nut labore et dolore magna aliqua.\n' +
+ 'Ut enim ad minim veniam,\nquis nostrud exercitation ullamco\nlaboris nisi ut aliquip ex ea commodo consequat.';
+
+ document.getElementById('add-text').onclick = function() {
+ var textSample = new fabric.Text(text.slice(0, getRandomInt(0, text.length)), {
+ left: getRandomInt(350, 400),
+ top: getRandomInt(350, 400),
+ fontFamily: 'helvetica',
+ angle: getRandomInt(-10, 10),
+ fill: '#' + getRandomColor(),
+ scaleX: 0.5,
+ scaleY: 0.5,
+ fontWeight: ''
+ });
+ canvas.add(textSample);
+ updateComplexity();
+ };
+
+
+ document.onkeydown = function(e) {
+ var obj = canvas.getActiveObject() || canvas.getActiveGroup();
+ if (obj && e.keyCode === 8) {
+ // this is horrible. need to fix, so that unified interface can be used
+ if (obj.type === 'group') {
+ // var groupObjects = obj.getObjects();
+ // canvas.discardActiveGroup();
+ // groupObjects.forEach(function(obj) {
+ // canvas.remove(obj);
+ // });
+ }
+ else {
+ //canvas.remove(obj);
+ }
+ canvas.renderAll();
+ // return false;
+ }
+ };
+
+ setTimeout(function() {
+ canvas.calcOffset();
+ }, 100);
+
+ if (document.location.search.indexOf('guidelines') > -1) {
+ initCenteringGuidelines(canvas);
+ initAligningGuidelines(canvas);
+ }
+
+ gradientifyBtn.onclick = function() {
+ var obj = canvas.getActiveObject();
+ if (obj) {
+ obj.setGradientFill({
+ x2: (getRandomInt(0, 1) ? 0 : obj.width),
+ y2: (getRandomInt(0, 1) ? 0 : obj.height),
+ colorStops: {
+ 0: '#' + getRandomColor(),
+ 1: '#' + getRandomColor()
+ }
+ });
+ canvas.renderAll();
+ }
+ };
+
+ var textEl = document.getElementById('text');
+ if (textEl) {
+ textEl.onfocus = function() {
+ var activeObject = canvas.getActiveObject();
+
+ if (activeObject && activeObject.type === 'text') {
+ this.value = (activeObject).text;
+ }
+ };
+ textEl.onkeyup = function(e) {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject) {
+ if (!this.value) {
+ canvas.discardActiveObject();
+ }
+ else {
+ (activeObject).text = this.value;
+ }
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdUnderlineBtn = document.getElementById('text-cmd-underline');
+ if (cmdUnderlineBtn) {
+ activeObjectButtons.push(cmdUnderlineBtn);
+ cmdUnderlineBtn.disabled = true;
+ cmdUnderlineBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.textDecoration = (activeObject.textDecoration == 'underline' ? '' : 'underline');
+ this.className = activeObject.textDecoration ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdLinethroughBtn = document.getElementById('text-cmd-linethrough');
+ if (cmdLinethroughBtn) {
+ activeObjectButtons.push(cmdLinethroughBtn);
+ cmdLinethroughBtn.disabled = true;
+ cmdLinethroughBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.textDecoration = (activeObject.textDecoration == 'line-through' ? '' : 'line-through');
+ this.className = activeObject.textDecoration ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdOverlineBtn = document.getElementById('text-cmd-overline');
+ if (cmdOverlineBtn) {
+ activeObjectButtons.push(cmdOverlineBtn);
+ cmdOverlineBtn.disabled = true;
+ cmdOverlineBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.textDecoration = (activeObject.textDecoration == 'overline' ? '' : 'overline');
+ this.className = activeObject.textDecoration ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdBoldBtn = document.getElementById('text-cmd-bold');
+ if (cmdBoldBtn) {
+ activeObjectButtons.push(cmdBoldBtn);
+ cmdBoldBtn.disabled = true;
+ cmdBoldBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.fontWeight = (activeObject.fontWeight == 'bold' ? '' : 'bold');
+ this.className = activeObject.fontWeight ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdItalicBtn = document.getElementById('text-cmd-italic');
+ if (cmdItalicBtn) {
+ activeObjectButtons.push(cmdItalicBtn);
+ cmdItalicBtn.disabled = true;
+ cmdItalicBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.fontStyle = (activeObject.fontStyle == 'italic' ? '' : 'italic');
+ this.className = activeObject.fontStyle ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var cmdShadowBtn = document.getElementById('text-cmd-shadow');
+ if (cmdShadowBtn) {
+ activeObjectButtons.push(cmdShadowBtn);
+ cmdShadowBtn.disabled = true;
+ cmdShadowBtn.onclick = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.textShadow = !activeObject.textShadow ? 'rgba(0,0,0,0.2) 2px 2px 10px' : '';
+ this.className = activeObject.textShadow ? 'selected' : '';
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var textAlignSwitch = document.getElementById('text-align');
+ if (textAlignSwitch) {
+ activeObjectButtons.push(textAlignSwitch);
+ textAlignSwitch.disabled = true;
+ textAlignSwitch.onchange = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.textAlign = this.value.toLowerCase();
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var fontFamilySwitch = document.getElementById('font-family');
+ if (fontFamilySwitch) {
+ activeObjectButtons.push(fontFamilySwitch);
+ fontFamilySwitch.disabled = true;
+ fontFamilySwitch.onchange = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.fontFamily = this.value;
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var bgColorField = document.getElementById('text-bg-color');
+ if (bgColorField) {
+ bgColorField.onchange = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.backgroundColor = this.value;
+ canvas.renderAll();
+ }
+ };
+ }
+
+ var strokeColorField = document.getElementById('text-stroke-color');
+ if (strokeColorField) {
+ strokeColorField.onchange = function() {
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.strokeStyle = this.value;
+ canvas.renderAll();
+ }
+ };
+ }
+
+ if (supportsSlider) {
+ (function(){
+ var container = document.getElementById('text-controls');
+ var slider = document.createElement('input');
+ var label = document.createElement('label');
+ label.innerHTML = 'Line height: ';
+ try { slider.type = 'range'; } catch(err) { }
+ slider.min = "0";
+ slider.max = "10";
+ slider.step = "0.1";
+ slider.value = "1.5";
+ container.appendChild(label);
+ label.appendChild(slider);
+ slider.title = "Line height";
+ slider.onchange = function(){
+ var activeObject = canvas.getActiveObject();
+ if (activeObject && activeObject.type === 'text') {
+ activeObject.lineHeight = this.value;
+ canvas.renderAll();
+ }
+ };
+
+ canvas.on('object:selected', function(e) {
+ slider.value = e.target.lineHeight;
+ });
+ })();
+ }
+
+ document.getElementById('load-svg').onclick = function() {
+ var svg = (document.getElementById('svg-console')).value;
+ fabric.loadSVGFromString(svg, function(objects, options) {
+ var obj = fabric.util.groupSVGElements(objects, options);
+ canvas.add(obj).centerObject(obj).renderAll();
+ obj.setCoords();
+ });
+ };
+
+ if (typeof Cufon !== 'undefined') {
+ Cufon.fonts.delicious.offsetLeft = 75;
+ Cufon.fonts.delicious.offsetTop = 25;
+ }
\ No newline at end of file