Last active
June 15, 2021 18:33
-
-
Save clouddueling/8475865 to your computer and use it in GitHub Desktop.
common.fabric module for angular/common
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* http://fabricjs.com/js/kitchensink/controller.js | |
* http://fabricjs.com/js/kitchensink/utils.js | |
* http://fabricjs.com/js/kitchensink/app_config.js | |
* http://fabricjs.com/events/ | |
* view-source:http://fabricjs.com/kitchensink/ | |
*/ | |
(function() { | |
'use strict'; | |
function capitalize(string) { | |
return string.charAt(0).toUpperCase() + string.slice(1); | |
} | |
angular.module('common.fabric', []) | |
.factory('FabricService', [function() { | |
var multiplier = 2; | |
var self = {}; | |
function update() { | |
if (!self.canvas) { | |
return; | |
} | |
self.canvas.fire('canvas:modified'); | |
self.canvas.renderAll(); | |
} | |
function getActiveStyle(styleName, object) { | |
if (!self.canvas) { | |
return; | |
} | |
object = object || self.canvas.getActiveObject(); | |
if (!object) { | |
return; | |
} | |
return (object.getSelectionStyles && object.isEditing) | |
? (object.getSelectionStyles()[styleName] || '') | |
: (object[styleName] || ''); | |
} | |
function setActiveStyle(styleName, value, object) { | |
if (!self.canvas) { | |
return; | |
} | |
object = object || self.canvas.getActiveObject(); | |
if (!object) { | |
return; | |
} | |
if (object.setSelectionStyles && object.isEditing) { | |
var style = { }; | |
style[styleName] = value; | |
object.setSelectionStyles(style); | |
object.setCoords(); | |
} | |
else { | |
object[styleName] = value; | |
} | |
object.setCoords(); | |
update(); | |
self.canvas.renderAll(); | |
} | |
function getActiveProp(name) { | |
if (!self.canvas) { | |
return; | |
} | |
var object = self.canvas.getActiveObject(); | |
if (!object) { | |
return; | |
} | |
return object[name] || ''; | |
} | |
function setActiveProp(name, value) { | |
var object = self.canvas.getActiveObject(); | |
if (!object) { | |
return; | |
} | |
object.set(name, value).setCoords(); | |
update(); | |
self.canvas.renderAll(); | |
} | |
self.canvas = undefined; | |
self.rotatingPointOffset = 20; | |
self.element = {}; | |
self.canvasId = 'fabric-' + Math.floor(Math.random() * 10000000); | |
self.init = function(json) { | |
self.element.attr('id', self.canvasId); | |
self.canvas = new fabric.Canvas(self.canvasId); | |
}; | |
self.loadJson = function(json) { | |
self.canvas.loadFromJSON(json, self.canvas.renderAll(self.canvas)); | |
}; | |
self.addShape = function(shapePath) { | |
fabric.loadSVGFromURL(shapePath, function(objects, options) { | |
var object = fabric.util.groupSVGElements(objects, options); | |
object.top = 20; | |
object.left = 20; | |
object.angle = 0; | |
object.opacity = 100; | |
object.rotatingPointOffset = self.rotatingPointOffset; | |
object.padding = 5; | |
object.borderColor = 'EEF6FC'; | |
object.cornerColor = 'rgba(64, 159, 221, .3)'; | |
object.cornerSize = 8; | |
object.transparentCorners = false; | |
if (object.isSameColor && object.isSameColor() || !object.paths) { | |
object.setFill('#0088cc'); | |
} else if (object.paths) { | |
for (var i = 0; i < object.paths.length; i++) { | |
object.paths[i].setFill('#0088cc'); | |
} | |
} | |
self.canvas.add(object); | |
object.active = true; | |
object.bringToFront(); | |
}); | |
}; | |
self.addImage = function(image) { | |
fabric.Image.fromURL(image, function (object) { | |
object.top = 20; | |
object.left = 20; | |
object.rotatingPointOffset = self.rotatingPointOffset; | |
object.padding = 5; | |
object.borderColor = 'EEF6FC'; | |
object.cornerColor = 'rgba(64, 159, 221, .3)'; | |
object.cornerSize = 8; | |
object.transparentCorners = false; | |
self.canvas.add(object); | |
object.active = true; | |
object.bringToFront(); | |
}); | |
}; | |
self.addText = function(str) { | |
str = str || "New Text"; | |
var text = new fabric.Text(str, { | |
left: 20, | |
top: 20, | |
color: '#454545', | |
fontFamily: 'Open Sans', | |
fontWeight: '', | |
textDecoration: '', | |
fontStyle: '', | |
textAlign: 'center', | |
fontSize: '40', | |
rotatingPointOffset: self.rotatingPointOffset, | |
angle: 0, | |
padding: 5, | |
borderColor: 'EEF6FC', | |
cornerColor: 'rgba(64, 159, 221, .3)', | |
cornerSize: 8, | |
transparentCorners: false, | |
hasRotatingPoint: true, | |
centerTransform: true | |
}); | |
self.canvas.add(text); | |
text.active = true; | |
text.bringToFront(); | |
}; | |
self.setBackgroundColor = function(color) { | |
self.canvas.setBackgroundColor(color); | |
update(); | |
}; | |
self.setWidth = function(width) { | |
self.canvas.setWidth(width); | |
update(); | |
}; | |
self.setHeight = function(height) { | |
self.canvas.setHeight(height); | |
update(); | |
}; | |
self.clearCanvas = function() { | |
self.canvas.clear(); | |
self.canvas.setBackgroundColor('ffffff'); | |
update(); | |
}; | |
self.deselectActiveObject = function() { | |
var object = self.canvas.getActiveObject(); | |
if (object) { | |
object.active = false; | |
} | |
}; | |
self.deactivateAll = function() { | |
self.canvas.deactivateAll().renderAll(); | |
}; | |
self.getCanvasData = function() { | |
var data = self.canvas.toDataURL({ | |
width: self.canvas.getWidth(), | |
height: self.canvas.getHeight(), | |
multiplier: multiplier | |
}); | |
return data; | |
}; | |
self.download = function() { | |
// If there is a focused object deselect it and after the download is initialized reselct it. | |
var object = self.canvas.getActiveObject(); | |
self.deselectActiveObject(); | |
// If zoom is less than 1 a small version is created with a lot of white space. | |
var data = self.getCanvasData().replace("image/png", "image/octet-stream"); | |
var filename = 'Untitled Image.png'; | |
var link = document.createElement('a'); | |
link.download = filename; | |
link.href = data; | |
link.click(); | |
if (object) { | |
object.active = true; | |
} | |
}; | |
self.removeSelected = function() { | |
var activeObject = self.canvas.getActiveObject(), | |
activeGroup = self.canvas.getActiveGroup(); | |
if (activeGroup) { | |
var objectsInGroup = activeGroup.getObjects(); | |
self.canvas.discardActiveGroup(); | |
objectsInGroup.forEach(function(object) { | |
self.canvas.remove(object); | |
}); | |
} else if (activeObject) { | |
self.canvas.remove(activeObject); | |
} | |
}; | |
self.getType = function() { | |
return getActiveProp('type'); | |
}; | |
self.getOpacity = function() { | |
return getActiveStyle('opacity') * 100; | |
}; | |
self.setOpacity = function(value) { | |
setActiveStyle('opacity', parseInt(value, 10) / 100); | |
}; | |
self.getFill = function() { | |
return getActiveStyle('fill'); | |
}; | |
self.setFill = function(value) { | |
if (! self.canvas) { | |
return; | |
} | |
// Yes this looks like shit but it works for text and uploaded shapes who both use the same prop. | |
var object = self.canvas.getActiveObject(); | |
if (object) { | |
if (object.type === 'text') { | |
setActiveStyle('fill', value); | |
} else { | |
if (object.isSameColor && object.isSameColor() || !object.paths) { | |
object.setFill(value); | |
} else if (object.paths) { | |
for (var i = 0; i < object.paths.length; i++) { | |
object.paths[i].setFill(value); | |
} | |
} | |
self.canvas.renderAll(); | |
} | |
} | |
}; | |
self.isBold = function() { | |
return getActiveStyle('fontWeight') === 'bold'; | |
}; | |
self.toggleBold = function() { | |
setActiveStyle('fontWeight', | |
getActiveStyle('fontWeight') === 'bold' ? '' : 'bold'); | |
}; | |
self.isItalic = function() { | |
return getActiveStyle('fontStyle') === 'italic'; | |
}; | |
self.toggleItalic = function() { | |
setActiveStyle('fontStyle', | |
getActiveStyle('fontStyle') === 'italic' ? '' : 'italic'); | |
}; | |
self.isUnderline = function() { | |
return getActiveStyle('textDecoration').indexOf('underline') > -1; | |
}; | |
self.toggleUnderline = function() { | |
var value = self.isUnderline() | |
? getActiveStyle('textDecoration').replace('underline', '') | |
: (getActiveStyle('textDecoration') + ' underline'); | |
setActiveStyle('textDecoration', value); | |
}; | |
self.isLinethrough = function() { | |
return getActiveStyle('textDecoration').indexOf('line-through') > -1; | |
}; | |
self.toggleLinethrough = function() { | |
var value = self.isLinethrough() | |
? getActiveStyle('textDecoration').replace('line-through', '') | |
: (getActiveStyle('textDecoration') + ' line-through'); | |
setActiveStyle('textDecoration', value); | |
}; | |
self.isOverline = function() { | |
return getActiveStyle('textDecoration').indexOf('overline') > -1; | |
}; | |
self.toggleOverline = function() { | |
var value = self.isOverline() | |
? getActiveStyle('textDecoration').replace('overline', '') | |
: (getActiveStyle('textDecoration') + ' overline'); | |
setActiveStyle('textDecoration', value); | |
}; | |
self.getText = function() { | |
return getActiveProp('text'); | |
}; | |
self.setText = function(value) { | |
setActiveProp('text', value); | |
}; | |
self.getTextAlign = function() { | |
return capitalize(getActiveProp('textAlign')); | |
}; | |
self.setTextAlign = function(value) { | |
setActiveProp('textAlign', value.toLowerCase()); | |
}; | |
self.getFontFamilygetStrokeColor = function() { | |
return getActiveProp('fontFamily').toLowerCase(); | |
}; | |
self.setFontFamily = function(value) { | |
setActiveProp('fontFamily', value.toLowerCase()); | |
}; | |
self.getBgColor = function() { | |
return getActiveProp('backgroundColor'); | |
}; | |
self.setBgColor = function(value) { | |
setActiveProp('backgroundColor', value); | |
}; | |
self.getFlipX = function() { | |
return getActiveProp('flipX'); | |
}; | |
self.setFlipX = function(value) { | |
setActiveProp('flipX', value); | |
}; | |
self.toggleFlipX = function() { | |
var value = self.getFlipX() ? false : true; | |
self.setFlipX(value); | |
}; | |
self.getTextBgColor = function() { | |
return getActiveProp('textBackgroundColor'); | |
}; | |
self.setTextBgColor = function(value) { | |
setActiveProp('textBackgroundColor', value); | |
}; | |
self.getStrokeColor = function() { | |
return getActiveStyle('stroke'); | |
}; | |
self.setStrokeColor = function(value) { | |
setActiveStyle('stroke', value); | |
}; | |
self.getStrokeWidth = function() { | |
return getActiveStyle('strokeWidth'); | |
}; | |
self.setStrokeWidth = function(value) { | |
setActiveStyle('strokeWidth', parseInt(value, 10)); | |
}; | |
self.getFontSize = function() { | |
return getActiveStyle('fontSize'); | |
}; | |
self.setFontSize = function(value) { | |
setActiveStyle('fontSize', parseInt(value, 10)); | |
}; | |
self.getLineHeight = function() { | |
return getActiveStyle('lineHeight'); | |
}; | |
self.setLineHeight = function(value) { | |
setActiveStyle('lineHeight', parseFloat(value, 10)); | |
}; | |
self.getBold = function() { | |
return getActiveStyle('fontWeight'); | |
}; | |
self.setBold = function(value) { | |
setActiveStyle('fontWeight', value ? 'bold' : ''); | |
}; | |
self.getCanvasBgColor = function() { | |
return self.canvas.backgroundColor; | |
}; | |
self.setCanvasBgColor = function(value) { | |
self.canvas.backgroundColor = value; | |
self.canvas.renderAll(); | |
}; | |
self.sendBackwards = function() { | |
var activeObject = self.canvas.getActiveObject(); | |
if (activeObject) { | |
self.canvas.sendBackwards(activeObject); | |
} | |
}; | |
self.sendToBack = function() { | |
var activeObject = self.canvas.getActiveObject(); | |
if (activeObject) { | |
self.canvas.sendToBack(activeObject); | |
} | |
}; | |
self.bringForward = function() { | |
var activeObject = self.canvas.getActiveObject(); | |
if (activeObject) { | |
self.canvas.bringForward(activeObject); | |
} | |
}; | |
self.bringToFront = function() { | |
var activeObject = self.canvas.getActiveObject(); | |
if (activeObject) { | |
self.canvas.bringToFront(activeObject); | |
} | |
}; | |
self.loadJson = function(json) { | |
self.canvas.loadFromJSON(json); | |
var obj = angular.fromJson(json); | |
self.setWidth(obj.width); | |
self.setHeight(obj.height); | |
}; | |
return self; | |
}]) | |
.directive('fabric', ['FabricService', '$timeout', function(FabricService, $timeout) { | |
return { | |
scope: { | |
ngModel: '=', | |
ngChange: '&' | |
}, | |
link: function(scope, element) { | |
fabric.Object.prototype.transparentCorners = false; | |
function update() { | |
$timeout(function() { | |
scope.ngModel = FabricService.canvas.toJSON(['height', 'width', 'backgroundColor']); | |
scope.ngChange(); | |
}); | |
} | |
function initCanvas() { | |
FabricService.element = element; | |
FabricService.init(scope.ngModel); | |
} | |
function initListeners() { | |
FabricService.canvas.on('canvas:modified', function(options) { | |
update(); | |
}); | |
FabricService.canvas.on('object:modified', function(options) { | |
FabricService.canvas.renderAll(); | |
update(); | |
}); | |
FabricService.canvas.on("object:selected", function(){ | |
$timeout(function() { | |
update(); | |
}); | |
}); | |
FabricService.canvas.on("selection:cleared", function(){ | |
$timeout(function() { | |
scope.fabricActiveObject = undefined; | |
}); | |
}); | |
FabricService.canvas.on("after:render", function(){ | |
FabricService.canvas.calcOffset(); | |
}); | |
} | |
initCanvas(); | |
initListeners(); | |
} | |
}; | |
}]) | |
.directive('fabricValue', ['FabricService', function(FabricService) { | |
return { | |
restrict: 'A', | |
link: function ($scope, $element, $attrs) { | |
var prop = capitalize($attrs.fabricValue), | |
getter = 'get' + prop, | |
setter = 'set' + prop; | |
$element.on('change keyup select', function() { | |
FabricService[setter] && FabricService[setter](this.value); | |
FabricService.canvas.fire('canvas:modified'); | |
}); | |
$scope.$watch(FabricService[getter], function(newVal) { | |
if (!FabricService.canvas) { | |
return; | |
} | |
if ($element[0].type === 'radio') { | |
var radioGroup = document.getElementsByName($element[0].name); | |
for (var i = 0, len = radioGroup.length; i < len; i++) { | |
radioGroup[i].checked = radioGroup[i].value === newVal; | |
} | |
} else { | |
$element.val(newVal); | |
} | |
FabricService.canvas.fire('canvas:modified'); | |
}); | |
} | |
}; | |
}]); | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
'use strict'; | |
angular.module('builders.images', []) | |
.factory('ImagesService', [function() { | |
var self = {}; | |
self.exampleSizes = [ | |
{ | |
name: 'Paper (8.5 x 11)', | |
height: 1100, | |
width: 850 | |
}, | |
{ | |
name: 'Paper (11 x 8.5)', | |
height: 850, | |
width: 1100 | |
}, | |
{ | |
name: 'Business Card (3.5 x 2)', | |
height: 440, | |
width: 770 | |
}, | |
{ | |
name: 'Postcard (6 x 4)', | |
height: 570, | |
width: 855 | |
}, | |
{ | |
name: 'Content/Builder Product Thumbnail', | |
height: 400, | |
width: 760 | |
}, | |
{ | |
name: 'Badge', | |
height: 400, | |
width: 400 | |
} | |
]; | |
self.fonts = [ | |
{ name: 'Sonsie One' }, | |
{ name: 'Croissant One' }, | |
{ name: 'Graduate' }, | |
{ name: 'Open Sans' }, | |
{ name: 'Krona One' }, | |
{ name: 'Mouse Memoirs' }, | |
{ name: 'Stoke' }, | |
{ name: 'Indie Flower' }, | |
{ name: 'Ribeye Marrow' }, | |
{ name: 'Courgette' }, | |
{ name: 'Gruppo' }, | |
{ name: 'Ranchers' } | |
]; | |
self.imageHandle = { | |
step: 'previous' | |
}; | |
self.shapeCategories = [ | |
{ | |
name: "Popular Shapes", | |
shapes: [ | |
'arrow6', | |
'bubble3', | |
'checkmark1', | |
'circle1', | |
'rectangle1', | |
'star1', | |
'triangle1', | |
'arrow7' | |
] | |
}, | |
{ | |
name: "Simple Shapes", | |
shapes: [ | |
'circle1', | |
'heart1', | |
'rectangle1', | |
'triangle1', | |
'star1', | |
'star2', | |
'star3', | |
'star4' | |
] | |
}, | |
{ | |
name: "Arrows & Pointers", | |
shapes: [ | |
'arrow1', | |
'arrow2', | |
'arrow3', | |
'arrow4', | |
'arrow6', | |
'arrow7', | |
'arrow8' | |
] | |
}, | |
{ | |
name: "Bubbles & Balloons", | |
shapes: [ | |
'bubble2', | |
'bubble3' | |
] | |
}, | |
{ | |
name: "Check Marks", | |
shapes: [ | |
'checkmark1' | |
] | |
} | |
]; | |
return self; | |
}]) | |
.controller('ImagesCtrl', ['$scope', 'ImagesService', 'FabricService', 'Page', 'Modal', function($scope, ImagesService, FabricService, Page, Modal) { | |
var handle; | |
$scope.ImagesService = ImagesService; | |
$scope.FabricService = FabricService; | |
$scope.updatePage = function(page) { | |
$scope.$timeout.cancel(handle); | |
handle = $scope.$timeout(function() { | |
Page.update(page.id, { | |
name: page.name, | |
json: page.json | |
}); | |
}, 500); | |
}; | |
$scope.loadPage = function(pageId) { | |
if (!pageId) { | |
return; | |
} | |
Page.load(pageId).success(function(data) { | |
$scope.page = data.page; | |
$scope.pageId = data.page.id; | |
var obj = angular.fromJson(data.page.json); | |
$scope.page.width = obj.width; | |
$scope.page.height = obj.height; | |
FabricService.loadJson(data.page.json); | |
}); | |
}; | |
$scope.createPage = function(cardId) { | |
Page.create({ | |
card_id: cardId | |
}).success(function(data) { | |
$scope.card.pages.push(data.page); | |
$scope.loadPage(data.page.id); | |
}); | |
}; | |
$scope.deletePage = function(pageId) { | |
Page.delete(pageId).success(function() { | |
$scope.card.pages = _.reject($scope.card.pages, function(page) { | |
return page.id === pageId; | |
}); | |
$scope.loadFirstPage(); | |
}); | |
}; | |
$scope.loadFirstPage = function() { | |
if ($scope.card.pages.length === 0) { | |
return; | |
} | |
$scope.pageId = $scope.card.pages[0].id; | |
$scope.loadPage($scope.pageId); | |
}; | |
$scope.updatePageOrder = function() { | |
var pageIds = _.pluck($scope.card.pages, 'id'); | |
$scope.Card.updatePageOrder($scope.card.id, { | |
page_ids: pageIds | |
}); | |
}; | |
$scope.addUploadedImage = function(requestText) { | |
var obj = angular.fromJson(requestText); | |
FabricService.addImage('/image?image=' + obj.filename + '&size=2000'); | |
Modal.close(); | |
}; | |
$scope.addShape = function(shape) { | |
FabricService.addShape('/lib/svg/' + shape + '.svg'); | |
Modal.close(); | |
}; | |
$scope.loadUploads = function() { | |
}; | |
ImagesService.selectedShapeCategory = ImagesService.shapeCategories[0]; | |
$scope.loadFirstPage(); | |
}]); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment