├── .DS_Store ├── Examples ├── .DS_Store ├── AppleWatchActivities.framer │ ├── .gitignore │ ├── app.coffee │ ├── framer │ │ ├── .bookmark │ │ ├── coffee-script.js │ │ ├── config.json │ │ ├── design.vekter │ │ ├── framer.generated.js │ │ ├── framer.init.js │ │ ├── framer.js │ │ ├── framer.js.map │ │ ├── framer.modules.js │ │ ├── framer.vekter.js │ │ ├── images │ │ │ ├── cursor-active.png │ │ │ ├── cursor-active@2x.png │ │ │ ├── cursor.png │ │ │ ├── cursor@2x.png │ │ │ ├── icon-120.png │ │ │ ├── icon-152.png │ │ │ ├── icon-180.png │ │ │ ├── icon-192.png │ │ │ └── icon-76.png │ │ ├── style.css │ │ └── version │ ├── images │ │ └── .gitkeep │ ├── index.html │ └── modules │ │ └── circleModule.coffee └── Countdown.framer │ ├── .gitignore │ ├── app.coffee │ ├── framer │ ├── .bookmark │ ├── coffee-script.js │ ├── config.json │ ├── design.vekter │ ├── framer.generated.js │ ├── framer.init.js │ ├── framer.js │ ├── framer.js.map │ ├── framer.modules.js │ ├── framer.vekter.js │ ├── images │ │ ├── cursor-active.png │ │ ├── cursor-active@2x.png │ │ ├── cursor.png │ │ ├── cursor@2x.png │ │ ├── icon-120.png │ │ ├── icon-152.png │ │ ├── icon-180.png │ │ ├── icon-192.png │ │ └── icon-76.png │ ├── style.css │ └── version │ ├── images │ └── .gitkeep │ ├── index.html │ └── modules │ └── circleModule.coffee ├── README.md ├── applewatchactivities.gif ├── circleModule.coffee └── countdown.gif /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/.DS_Store -------------------------------------------------------------------------------- /Examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/.DS_Store -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | framer/*.old* 33 | framer/.*.hash 34 | framer/backup.coffee 35 | framer/backups/* 36 | framer/manifest.txt 37 | framer/metadata.json 38 | framer/preview.png 39 | framer/social-880x460.png 40 | framer/social-1200x630.png 41 | -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/app.coffee: -------------------------------------------------------------------------------- 1 | # Project Info 2 | # This info is presented in a widget when you share. 3 | # http://framerjs.com/docs/#info.info 4 | 5 | Framer.Info = 6 | title: "Apple Watch Activities" 7 | author: "Jonathan Arnold" 8 | twitter: "@servusjon" 9 | description: "Build with SVGCircle Module. Learn more: https://github.com/ServusJon/SVGCircle-Module-for-FramerJS" 10 | 11 | {Circle} = require "circleModule" 12 | 13 | padding = 20 14 | 15 | loadingCircle = new Circle 16 | circleSize: 300 17 | topColor: "#ff150f" 18 | bottomColor: "#ff23bd" 19 | strokeWidth: 40 20 | # hasLinearEasing: true 21 | loadingCircle.center() 22 | 23 | loadingCircle2 = new Circle 24 | circleSize: 220 - padding 25 | strokeWidth: 40 26 | topColor: "#7cc201" 27 | bottomColor: "#a3fe00" 28 | loadingCircle2.center() 29 | 30 | loadingCircle3 = new Circle 31 | circleSize: 140 - padding * 2 32 | strokeWidth: 40 33 | topColor: "#1baca6" 34 | bottomColor: "#18e1e9" 35 | loadingCircle3.center() 36 | 37 | loadingCircle.changeTo(80, 2) 38 | loadingCircle2.changeTo(60, 2) 39 | loadingCircle3.changeTo(30, 2) 40 | -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/.bookmark -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 0, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 0, 8 | "deviceType" : "fullscreen", 9 | "sharedPrototype" : 0, 10 | "propertyPanelToggleStates" : { 11 | 12 | }, 13 | "projectId" : "5916C71F-6B6D-4A4A-8AA2-A984D21C7925", 14 | "deviceOrientation" : 0, 15 | "selectedHand" : "", 16 | "showBezel" : 0, 17 | "foldedCodeRanges" : [ 18 | "{107, 213}" 19 | ], 20 | "deviceScale" : 1 21 | } -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/design.vekter: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 20, 3 | "root" : { 4 | "id" : "tB0fhMSIV", 5 | "__class" : "CanvasNode", 6 | "parentid" : null, 7 | "children" : [ 8 | 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":1,"selectedHand":"","deviceType":"fullscreen","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":1,"selectedHand":"","deviceType":"fullscreen","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"AppleWatchActivities.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/framer.modules.js: -------------------------------------------------------------------------------- 1 | require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\n \n \n \n \n \n \n \n"; 80 | self = this; 81 | Utils.domComplete(function() { 82 | return self.path = document.querySelector("#" + self.circleID); 83 | }); 84 | this.proxy = new Layer({ 85 | opacity: 0, 86 | name: "circuleModuleProxy" 87 | }); 88 | this.proxy.sendToBack(); 89 | this.proxy.on(Events.AnimationEnd, function(animation, layer) { 90 | return self.onFinished(); 91 | }); 92 | this.proxy.on('change:x', function() { 93 | var offset; 94 | offset = Utils.modulate(this.x, [0, 500], [self.pathLength, 0]); 95 | self.path.setAttribute('stroke-dashoffset', offset); 96 | if (self.options.hasCounter !== null) { 97 | numberNow = Utils.round(self.proxy.x / 5); 98 | return counter.html = numberNow; 99 | } 100 | }); 101 | Utils.domComplete(function() { 102 | return self.proxy.x = 0.1; 103 | }); 104 | } 105 | 106 | Circle.prototype.changeTo = function(value, time) { 107 | var customCurve; 108 | if (time === void 0) { 109 | time = 2; 110 | } 111 | if (this.options.hasLinearEasing === true) { 112 | customCurve = "linear"; 113 | } else { 114 | customCurve = "ease-in-out"; 115 | } 116 | this.proxy.animate({ 117 | properties: { 118 | x: 500 * (value / 100) 119 | }, 120 | time: time, 121 | curve: customCurve 122 | }); 123 | return this.currentValue = value; 124 | }; 125 | 126 | Circle.prototype.startAt = function(value) { 127 | this.proxy.animate({ 128 | properties: { 129 | x: 500 * (value / 100) 130 | }, 131 | time: 0.001 132 | }); 133 | return this.currentValue = value; 134 | }; 135 | 136 | Circle.prototype.hide = function() { 137 | return this.opacity = 0; 138 | }; 139 | 140 | Circle.prototype.show = function() { 141 | return this.opacity = 1; 142 | }; 143 | 144 | Circle.prototype.onFinished = function() {}; 145 | 146 | return Circle; 147 | 148 | })(Layer); 149 | 150 | 151 | },{}]},{},[]) 152 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWVyLm1vZHVsZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL1VzZXJzL0pvbmF0aGFuLkFybm9sZC9EZXNrdG9wL2dpdGh1Yi9TVkdDaXJjbGUtTW9kdWxlLWZvci1GcmFtZXJKUy9FeGFtcGxlcy9BcHBsZVdhdGNoQWN0aXZpdGllcy5mcmFtZXIvbW9kdWxlcy9jaXJjbGVNb2R1bGUuY29mZmVlIiwibm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjbGFzcyBleHBvcnRzLkNpcmNsZSBleHRlbmRzIExheWVyXG5cdGN1cnJlbnRWYWx1ZTogbnVsbFxuXG5cdGNvbnN0cnVjdG9yOiAoQG9wdGlvbnM9e30pIC0+XG5cblx0XHRAb3B0aW9ucy5jaXJjbGVTaXplID89IDMwMFxuXHRcdEBvcHRpb25zLnN0cm9rZVdpZHRoID89IDI0XG5cdFx0QG9wdGlvbnMubGluZWNhcCA/PSBcInJvdW5kXCJcblxuXHRcdEBvcHRpb25zLnN0cm9rZUNvbG9yID89IFwiI2ZjMjQ1Y1wiXG5cdFx0QG9wdGlvbnMudG9wQ29sb3IgPz0gbnVsbFxuXHRcdEBvcHRpb25zLmJvdHRvbUNvbG9yID89IG51bGxcblxuXHRcdEBvcHRpb25zLmhhc0NvdW50ZXIgPz0gbnVsbFxuXHRcdEBvcHRpb25zLmNvdW50ZXJDb2xvciA/PSBcIiNmZmZcIlxuXHRcdEBvcHRpb25zLmNvdW50ZXJGb250U2l6ZSA/PSA2MFxuXHRcdEBvcHRpb25zLmhhc0xpbmVhckVhc2luZyA/PSBmYWxzZVxuXG5cdFx0QG9wdGlvbnMudmFsdWUgPSAyXG5cblx0XHRAb3B0aW9ucy52aWV3Qm94ID0gKEBvcHRpb25zLmNpcmNsZVNpemUpICsgQG9wdGlvbnMuc3Ryb2tlV2lkdGhcblxuXHRcdHN1cGVyIEBvcHRpb25zXG5cblx0XHRALmJhY2tncm91bmRDb2xvciA9IFwiXCJcblx0XHRALmhlaWdodCA9IEBvcHRpb25zLnZpZXdCb3hcblx0XHRALndpZHRoID0gQG9wdGlvbnMudmlld0JveFxuXHRcdEAucm90YXRpb24gPSAtOTBcblxuXG5cdFx0QC5wYXRoTGVuZ3RoID0gTWF0aC5QSSAqIEBvcHRpb25zLmNpcmNsZVNpemVcblxuXHRcdEAuY2lyY2xlSUQgPSBcImNpcmNsZVwiICsgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKjEwMDApXG5cdFx0QC5ncmFkaWVudElEID0gXCJjaXJjbGVcIiArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSoxMDAwKVxuXG5cdFx0IyBQdXQgdGhpcyBpbnNpZGUgbGluZWFyZ3JhZGllbnRcblx0XHQjIGdyYWRpZW50VW5pdHM9XCJ1c2VyU3BhY2VPblVzZVwiXG5cdFx0IyAgICB4MT1cIjAlXCIgeTE9XCIwJVwiIHgyPVwiNTAlXCIgeTI9XCIwJVwiIGdyYWRpZW50VHJhbnNmb3JtPVwicm90YXRlKDEyMClcIlxuXG5cblx0XHRpZiBAb3B0aW9ucy5oYXNDb3VudGVyIGlzbnQgbnVsbFxuXHRcdFx0Y291bnRlciA9IG5ldyBMYXllclxuXHRcdFx0XHRwYXJlbnQ6IEBcblx0XHRcdFx0aHRtbDogXCJcIlxuXHRcdFx0XHR3aWR0aDogQC53aWR0aFxuXHRcdFx0XHRoZWlnaHQ6IEAuaGVpZ2h0XG5cdFx0XHRcdGJhY2tncm91bmRDb2xvcjogXCJcIlxuXHRcdFx0XHRyb3RhdGlvbjogOTBcblx0XHRcdFx0Y29sb3I6IEBvcHRpb25zLmNvdW50ZXJDb2xvclxuXG5cdFx0XHRzdHlsZSA9IHtcblx0XHRcdFx0dGV4dEFsaWduOiBcImNlbnRlclwiXG5cdFx0XHRcdGZvbnRTaXplOiBcIiN7QG9wdGlvbnMuY291bnRlckZvbnRTaXplfXB4XCJcblx0XHRcdFx0bGluZUhlaWdodDogXCIje0AuaGVpZ2h0fXB4XCJcblx0XHRcdFx0Zm9udFdlaWdodDogXCI2MDBcIlxuXHRcdFx0XHRmb250RmFtaWx5OiBcIi1hcHBsZS1zeXN0ZW0sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWZcIlxuXHRcdFx0XHRib3hTaXppbmc6IFwiYm9yZGVyLWJveFwiXG5cdFx0XHRcdGhlaWdodDogQC5oZWlnaHRcblx0XHRcdH1cblxuXHRcdFx0Y291bnRlci5zdHlsZSA9IHN0eWxlXG5cblx0XHRcdG51bWJlclN0YXJ0ID0gMFxuXHRcdFx0bnVtYmVyRW5kID0gMTAwXG5cdFx0XHRudW1iZXJEdXJhdGlvbiA9IDJcblxuXHRcdFx0bnVtYmVyTm93ID0gbnVtYmVyU3RhcnRcblx0XHRcdG51bWJlckludGVydmFsID0gbnVtYmVyRW5kIC0gbnVtYmVyU3RhcnRcblxuXG5cdFx0QC5odG1sID0gXCJcIlwiXG5cdFx0XHQ8c3ZnIHZpZXdCb3g9Jy0je0BvcHRpb25zLnN0cm9rZVdpZHRoLzJ9IC0je0BvcHRpb25zLnN0cm9rZVdpZHRoLzJ9ICN7QG9wdGlvbnMudmlld0JveH0gI3tAb3B0aW9ucy52aWV3Qm94fScgPlxuXHRcdFx0XHQ8ZGVmcz5cblx0XHRcdFx0ICAgIDxsaW5lYXJHcmFkaWVudCBpZD0nI3tAZ3JhZGllbnRJRH0nID5cblx0XHRcdFx0ICAgICAgICA8c3RvcCBvZmZzZXQ9XCIwJVwiIHN0b3AtY29sb3I9JyN7aWYgQG9wdGlvbnMudG9wQ29sb3IgaXNudCBudWxsIHRoZW4gQG9wdGlvbnMuYm90dG9tQ29sb3IgZWxzZSBAb3B0aW9ucy5zdHJva2VDb2xvcn0nLz5cblx0XHRcdFx0ICAgICAgICA8c3RvcCBvZmZzZXQ9XCIxMDAlXCIgc3RvcC1jb2xvcj0nI3tpZiBAb3B0aW9ucy50b3BDb2xvciBpc250IG51bGwgdGhlbiBAb3B0aW9ucy50b3BDb2xvciBlbHNlIEBvcHRpb25zLnN0cm9rZUNvbG9yfScgc3RvcC1vcGFjaXR5PVwiMVwiIC8+XG5cdFx0XHRcdCAgICA8L2xpbmVhckdyYWRpZW50PlxuXHRcdFx0XHQ8L2RlZnM+XG5cdFx0XHRcdDxjaXJjbGUgaWQ9JyN7QGNpcmNsZUlEfSdcblx0XHRcdFx0XHRcdGZpbGw9J25vbmUnXG5cdFx0XHRcdFx0XHRzdHJva2UtbGluZWNhcD0nI3tAb3B0aW9ucy5saW5lY2FwfSdcblx0XHRcdFx0XHRcdHN0cm9rZS13aWR0aCAgICAgID0gJyN7QG9wdGlvbnMuc3Ryb2tlV2lkdGh9J1xuXHRcdFx0XHRcdFx0c3Ryb2tlLWRhc2hhcnJheSAgPSAnI3tALnBhdGhMZW5ndGh9J1xuXHRcdFx0XHRcdFx0c3Ryb2tlLWRhc2hvZmZzZXQgPSAnMCdcblx0XHRcdFx0XHRcdHN0cm9rZT1cInVybCgjI3tAZ3JhZGllbnRJRH0pXCJcblx0XHRcdFx0XHRcdHN0cm9rZS13aWR0aD1cIjEwXCJcblx0XHRcdFx0XHRcdGN4ID0gJyN7QG9wdGlvbnMuY2lyY2xlU2l6ZS8yfSdcblx0XHRcdFx0XHRcdGN5ID0gJyN7QG9wdGlvbnMuY2lyY2xlU2l6ZS8yfSdcblx0XHRcdFx0XHRcdHIgID0gJyN7QG9wdGlvbnMuY2lyY2xlU2l6ZS8yfSc+XG5cdFx0XHQ8L3N2Zz5cIlwiXCJcblxuXHRcdHNlbGYgPSBAXG5cdFx0VXRpbHMuZG9tQ29tcGxldGUgLT5cblx0XHRcdHNlbGYucGF0aCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCIjI3tzZWxmLmNpcmNsZUlEfVwiKVxuXG5cdFx0QHByb3h5ID0gbmV3IExheWVyXG5cdFx0XHRvcGFjaXR5OiAwXG5cdFx0XHRuYW1lOiBcImNpcmN1bGVNb2R1bGVQcm94eVwiXG5cdFx0XHRcblx0XHRAcHJveHkuc2VuZFRvQmFjaygpXG5cblx0XHRAcHJveHkub24gRXZlbnRzLkFuaW1hdGlvbkVuZCwgKGFuaW1hdGlvbiwgbGF5ZXIpIC0+XG5cdFx0XHRzZWxmLm9uRmluaXNoZWQoKVxuXG5cdFx0QHByb3h5Lm9uICdjaGFuZ2U6eCcsIC0+XG5cblx0XHRcdG9mZnNldCA9IFV0aWxzLm1vZHVsYXRlKEAueCwgWzAsIDUwMF0sIFtzZWxmLnBhdGhMZW5ndGgsIDBdKVxuXG5cdFx0XHRzZWxmLnBhdGguc2V0QXR0cmlidXRlICdzdHJva2UtZGFzaG9mZnNldCcsIG9mZnNldFxuXG5cdFx0XHRpZiBzZWxmLm9wdGlvbnMuaGFzQ291bnRlciBpc250IG51bGxcblx0XHRcdFx0bnVtYmVyTm93ID0gVXRpbHMucm91bmQoc2VsZi5wcm94eS54IC8gNSlcblx0XHRcdFx0Y291bnRlci5odG1sID0gbnVtYmVyTm93XG5cblx0XHRVdGlscy5kb21Db21wbGV0ZSAtPlxuXHRcdFx0c2VsZi5wcm94eS54ID0gMC4xXG5cblx0Y2hhbmdlVG86ICh2YWx1ZSwgdGltZSkgLT5cblx0XHRpZiB0aW1lIGlzIHVuZGVmaW5lZFxuXHRcdFx0dGltZSA9IDJcblxuXHRcdGlmIEBvcHRpb25zLmhhc0xpbmVhckVhc2luZyBpcyB0cnVlXG5cdFx0XHRjdXN0b21DdXJ2ZSA9IFwibGluZWFyXCJcblx0XHRlbHNlXG5cdFx0XHRjdXN0b21DdXJ2ZSA9IFwiZWFzZS1pbi1vdXRcIlxuXG5cdFx0QHByb3h5LmFuaW1hdGVcblx0XHRcdHByb3BlcnRpZXM6XG5cdFx0XHRcdHg6IDUwMCAqICh2YWx1ZSAvIDEwMClcblx0XHRcdHRpbWU6IHRpbWVcblx0XHRcdGN1cnZlOiBjdXN0b21DdXJ2ZVxuXG5cdFx0QGN1cnJlbnRWYWx1ZSA9IHZhbHVlXG5cblx0c3RhcnRBdDogKHZhbHVlKSAtPlxuXHRcdEBwcm94eS5hbmltYXRlXG5cdFx0XHRwcm9wZXJ0aWVzOlxuXHRcdFx0XHR4OiA1MDAgKiAodmFsdWUgLyAxMDApXG5cdFx0XHR0aW1lOiAwLjAwMVxuXG5cdFx0QGN1cnJlbnRWYWx1ZSA9IHZhbHVlXG5cblxuXG5cdGhpZGU6IC0+XG5cdFx0QC5vcGFjaXR5ID0gMFxuXG5cdHNob3c6IC0+XG5cdFx0QC5vcGFjaXR5ID0gMVxuXG5cdG9uRmluaXNoZWQ6IC0+XG5cbiIsIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQ0FBO0FEQUEsSUFBQTs7O0FBQU0sT0FBTyxDQUFDOzs7bUJBQ2IsWUFBQSxHQUFjOztFQUVELGdCQUFDLE9BQUQ7QUFFWixRQUFBO0lBRmEsSUFBQyxDQUFBLDRCQUFELFVBQVM7O1VBRWQsQ0FBQyxhQUFjOzs7V0FDZixDQUFDLGNBQWU7OztXQUNoQixDQUFDLFVBQVc7OztXQUVaLENBQUMsY0FBZTs7O1dBQ2hCLENBQUMsV0FBWTs7O1dBQ2IsQ0FBQyxjQUFlOzs7V0FFaEIsQ0FBQyxhQUFjOzs7V0FDZixDQUFDLGVBQWdCOzs7V0FDakIsQ0FBQyxrQkFBbUI7OztXQUNwQixDQUFDLGtCQUFtQjs7SUFFNUIsSUFBQyxDQUFBLE9BQU8sQ0FBQyxLQUFULEdBQWlCO0lBRWpCLElBQUMsQ0FBQSxPQUFPLENBQUMsT0FBVCxHQUFvQixJQUFDLENBQUEsT0FBTyxDQUFDLFVBQVYsR0FBd0IsSUFBQyxDQUFBLE9BQU8sQ0FBQztJQUVwRCx3Q0FBTSxJQUFDLENBQUEsT0FBUDtJQUVBLElBQUMsQ0FBQyxlQUFGLEdBQW9CO0lBQ3BCLElBQUMsQ0FBQyxNQUFGLEdBQVcsSUFBQyxDQUFBLE9BQU8sQ0FBQztJQUNwQixJQUFDLENBQUMsS0FBRixHQUFVLElBQUMsQ0FBQSxPQUFPLENBQUM7SUFDbkIsSUFBQyxDQUFDLFFBQUYsR0FBYSxDQUFDO0lBR2QsSUFBQyxDQUFDLFVBQUYs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 153 | -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/framer/version: -------------------------------------------------------------------------------- 1 | 12 -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/AppleWatchActivities.framer/images/.gitkeep -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Examples/AppleWatchActivities.framer/modules/circleModule.coffee: -------------------------------------------------------------------------------- 1 | class exports.Circle extends Layer 2 | currentValue: null 3 | 4 | constructor: (@options={}) -> 5 | 6 | @options.circleSize ?= 300 7 | @options.strokeWidth ?= 24 8 | @options.linecap ?= "round" 9 | 10 | @options.strokeColor ?= "#fc245c" 11 | @options.topColor ?= null 12 | @options.bottomColor ?= null 13 | 14 | @options.hasCounter ?= null 15 | @options.counterColor ?= "#fff" 16 | @options.counterFontSize ?= 60 17 | @options.hasLinearEasing ?= false 18 | 19 | @options.value = 2 20 | 21 | @options.viewBox = (@options.circleSize) + @options.strokeWidth 22 | 23 | super @options 24 | 25 | @.backgroundColor = "" 26 | @.height = @options.viewBox 27 | @.width = @options.viewBox 28 | @.rotation = -90 29 | 30 | 31 | @.pathLength = Math.PI * @options.circleSize 32 | 33 | @.circleID = "circle" + Math.floor(Math.random()*1000) 34 | @.gradientID = "circle" + Math.floor(Math.random()*1000) 35 | 36 | # Put this inside lineargradient 37 | # gradientUnits="userSpaceOnUse" 38 | # x1="0%" y1="0%" x2="50%" y2="0%" gradientTransform="rotate(120)" 39 | 40 | 41 | if @options.hasCounter isnt null 42 | counter = new Layer 43 | parent: @ 44 | html: "" 45 | width: @.width 46 | height: @.height 47 | backgroundColor: "" 48 | rotation: 90 49 | color: @options.counterColor 50 | 51 | style = { 52 | textAlign: "center" 53 | fontSize: "#{@options.counterFontSize}px" 54 | lineHeight: "#{@.height}px" 55 | fontWeight: "600" 56 | fontFamily: "-apple-system, Helvetica, Arial, sans-serif" 57 | boxSizing: "border-box" 58 | height: @.height 59 | } 60 | 61 | counter.style = style 62 | 63 | numberStart = 0 64 | numberEnd = 100 65 | numberDuration = 2 66 | 67 | numberNow = numberStart 68 | numberInterval = numberEnd - numberStart 69 | 70 | 71 | @.html = """ 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 90 | """ 91 | 92 | self = @ 93 | Utils.domComplete -> 94 | self.path = document.querySelector("##{self.circleID}") 95 | 96 | @proxy = new Layer 97 | opacity: 0 98 | name: "circuleModuleProxy" 99 | 100 | @proxy.sendToBack() 101 | 102 | @proxy.on Events.AnimationEnd, (animation, layer) -> 103 | self.onFinished() 104 | 105 | @proxy.on 'change:x', -> 106 | 107 | offset = Utils.modulate(@.x, [0, 500], [self.pathLength, 0]) 108 | 109 | self.path.setAttribute 'stroke-dashoffset', offset 110 | 111 | if self.options.hasCounter isnt null 112 | numberNow = Utils.round(self.proxy.x / 5) 113 | counter.html = numberNow 114 | 115 | Utils.domComplete -> 116 | self.proxy.x = 0.1 117 | 118 | changeTo: (value, time) -> 119 | if time is undefined 120 | time = 2 121 | 122 | if @options.hasLinearEasing is true 123 | customCurve = "linear" 124 | else 125 | customCurve = "ease-in-out" 126 | 127 | @proxy.animate 128 | properties: 129 | x: 500 * (value / 100) 130 | time: time 131 | curve: customCurve 132 | 133 | @currentValue = value 134 | 135 | startAt: (value) -> 136 | @proxy.animate 137 | properties: 138 | x: 500 * (value / 100) 139 | time: 0.001 140 | 141 | @currentValue = value 142 | 143 | 144 | 145 | hide: -> 146 | @.opacity = 0 147 | 148 | show: -> 149 | @.opacity = 1 150 | 151 | onFinished: -> 152 | 153 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | framer/*.old* 33 | framer/.*.hash 34 | framer/backup.coffee 35 | framer/backups/* 36 | framer/manifest.txt 37 | framer/metadata.json 38 | framer/preview.png 39 | framer/social-880x460.png 40 | framer/social-1200x630.png 41 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/app.coffee: -------------------------------------------------------------------------------- 1 | # Project Info 2 | # This info is presented in a widget when you share. 3 | # http://framerjs.com/docs/#info.info 4 | 5 | Framer.Info = 6 | title: "Apple Watch Activities" 7 | author: "Jonathan Arnold" 8 | twitter: "@servusjon" 9 | description: "Build with SVGCircle Module. Learn more: https://github.com/ServusJon/SVGCircle-Module-for-FramerJS" 10 | 11 | 12 | {Circle} = require "circleModule" 13 | 14 | circleMaxWidth = 160 15 | strokeWidth = 26 16 | circlePadding = 6 17 | 18 | loadingCircle = new Circle 19 | circleWidth: circleMaxWidth 20 | topColor: "#ff150f" 21 | bottomColor: "#ff23bd" 22 | strokeWidth: strokeWidth 23 | hasCounter: true 24 | counterColor: "#ff1d6a" 25 | hasLinearEasing: true 26 | loadingCircle.center() 27 | 28 | loadingCircle.changeTo(100) 29 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/.bookmark -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 0, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 0, 8 | "deviceType" : "fullscreen", 9 | "sharedPrototype" : 0, 10 | "propertyPanelToggleStates" : { 11 | 12 | }, 13 | "projectId" : "3D937E69-52A6-4769-A424-E93D321BF58D", 14 | "deviceOrientation" : 0, 15 | "selectedHand" : "", 16 | "showBezel" : 0, 17 | "foldedCodeRanges" : [ 18 | "{107, 213}" 19 | ], 20 | "deviceScale" : 1 21 | } -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/design.vekter: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 20, 3 | "root" : { 4 | "id" : "tB0fhMSIV", 5 | "__class" : "CanvasNode", 6 | "parentid" : null, 7 | "children" : [ 8 | 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":1,"selectedHand":"","deviceType":"fullscreen","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":1,"selectedHand":"","deviceType":"fullscreen","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"Countdown.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/framer.modules.js: -------------------------------------------------------------------------------- 1 | require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\n \n \n \n \n \n \n \n"; 80 | self = this; 81 | Utils.domComplete(function() { 82 | return self.path = document.querySelector("#" + self.circleID); 83 | }); 84 | this.proxy = new Layer({ 85 | opacity: 0, 86 | name: "circuleModuleProxy" 87 | }); 88 | this.proxy.sendToBack(); 89 | this.proxy.on(Events.AnimationEnd, function(animation, layer) { 90 | return self.onFinished(); 91 | }); 92 | this.proxy.on('change:x', function() { 93 | var offset; 94 | offset = Utils.modulate(this.x, [0, 500], [self.pathLength, 0]); 95 | self.path.setAttribute('stroke-dashoffset', offset); 96 | if (self.options.hasCounter !== null) { 97 | numberNow = Utils.round(self.proxy.x / 5); 98 | return counter.html = numberNow; 99 | } 100 | }); 101 | Utils.domComplete(function() { 102 | return self.proxy.x = 0.1; 103 | }); 104 | } 105 | 106 | Circle.prototype.changeTo = function(value, time) { 107 | var customCurve; 108 | if (time === void 0) { 109 | time = 2; 110 | } 111 | if (this.options.hasLinearEasing === true) { 112 | customCurve = "linear"; 113 | } else { 114 | customCurve = "ease-in-out"; 115 | } 116 | this.proxy.animate({ 117 | properties: { 118 | x: 500 * (value / 100) 119 | }, 120 | time: time, 121 | curve: customCurve 122 | }); 123 | return this.currentValue = value; 124 | }; 125 | 126 | Circle.prototype.startAt = function(value) { 127 | this.proxy.animate({ 128 | properties: { 129 | x: 500 * (value / 100) 130 | }, 131 | time: 0.001 132 | }); 133 | return this.currentValue = value; 134 | }; 135 | 136 | Circle.prototype.hide = function() { 137 | return this.opacity = 0; 138 | }; 139 | 140 | Circle.prototype.show = function() { 141 | return this.opacity = 1; 142 | }; 143 | 144 | Circle.prototype.onFinished = function() {}; 145 | 146 | return Circle; 147 | 148 | })(Layer); 149 | 150 | 151 | },{}]},{},[]) 152 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWVyLm1vZHVsZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL1VzZXJzL0pvbmF0aGFuLkFybm9sZC9EZXNrdG9wL2dpdGh1Yi9TVkdDaXJjbGUtTW9kdWxlLWZvci1GcmFtZXJKUy9FeGFtcGxlcy9Db3VudGRvd24uZnJhbWVyL21vZHVsZXMvY2lyY2xlTW9kdWxlLmNvZmZlZSIsIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiXSwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgZXhwb3J0cy5DaXJjbGUgZXh0ZW5kcyBMYXllclxuXHRjdXJyZW50VmFsdWU6IG51bGxcblxuXHRjb25zdHJ1Y3RvcjogKEBvcHRpb25zPXt9KSAtPlxuXG5cdFx0QG9wdGlvbnMuY2lyY2xlU2l6ZSA/PSAzMDBcblx0XHRAb3B0aW9ucy5zdHJva2VXaWR0aCA/PSAyNFxuXHRcdEBvcHRpb25zLmxpbmVjYXAgPz0gXCJyb3VuZFwiXG5cblx0XHRAb3B0aW9ucy5zdHJva2VDb2xvciA/PSBcIiNmYzI0NWNcIlxuXHRcdEBvcHRpb25zLnRvcENvbG9yID89IG51bGxcblx0XHRAb3B0aW9ucy5ib3R0b21Db2xvciA/PSBudWxsXG5cblx0XHRAb3B0aW9ucy5oYXNDb3VudGVyID89IG51bGxcblx0XHRAb3B0aW9ucy5jb3VudGVyQ29sb3IgPz0gXCIjZmZmXCJcblx0XHRAb3B0aW9ucy5jb3VudGVyRm9udFNpemUgPz0gNjBcblx0XHRAb3B0aW9ucy5oYXNMaW5lYXJFYXNpbmcgPz0gZmFsc2VcblxuXHRcdEBvcHRpb25zLnZhbHVlID0gMlxuXG5cdFx0QG9wdGlvbnMudmlld0JveCA9IChAb3B0aW9ucy5jaXJjbGVTaXplKSArIEBvcHRpb25zLnN0cm9rZVdpZHRoXG5cblx0XHRzdXBlciBAb3B0aW9uc1xuXG5cdFx0QC5iYWNrZ3JvdW5kQ29sb3IgPSBcIlwiXG5cdFx0QC5oZWlnaHQgPSBAb3B0aW9ucy52aWV3Qm94XG5cdFx0QC53aWR0aCA9IEBvcHRpb25zLnZpZXdCb3hcblx0XHRALnJvdGF0aW9uID0gLTkwXG5cblxuXHRcdEAucGF0aExlbmd0aCA9IE1hdGguUEkgKiBAb3B0aW9ucy5jaXJjbGVTaXplXG5cblx0XHRALmNpcmNsZUlEID0gXCJjaXJjbGVcIiArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSoxMDAwKVxuXHRcdEAuZ3JhZGllbnRJRCA9IFwiY2lyY2xlXCIgKyBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqMTAwMClcblxuXHRcdCMgUHV0IHRoaXMgaW5zaWRlIGxpbmVhcmdyYWRpZW50XG5cdFx0IyBncmFkaWVudFVuaXRzPVwidXNlclNwYWNlT25Vc2VcIlxuXHRcdCMgICAgeDE9XCIwJVwiIHkxPVwiMCVcIiB4Mj1cIjUwJVwiIHkyPVwiMCVcIiBncmFkaWVudFRyYW5zZm9ybT1cInJvdGF0ZSgxMjApXCJcblxuXG5cdFx0aWYgQG9wdGlvbnMuaGFzQ291bnRlciBpc250IG51bGxcblx0XHRcdGNvdW50ZXIgPSBuZXcgTGF5ZXJcblx0XHRcdFx0cGFyZW50OiBAXG5cdFx0XHRcdGh0bWw6IFwiXCJcblx0XHRcdFx0d2lkdGg6IEAud2lkdGhcblx0XHRcdFx0aGVpZ2h0OiBALmhlaWdodFxuXHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IFwiXCJcblx0XHRcdFx0cm90YXRpb246IDkwXG5cdFx0XHRcdGNvbG9yOiBAb3B0aW9ucy5jb3VudGVyQ29sb3JcblxuXHRcdFx0c3R5bGUgPSB7XG5cdFx0XHRcdHRleHRBbGlnbjogXCJjZW50ZXJcIlxuXHRcdFx0XHRmb250U2l6ZTogXCIje0BvcHRpb25zLmNvdW50ZXJGb250U2l6ZX1weFwiXG5cdFx0XHRcdGxpbmVIZWlnaHQ6IFwiI3tALmhlaWdodH1weFwiXG5cdFx0XHRcdGZvbnRXZWlnaHQ6IFwiNjAwXCJcblx0XHRcdFx0Zm9udEZhbWlseTogXCItYXBwbGUtc3lzdGVtLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmXCJcblx0XHRcdFx0Ym94U2l6aW5nOiBcImJvcmRlci1ib3hcIlxuXHRcdFx0XHRoZWlnaHQ6IEAuaGVpZ2h0XG5cdFx0XHR9XG5cblx0XHRcdGNvdW50ZXIuc3R5bGUgPSBzdHlsZVxuXG5cdFx0XHRudW1iZXJTdGFydCA9IDBcblx0XHRcdG51bWJlckVuZCA9IDEwMFxuXHRcdFx0bnVtYmVyRHVyYXRpb24gPSAyXG5cblx0XHRcdG51bWJlck5vdyA9IG51bWJlclN0YXJ0XG5cdFx0XHRudW1iZXJJbnRlcnZhbCA9IG51bWJlckVuZCAtIG51bWJlclN0YXJ0XG5cblxuXHRcdEAuaHRtbCA9IFwiXCJcIlxuXHRcdFx0PHN2ZyB2aWV3Qm94PSctI3tAb3B0aW9ucy5zdHJva2VXaWR0aC8yfSAtI3tAb3B0aW9ucy5zdHJva2VXaWR0aC8yfSAje0BvcHRpb25zLnZpZXdCb3h9ICN7QG9wdGlvbnMudmlld0JveH0nID5cblx0XHRcdFx0PGRlZnM+XG5cdFx0XHRcdCAgICA8bGluZWFyR3JhZGllbnQgaWQ9JyN7QGdyYWRpZW50SUR9JyA+XG5cdFx0XHRcdCAgICAgICAgPHN0b3Agb2Zmc2V0PVwiMCVcIiBzdG9wLWNvbG9yPScje2lmIEBvcHRpb25zLnRvcENvbG9yIGlzbnQgbnVsbCB0aGVuIEBvcHRpb25zLmJvdHRvbUNvbG9yIGVsc2UgQG9wdGlvbnMuc3Ryb2tlQ29sb3J9Jy8+XG5cdFx0XHRcdCAgICAgICAgPHN0b3Agb2Zmc2V0PVwiMTAwJVwiIHN0b3AtY29sb3I9JyN7aWYgQG9wdGlvbnMudG9wQ29sb3IgaXNudCBudWxsIHRoZW4gQG9wdGlvbnMudG9wQ29sb3IgZWxzZSBAb3B0aW9ucy5zdHJva2VDb2xvcn0nIHN0b3Atb3BhY2l0eT1cIjFcIiAvPlxuXHRcdFx0XHQgICAgPC9saW5lYXJHcmFkaWVudD5cblx0XHRcdFx0PC9kZWZzPlxuXHRcdFx0XHQ8Y2lyY2xlIGlkPScje0BjaXJjbGVJRH0nXG5cdFx0XHRcdFx0XHRmaWxsPSdub25lJ1xuXHRcdFx0XHRcdFx0c3Ryb2tlLWxpbmVjYXA9JyN7QG9wdGlvbnMubGluZWNhcH0nXG5cdFx0XHRcdFx0XHRzdHJva2Utd2lkdGggICAgICA9ICcje0BvcHRpb25zLnN0cm9rZVdpZHRofSdcblx0XHRcdFx0XHRcdHN0cm9rZS1kYXNoYXJyYXkgID0gJyN7QC5wYXRoTGVuZ3RofSdcblx0XHRcdFx0XHRcdHN0cm9rZS1kYXNob2Zmc2V0ID0gJzAnXG5cdFx0XHRcdFx0XHRzdHJva2U9XCJ1cmwoIyN7QGdyYWRpZW50SUR9KVwiXG5cdFx0XHRcdFx0XHRzdHJva2Utd2lkdGg9XCIxMFwiXG5cdFx0XHRcdFx0XHRjeCA9ICcje0BvcHRpb25zLmNpcmNsZVNpemUvMn0nXG5cdFx0XHRcdFx0XHRjeSA9ICcje0BvcHRpb25zLmNpcmNsZVNpemUvMn0nXG5cdFx0XHRcdFx0XHRyICA9ICcje0BvcHRpb25zLmNpcmNsZVNpemUvMn0nPlxuXHRcdFx0PC9zdmc+XCJcIlwiXG5cblx0XHRzZWxmID0gQFxuXHRcdFV0aWxzLmRvbUNvbXBsZXRlIC0+XG5cdFx0XHRzZWxmLnBhdGggPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiIyN7c2VsZi5jaXJjbGVJRH1cIilcblxuXHRcdEBwcm94eSA9IG5ldyBMYXllclxuXHRcdFx0b3BhY2l0eTogMFxuXHRcdFx0bmFtZTogXCJjaXJjdWxlTW9kdWxlUHJveHlcIlxuXHRcdFx0XG5cdFx0QHByb3h5LnNlbmRUb0JhY2soKVxuXG5cdFx0QHByb3h5Lm9uIEV2ZW50cy5BbmltYXRpb25FbmQsIChhbmltYXRpb24sIGxheWVyKSAtPlxuXHRcdFx0c2VsZi5vbkZpbmlzaGVkKClcblxuXHRcdEBwcm94eS5vbiAnY2hhbmdlOngnLCAtPlxuXG5cdFx0XHRvZmZzZXQgPSBVdGlscy5tb2R1bGF0ZShALngsIFswLCA1MDBdLCBbc2VsZi5wYXRoTGVuZ3RoLCAwXSlcblxuXHRcdFx0c2VsZi5wYXRoLnNldEF0dHJpYnV0ZSAnc3Ryb2tlLWRhc2hvZmZzZXQnLCBvZmZzZXRcblxuXHRcdFx0aWYgc2VsZi5vcHRpb25zLmhhc0NvdW50ZXIgaXNudCBudWxsXG5cdFx0XHRcdG51bWJlck5vdyA9IFV0aWxzLnJvdW5kKHNlbGYucHJveHkueCAvIDUpXG5cdFx0XHRcdGNvdW50ZXIuaHRtbCA9IG51bWJlck5vd1xuXG5cdFx0VXRpbHMuZG9tQ29tcGxldGUgLT5cblx0XHRcdHNlbGYucHJveHkueCA9IDAuMVxuXG5cdGNoYW5nZVRvOiAodmFsdWUsIHRpbWUpIC0+XG5cdFx0aWYgdGltZSBpcyB1bmRlZmluZWRcblx0XHRcdHRpbWUgPSAyXG5cblx0XHRpZiBAb3B0aW9ucy5oYXNMaW5lYXJFYXNpbmcgaXMgdHJ1ZVxuXHRcdFx0Y3VzdG9tQ3VydmUgPSBcImxpbmVhclwiXG5cdFx0ZWxzZVxuXHRcdFx0Y3VzdG9tQ3VydmUgPSBcImVhc2UtaW4tb3V0XCJcblxuXHRcdEBwcm94eS5hbmltYXRlXG5cdFx0XHRwcm9wZXJ0aWVzOlxuXHRcdFx0XHR4OiA1MDAgKiAodmFsdWUgLyAxMDApXG5cdFx0XHR0aW1lOiB0aW1lXG5cdFx0XHRjdXJ2ZTogY3VzdG9tQ3VydmVcblxuXHRcdEBjdXJyZW50VmFsdWUgPSB2YWx1ZVxuXG5cdHN0YXJ0QXQ6ICh2YWx1ZSkgLT5cblx0XHRAcHJveHkuYW5pbWF0ZVxuXHRcdFx0cHJvcGVydGllczpcblx0XHRcdFx0eDogNTAwICogKHZhbHVlIC8gMTAwKVxuXHRcdFx0dGltZTogMC4wMDFcblxuXHRcdEBjdXJyZW50VmFsdWUgPSB2YWx1ZVxuXG5cblxuXHRoaWRlOiAtPlxuXHRcdEAub3BhY2l0eSA9IDBcblxuXHRzaG93OiAtPlxuXHRcdEAub3BhY2l0eSA9IDFcblxuXHRvbkZpbmlzaGVkOiAtPlxuXG4iLCIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUNBQTtBREFBLElBQUE7OztBQUFNLE9BQU8sQ0FBQzs7O21CQUNiLFlBQUEsR0FBYzs7RUFFRCxnQkFBQyxPQUFEO0FBRVosUUFBQTtJQUZhLElBQUMsQ0FBQSw0QkFBRCxVQUFTOztVQUVkLENBQUMsYUFBYzs7O1dBQ2YsQ0FBQyxjQUFlOzs7V0FDaEIsQ0FBQyxVQUFXOzs7V0FFWixDQUFDLGNBQWU7OztXQUNoQixDQUFDLFdBQVk7OztXQUNiLENBQUMsY0FBZTs7O1dBRWhCLENBQUMsYUFBYzs7O1dBQ2YsQ0FBQyxlQUFnQjs7O1dBQ2pCLENBQUMsa0JBQW1COzs7V0FDcEIsQ0FBQyxrQkFBbUI7O0lBRTVCLElBQUMsQ0FBQSxPQUFPLENBQUMsS0FBVCxHQUFpQjtJQUVqQixJQUFDLENBQUEsT0FBTyxDQUFDLE9BQVQsR0FBb0IsSUFBQyxDQUFBLE9BQU8sQ0FBQyxVQUFWLEdBQXdCLElBQUMsQ0FBQSxPQUFPLENBQUM7SUFFcEQsd0NBQU0sSUFBQyxDQUFBLE9BQVA7SUFFQSxJQUFDLENBQUMsZUFBRixHQUFvQjtJQUNwQixJQUFDLENBQUMsTUFBRixHQUFXLElBQUMsQ0FBQSxPQUFPLENBQUM7SUFDcEIsSUFBQyxDQUFDLEtBQUYsR0FBVSxJQUFDLENBQUEsT0FBTyxDQUFDO0lBQ25CLElBQUMsQ0FBQyxRQUFGLEdBQWEsQ0FBQztJQUdkLElBQUMsQ0FBQyxVQUFGLEdBQWUsSUFBSSxD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 153 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Examples/Countdown.framer/framer/version: -------------------------------------------------------------------------------- 1 | 12 -------------------------------------------------------------------------------- /Examples/Countdown.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/Examples/Countdown.framer/images/.gitkeep -------------------------------------------------------------------------------- /Examples/Countdown.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Examples/Countdown.framer/modules/circleModule.coffee: -------------------------------------------------------------------------------- 1 | class exports.Circle extends Layer 2 | currentValue: null 3 | 4 | constructor: (@options={}) -> 5 | 6 | @options.circleSize ?= 300 7 | @options.strokeWidth ?= 24 8 | @options.linecap ?= "round" 9 | 10 | @options.strokeColor ?= "#fc245c" 11 | @options.topColor ?= null 12 | @options.bottomColor ?= null 13 | 14 | @options.hasCounter ?= null 15 | @options.counterColor ?= "#fff" 16 | @options.counterFontSize ?= 60 17 | @options.hasLinearEasing ?= false 18 | 19 | @options.value = 2 20 | 21 | @options.viewBox = (@options.circleSize) + @options.strokeWidth 22 | 23 | super @options 24 | 25 | @.backgroundColor = "" 26 | @.height = @options.viewBox 27 | @.width = @options.viewBox 28 | @.rotation = -90 29 | 30 | 31 | @.pathLength = Math.PI * @options.circleSize 32 | 33 | @.circleID = "circle" + Math.floor(Math.random()*1000) 34 | @.gradientID = "circle" + Math.floor(Math.random()*1000) 35 | 36 | # Put this inside lineargradient 37 | # gradientUnits="userSpaceOnUse" 38 | # x1="0%" y1="0%" x2="50%" y2="0%" gradientTransform="rotate(120)" 39 | 40 | 41 | if @options.hasCounter isnt null 42 | counter = new Layer 43 | parent: @ 44 | html: "" 45 | width: @.width 46 | height: @.height 47 | backgroundColor: "" 48 | rotation: 90 49 | color: @options.counterColor 50 | 51 | style = { 52 | textAlign: "center" 53 | fontSize: "#{@options.counterFontSize}px" 54 | lineHeight: "#{@.height}px" 55 | fontWeight: "600" 56 | fontFamily: "-apple-system, Helvetica, Arial, sans-serif" 57 | boxSizing: "border-box" 58 | height: @.height 59 | } 60 | 61 | counter.style = style 62 | 63 | numberStart = 0 64 | numberEnd = 100 65 | numberDuration = 2 66 | 67 | numberNow = numberStart 68 | numberInterval = numberEnd - numberStart 69 | 70 | 71 | @.html = """ 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 90 | """ 91 | 92 | self = @ 93 | Utils.domComplete -> 94 | self.path = document.querySelector("##{self.circleID}") 95 | 96 | @proxy = new Layer 97 | opacity: 0 98 | name: "circuleModuleProxy" 99 | 100 | @proxy.sendToBack() 101 | 102 | @proxy.on Events.AnimationEnd, (animation, layer) -> 103 | self.onFinished() 104 | 105 | @proxy.on 'change:x', -> 106 | 107 | offset = Utils.modulate(@.x, [0, 500], [self.pathLength, 0]) 108 | 109 | self.path.setAttribute 'stroke-dashoffset', offset 110 | 111 | if self.options.hasCounter isnt null 112 | numberNow = Utils.round(self.proxy.x / 5) 113 | counter.html = numberNow 114 | 115 | Utils.domComplete -> 116 | self.proxy.x = 0.1 117 | 118 | changeTo: (value, time) -> 119 | if time is undefined 120 | time = 2 121 | 122 | if @options.hasLinearEasing is true 123 | customCurve = "linear" 124 | else 125 | customCurve = "ease-in-out" 126 | 127 | @proxy.animate 128 | properties: 129 | x: 500 * (value / 100) 130 | time: time 131 | curve: customCurve 132 | 133 | @currentValue = value 134 | 135 | startAt: (value) -> 136 | @proxy.animate 137 | properties: 138 | x: 500 * (value / 100) 139 | time: 0.001 140 | 141 | @currentValue = value 142 | 143 | 144 | 145 | hide: -> 146 | @.opacity = 0 147 | 148 | show: -> 149 | @.opacity = 1 150 | 151 | onFinished: -> 152 | 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SVG Circle Module for Loading, Countdown or for fun 2 | 3 | #### Live Demo 4 | Apple Watch Activities: [http://share.framerjs.com/0w3wirptkfc9/](http://share.framerjs.com/0w3wirptkfc9/)
5 | Countdown: [http://share.framerjs.com/8as5o1wn1f0a/](http://share.framerjs.com/8as5o1wn1f0a/) 6 | 7 | Countdown 8 | Apple Watch Activities 9 | 10 | Thank you [Henrique Gusso](https://twitter.com/gusso) for writing that [great article](https://medium.com/@gusso/draw-and-animate-an-svg-circle-in-framer-d4bc3a9863c1#.9kdfcl942). 11 | 12 | ## Setup 13 | 1. Download the `circleModule.coffee` file 14 | 2. Create or open a framer project and drop `circleModule.coffee` inside the /modules folder 15 | 3. Add `{Circle} = require "circleModule"` at the top of your document (case-sensitive). 16 | 17 | ## Add Circle 18 | ```coffeescript 19 | circle = new Circle 20 | ``` 21 | You can also change the size of the circle `circleSize: 400` and the strokeSize `circleSize: 20`. 22 | 23 | ## Start Animation or set value initial value 24 | You can animate to a certain value (percent-based). You can change the value any time in your prototype. 25 | ```coffeescript 26 | circle.changeTo(50) # Animates to 50% of circle in the default time 27 | 28 | # Options: Speed (in seconds) 29 | circle.changeTo(50, 10) # Animates to 50% of circle in the 10s 30 | ``` 31 | 32 | Or just set a initial value (percent-based) 33 | ```coffeescript 34 | circle.startAt(10) 35 | ``` 36 | 37 | ## Countdown 38 | You can use the circle also for countdowns 39 | ```coffeescript 40 | countdownCircle = new Circle 41 | hasCounter: true 42 | ``` 43 | 44 | Change the text color `counterColor: "#fff"` and font-size `counterFontSize: 20` to your liking. 45 | 46 | ## Callback 47 | You can get a callback when animation is completed 48 | ```coffeescript 49 | circle.onFinished = -> 50 | print "animation done" 51 | ``` 52 | 53 | Get the current value of the circle 54 | ```coffeescript 55 | circle.onFinished = -> 56 | if circle.currentValue == 80 # TRUE if circle was animated to "circle.changeTo(80)" 57 | print "80%" 58 | ``` 59 | 60 | ## Coloring / Gradients 61 | You can either use a plain color (default) for the circle or a gradient. 62 | ```coffeescript 63 | gradientCircle = new Circle 64 | topColor: "#7cc201" 65 | bottomColor: "#a3fe00" 66 | 67 | plainCircle = new Circle 68 | color: "#7cc201" 69 | ``` 70 | 71 | 72 | ## Show / Hide Circle 73 | You can easily animate the circles visibilty using standard framer functions. For instant changes: 74 | ```coffeescript 75 | circle.hide() 76 | circle.show() 77 | ``` 78 | 79 | ## Optional Properties 80 | You can also customize the circle with following properties: 81 | 82 | | property | Description| 83 | | ------------- | ------------- | 84 | | `circleSize` | The size of the circle (default: 300) | 85 | | `strokeWidth` | The thickness of the stroke (default: 24) | 86 | | `strokeColor` | The color of the stroke (default: "#fc245c") | 87 | | `linecap` | The shape of the stroke's endcaps. Use "butt", "round" or "square" (default: "round") | 88 | | `topColor` | Top Gradient Color | 89 | | `bottomColor` | Bottom Gradient Color | 90 | | `hasCounter` | Set it to `true`, will show a countdown label (default: null) | 91 | | `counterColor` | Text color of countdown label (default: "#fff") | 92 | | `counterFontSize` | Font size of countdown label (default: 60) | 93 | | `hasLinearEasing` | Allows to change the animation curve to "linear" for "ease-in-out". Set it to `true (default: null) | 94 | 95 | ```coffeescript 96 | loadingCircle = new Circle 97 | circleSize: 200 98 | strokeWidth: 30 99 | linecap: "round" 100 | 101 | topColor: "#ff150f" 102 | bottomColor: "#ff23bd" 103 | 104 | hasCounter: true 105 | counterColor: "#fff" 106 | hasLinearEasing: true 107 | 108 | counterColor: "red" 109 | counterFontSize: 100 110 | 111 | loadingCircle.center() # center the circle 112 | 113 | loadingCircle.changeTo(100) 114 | 115 | loadingCircle.onFinished = -> 116 | print "animation is done" 117 | ``` 118 | -------------------------------------------------------------------------------- /applewatchactivities.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/applewatchactivities.gif -------------------------------------------------------------------------------- /circleModule.coffee: -------------------------------------------------------------------------------- 1 | class exports.Circle extends Layer 2 | currentValue: null 3 | 4 | constructor: (@options={}) -> 5 | 6 | @options.circleSize ?= 300 7 | @options.strokeWidth ?= 24 8 | @options.linecap ?= "round" 9 | 10 | @options.strokeColor ?= "#fc245c" 11 | @options.topColor ?= null 12 | @options.bottomColor ?= null 13 | 14 | @options.hasCounter ?= null 15 | @options.counterColor ?= "#fff" 16 | @options.counterFontSize ?= 60 17 | @options.hasLinearEasing ?= false 18 | 19 | @options.value = 2 20 | 21 | @options.viewBox = (@options.circleSize) + @options.strokeWidth 22 | 23 | super @options 24 | 25 | @.backgroundColor = "" 26 | @.height = @options.viewBox 27 | @.width = @options.viewBox 28 | @.rotation = -90 29 | 30 | 31 | @.pathLength = Math.PI * @options.circleSize 32 | 33 | @.circleID = "circle" + Math.floor(Math.random()*1000) 34 | @.gradientID = "circle" + Math.floor(Math.random()*1000) 35 | 36 | # Put this inside lineargradient 37 | # gradientUnits="userSpaceOnUse" 38 | # x1="0%" y1="0%" x2="50%" y2="0%" gradientTransform="rotate(120)" 39 | 40 | 41 | if @options.hasCounter isnt null 42 | counter = new Layer 43 | parent: @ 44 | html: "" 45 | width: @.width 46 | height: @.height 47 | backgroundColor: "" 48 | rotation: 90 49 | color: @options.counterColor 50 | 51 | style = { 52 | textAlign: "center" 53 | fontSize: "#{@options.counterFontSize}px" 54 | lineHeight: "#{@.height}px" 55 | fontWeight: "600" 56 | fontFamily: "-apple-system, Helvetica, Arial, sans-serif" 57 | boxSizing: "border-box" 58 | height: @.height 59 | } 60 | 61 | counter.style = style 62 | 63 | numberStart = 0 64 | numberEnd = 100 65 | numberDuration = 2 66 | 67 | numberNow = numberStart 68 | numberInterval = numberEnd - numberStart 69 | 70 | 71 | @.html = """ 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 90 | """ 91 | 92 | self = @ 93 | Utils.domComplete -> 94 | self.path = document.querySelector("##{self.circleID}") 95 | 96 | @proxy = new Layer 97 | opacity: 0 98 | name: "circuleModuleProxy" 99 | 100 | @proxy.sendToBack() 101 | 102 | @proxy.on Events.AnimationEnd, (animation, layer) -> 103 | self.onFinished() 104 | 105 | @proxy.on 'change:x', -> 106 | 107 | offset = Utils.modulate(@.x, [0, 500], [self.pathLength, 0]) 108 | 109 | self.path.setAttribute 'stroke-dashoffset', offset 110 | 111 | if self.options.hasCounter isnt null 112 | numberNow = Utils.round(self.proxy.x / 5) 113 | counter.html = numberNow 114 | 115 | Utils.domComplete -> 116 | self.proxy.x = 0.1 117 | 118 | changeTo: (value, time) -> 119 | if time is undefined 120 | time = 2 121 | 122 | if @options.hasLinearEasing is true 123 | customCurve = "linear" 124 | else 125 | customCurve = "ease-in-out" 126 | 127 | @proxy.animate 128 | properties: 129 | x: 500 * (value / 100) 130 | time: time 131 | curve: customCurve 132 | 133 | @currentValue = value 134 | 135 | startAt: (value) -> 136 | @proxy.animate 137 | properties: 138 | x: 500 * (value / 100) 139 | time: 0.001 140 | 141 | @currentValue = value 142 | 143 | 144 | 145 | hide: -> 146 | @.opacity = 0 147 | 148 | show: -> 149 | @.opacity = 1 150 | 151 | onFinished: -> 152 | 153 | -------------------------------------------------------------------------------- /countdown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServusJon/SVGCircle-Module-for-FramerJS/4fbbea8b5bbce544a7144d98c95e0c673b062915/countdown.gif --------------------------------------------------------------------------------