├── usage.gif ├── search.gif ├── src └── Contents │ ├── Sketch │ ├── main.cocoascript │ ├── manifest.json │ ├── MochaJSDelegate.js │ ├── baidu.js │ ├── google.js │ ├── mapbox.js │ └── common.js │ └── Resources │ ├── mapbox.html │ ├── google.html │ └── baidu.html ├── MapCreator.sketchplugin └── Contents │ ├── Sketch │ ├── main.cocoascript │ ├── manifest.json │ ├── MochaJSDelegate.js │ ├── baidu.js │ ├── google.js │ ├── mapbox.js │ └── common.js │ └── Resources │ ├── mapbox.html │ ├── google.html │ └── baidu.html ├── appcast.xml └── README.md /usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terence55/sketch-map-creator/HEAD/usage.gif -------------------------------------------------------------------------------- /search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terence55/sketch-map-creator/HEAD/search.gif -------------------------------------------------------------------------------- /src/Contents/Sketch/main.cocoascript: -------------------------------------------------------------------------------- 1 | @import "baidu.js"; 2 | @import "mapbox.js"; 3 | @import "google.js"; 4 | 5 | function commandCreateBaiduMap(context) { 6 | var map = new BaiduMap(); 7 | map.createMap(context); 8 | } 9 | 10 | function commandCreateMapboxMap(context) { 11 | var map = new Mapbox(); 12 | map.createMap(context); 13 | } 14 | 15 | function commandCreateGoogleMap(context) { 16 | var map = new Google(); 17 | map.createMap(context); 18 | } -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/main.cocoascript: -------------------------------------------------------------------------------- 1 | @import "baidu.js"; 2 | @import "mapbox.js"; 3 | @import "google.js"; 4 | 5 | function commandCreateBaiduMap(context) { 6 | var map = new BaiduMap(); 7 | map.createMap(context); 8 | } 9 | 10 | function commandCreateMapboxMap(context) { 11 | var map = new Mapbox(); 12 | map.createMap(context); 13 | } 14 | 15 | function commandCreateGoogleMap(context) { 16 | var map = new Google(); 17 | map.createMap(context); 18 | } -------------------------------------------------------------------------------- /appcast.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Map Creator 5 | https://github.com/terence55/sketch-map-creator 6 | Plugin to visually create static map(BaiduMap, MapBox, GoogleMap) with custom options 7 | en 8 | 9 | Version 1.2.1 10 | 11 | 13 |
  • Plugin to visually create static map(BaiduMap, MapBox, GoogleMap) with custom options
  • 14 | 15 | ]]> 16 |
    17 | 18 |
    19 |
    20 |
    -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Map Creator for Sketch 2 | 3 | ## Features (v1.2.1) 4 | 5 | - Plugin for Sketch to create a static map with custom options. 6 | - ***Visual selection for map center and zoom level supported(New feature).*** 7 | - BaiduMap, MapBox and ***GoogleMap(new)*** have been supported now. 8 | - Easy to extend for other map services. 9 | - ***Support location search(New feature).*** 10 | 11 | ***Now in latest version, you can select layer in Sketch 52+ correctly.*** 12 | 13 | ## Installation 14 | 15 | - [Download](https://codeload.github.com/terence55/sketch-map-creator/zip/1.2.1) and unzip. 16 | - Open the file 'MapCreator.sketchplugin' for auto installation. 17 | 18 | ## Usage 19 | 20 | - Select a shape layer. 21 | - Choose the map you need. 22 | - Move map to target the center you want, zoom in/out with mouse wheel or buttons on map. You can also change map type in MapBox and GoogleMap. 23 | - Done. 24 | 25 | ![Demo](/usage.gif?raw=true "Map Creator for Sketch Demo") 26 | 27 | ### Location Search 28 | 29 | ![LocationSearch](/search.gif?raw=true "LocationSearch Demo") 30 | -------------------------------------------------------------------------------- /src/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author" : "Terence Wu", 3 | "bundleVersion" : 5, 4 | "commands" : [ 5 | { 6 | "script" : "main.cocoascript", 7 | "name" : "Create Baidu Map", 8 | "handler" : "commandCreateBaiduMap", 9 | "identifier" : "commandCreateBaiduMap" 10 | }, 11 | { 12 | "script" : "main.cocoascript", 13 | "name" : "Create Mapbox Map", 14 | "handler" : "commandCreateMapboxMap", 15 | "identifier" : "commandCreateMapboxMap" 16 | }, 17 | { 18 | "script" : "main.cocoascript", 19 | "name" : "Create Google Map", 20 | "handler" : "commandCreateGoogleMap", 21 | "identifier" : "commandCreateGoogleMap" 22 | } 23 | ], 24 | "menu" : { 25 | "items" : [ 26 | "commandCreateBaiduMap", 27 | "commandCreateMapboxMap", 28 | "commandCreateGoogleMap" 29 | ], 30 | "title" : "Map Creator" 31 | }, 32 | "homepage" : "https://github.com/terence55/sketch-map-creator", 33 | "identifier" : "io.terence.sketch.mapcreator", 34 | "appcast": "https://raw.githubusercontent.com/terence55/sketch-map-creator/master/appcast.xml", 35 | "version" : "1.2.1", 36 | "description" : "Plugin to visually create static map(BaiduMap, MapBox, GoogleMap) with custom options", 37 | "authorEmail" : "trence320@163.com", 38 | "name" : "Map Creator" 39 | } 40 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author" : "Terence Wu", 3 | "bundleVersion" : 5, 4 | "commands" : [ 5 | { 6 | "script" : "main.cocoascript", 7 | "name" : "Create Baidu Map", 8 | "handler" : "commandCreateBaiduMap", 9 | "identifier" : "commandCreateBaiduMap" 10 | }, 11 | { 12 | "script" : "main.cocoascript", 13 | "name" : "Create Mapbox Map", 14 | "handler" : "commandCreateMapboxMap", 15 | "identifier" : "commandCreateMapboxMap" 16 | }, 17 | { 18 | "script" : "main.cocoascript", 19 | "name" : "Create Google Map", 20 | "handler" : "commandCreateGoogleMap", 21 | "identifier" : "commandCreateGoogleMap" 22 | } 23 | ], 24 | "menu" : { 25 | "items" : [ 26 | "commandCreateBaiduMap", 27 | "commandCreateMapboxMap", 28 | "commandCreateGoogleMap" 29 | ], 30 | "title" : "Map Creator" 31 | }, 32 | "homepage" : "https://github.com/terence55/sketch-map-creator", 33 | "identifier" : "io.terence.sketch.mapcreator", 34 | "appcast": "https://raw.githubusercontent.com/terence55/sketch-map-creator/master/appcast.xml", 35 | "version" : "1.2.1", 36 | "description" : "Plugin to visually create static map(BaiduMap, MapBox, GoogleMap) with custom options", 37 | "authorEmail" : "trence320@163.com", 38 | "name" : "Map Creator" 39 | } 40 | -------------------------------------------------------------------------------- /src/Contents/Resources/mapbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | Mapbox 12 | 13 | 14 |
    15 | 16 | 72 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Resources/mapbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | Mapbox 12 | 13 | 14 |
    15 | 16 | 72 | -------------------------------------------------------------------------------- /src/Contents/Sketch/MochaJSDelegate.js: -------------------------------------------------------------------------------- 1 | // 2 | // MochaJSDelegate.js 3 | // MochaJSDelegate 4 | // 5 | // Created by Matt Curtis 6 | // Copyright (c) 2015. All rights reserved. 7 | // 8 | 9 | var MochaJSDelegate = function(selectorHandlerDict){ 10 | var uniqueClassName = "MochaJSDelegate_DynamicClass_" + NSUUID.UUID().UUIDString(); 11 | 12 | var delegateClassDesc = MOClassDescription.allocateDescriptionForClassWithName_superclass_(uniqueClassName, NSObject); 13 | 14 | delegateClassDesc.registerClass(); 15 | 16 | // Handler storage 17 | 18 | var handlers = {}; 19 | 20 | // Define interface 21 | 22 | this.setHandlerForSelector = function(selectorString, func){ 23 | var handlerHasBeenSet = (selectorString in handlers); 24 | var selector = NSSelectorFromString(selectorString); 25 | 26 | handlers[selectorString] = func; 27 | 28 | if(!handlerHasBeenSet){ 29 | /* 30 | For some reason, Mocha acts weird about arguments: 31 | https://github.com/logancollins/Mocha/issues/28 32 | We have to basically create a dynamic handler with a likewise dynamic number of predefined arguments. 33 | */ 34 | 35 | var dynamicHandler = function(){ 36 | var functionToCall = handlers[selectorString]; 37 | 38 | if(!functionToCall) return; 39 | 40 | return functionToCall.apply(delegateClassDesc, arguments); 41 | }; 42 | 43 | var args = [], regex = /:/g; 44 | while(match = regex.exec(selectorString)) args.push("arg"+args.length); 45 | 46 | dynamicFunction = eval("(function("+args.join(",")+"){ return dynamicHandler.apply(this, arguments); })"); 47 | 48 | delegateClassDesc.addInstanceMethodWithSelector_function_(selector, dynamicFunction); 49 | } 50 | }; 51 | 52 | this.removeHandlerForSelector = function(selectorString){ 53 | delete handlers[selectorString]; 54 | }; 55 | 56 | this.getHandlerForSelector = function(selectorString){ 57 | return handlers[selectorString]; 58 | }; 59 | 60 | this.getAllHandlers = function(){ 61 | return handlers; 62 | }; 63 | 64 | this.getClass = function(){ 65 | return NSClassFromString(uniqueClassName); 66 | }; 67 | 68 | this.getClassInstance = function(){ 69 | return NSClassFromString(uniqueClassName).new(); 70 | }; 71 | 72 | // Conveience 73 | 74 | if(typeof selectorHandlerDict == "object"){ 75 | for(var selectorString in selectorHandlerDict){ 76 | this.setHandlerForSelector(selectorString, selectorHandlerDict[selectorString]); 77 | } 78 | } 79 | }; -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/MochaJSDelegate.js: -------------------------------------------------------------------------------- 1 | // 2 | // MochaJSDelegate.js 3 | // MochaJSDelegate 4 | // 5 | // Created by Matt Curtis 6 | // Copyright (c) 2015. All rights reserved. 7 | // 8 | 9 | var MochaJSDelegate = function(selectorHandlerDict){ 10 | var uniqueClassName = "MochaJSDelegate_DynamicClass_" + NSUUID.UUID().UUIDString(); 11 | 12 | var delegateClassDesc = MOClassDescription.allocateDescriptionForClassWithName_superclass_(uniqueClassName, NSObject); 13 | 14 | delegateClassDesc.registerClass(); 15 | 16 | // Handler storage 17 | 18 | var handlers = {}; 19 | 20 | // Define interface 21 | 22 | this.setHandlerForSelector = function(selectorString, func){ 23 | var handlerHasBeenSet = (selectorString in handlers); 24 | var selector = NSSelectorFromString(selectorString); 25 | 26 | handlers[selectorString] = func; 27 | 28 | if(!handlerHasBeenSet){ 29 | /* 30 | For some reason, Mocha acts weird about arguments: 31 | https://github.com/logancollins/Mocha/issues/28 32 | We have to basically create a dynamic handler with a likewise dynamic number of predefined arguments. 33 | */ 34 | 35 | var dynamicHandler = function(){ 36 | var functionToCall = handlers[selectorString]; 37 | 38 | if(!functionToCall) return; 39 | 40 | return functionToCall.apply(delegateClassDesc, arguments); 41 | }; 42 | 43 | var args = [], regex = /:/g; 44 | while(match = regex.exec(selectorString)) args.push("arg"+args.length); 45 | 46 | dynamicFunction = eval("(function("+args.join(",")+"){ return dynamicHandler.apply(this, arguments); })"); 47 | 48 | delegateClassDesc.addInstanceMethodWithSelector_function_(selector, dynamicFunction); 49 | } 50 | }; 51 | 52 | this.removeHandlerForSelector = function(selectorString){ 53 | delete handlers[selectorString]; 54 | }; 55 | 56 | this.getHandlerForSelector = function(selectorString){ 57 | return handlers[selectorString]; 58 | }; 59 | 60 | this.getAllHandlers = function(){ 61 | return handlers; 62 | }; 63 | 64 | this.getClass = function(){ 65 | return NSClassFromString(uniqueClassName); 66 | }; 67 | 68 | this.getClassInstance = function(){ 69 | return NSClassFromString(uniqueClassName).new(); 70 | }; 71 | 72 | // Conveience 73 | 74 | if(typeof selectorHandlerDict == "object"){ 75 | for(var selectorString in selectorHandlerDict){ 76 | this.setHandlerForSelector(selectorString, selectorHandlerDict[selectorString]); 77 | } 78 | } 79 | }; -------------------------------------------------------------------------------- /src/Contents/Resources/google.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 19 | 20 | GoogleMap 21 | 22 | 23 |
    24 |
    25 | 26 | 99 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Resources/google.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 19 | 20 | GoogleMap 21 | 22 | 23 |
    24 |
    25 | 26 | 99 | -------------------------------------------------------------------------------- /src/Contents/Sketch/baidu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * baidu.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | @import "MochaJSDelegate.js"; 9 | 10 | function BaiduMap() {} 11 | 12 | BaiduMap.prototype.prefix = 'baidu'; 13 | BaiduMap.prototype.maxWidth = 512; 14 | BaiduMap.prototype.maxHeight = 512; 15 | BaiduMap.prototype.ak = '4yWbU5UAZzPq3zG136ioc188jR1p6j0t'; 16 | 17 | BaiduMap.prototype.createMap = function (context) { 18 | if (!checkLayer(context.selection)) { 19 | return; 20 | } 21 | var viewIndex = []; 22 | var dialog = this.buildOptionDialog(viewIndex, context); 23 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 24 | if (!options) { 25 | return; 26 | } 27 | var shouldRemember = getOption('remember', 0, this.prefix); 28 | if (shouldRemember == 1) { 29 | setOption('lng', this.centerLng, this.prefix); 30 | setOption('lat', this.centerLat, this.prefix); 31 | setOption('zoom', this.zoom, this.prefix); 32 | } 33 | var layer = context.selection[0]; 34 | var layerSizes = layer.frame(); 35 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 36 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 37 | var imageUrl = 'https://api.map.baidu.com/staticimage/v2?center=' + encodeURIComponent(this.centerLng + ',' + this.centerLat) + '&width=' + width + '&height=' + height + '&zoom=' + (parseInt(this.zoom)) + '&scale=2©right=1&ak=' + this.ak; 38 | fillLayer(context, imageUrl, layer); 39 | } 40 | 41 | BaiduMap.prototype.buildOptionDialog = function (viewIndex, context) { 42 | var shouldRemember = getOption('remember', 0, this.prefix); 43 | 44 | var dialogWindow = NSAlert.alloc().init(); 45 | dialogWindow.setMessageText(tipsTargetCenter); 46 | var dialogContent = NSView.alloc().init(); 47 | dialogContent.setFlipped(true); 48 | dialogContent.frame = NSMakeRect(0, 0, 800, 400); 49 | dialogWindow.accessoryView = dialogContent; 50 | 51 | dialogWindow.addButtonWithTitle('OK'); 52 | dialogWindow.addButtonWithTitle('Cancel'); 53 | 54 | var webView = createWebView('baidu.html', context, NSMakeRect(0, 0, 800, 350)); 55 | var windowObject = webView.windowScriptObject(); 56 | var self = this; 57 | var delegate = new MochaJSDelegate({ 58 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 59 | if (shouldRemember == 1) { 60 | var options = { 61 | center: { 62 | lng: parseFloat(getOption('lng', 0, self.prefix)), 63 | lat: parseFloat(getOption('lat', 0, self.prefix)) 64 | }, 65 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 66 | }; 67 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 68 | } 69 | }), 70 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 71 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 72 | var hash = parseHash(locationHash); 73 | self.centerLng = hash.centerLng; 74 | self.centerLat = hash.centerLat; 75 | self.zoom = hash.zoom; 76 | }) 77 | }); 78 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 79 | dialogContent.addSubview(webView); 80 | 81 | var checkTag = 1; 82 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 360, 200, 20), checkTag); 83 | dialogContent.addSubview(remember); 84 | 85 | viewIndex.push({ 86 | key: 'remember', 87 | index: checkTag, 88 | type: 'string' 89 | }); 90 | 91 | return dialogWindow; 92 | } 93 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/baidu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * baidu.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | @import "MochaJSDelegate.js"; 9 | 10 | function BaiduMap() {} 11 | 12 | BaiduMap.prototype.prefix = 'baidu'; 13 | BaiduMap.prototype.maxWidth = 512; 14 | BaiduMap.prototype.maxHeight = 512; 15 | BaiduMap.prototype.ak = '4yWbU5UAZzPq3zG136ioc188jR1p6j0t'; 16 | 17 | BaiduMap.prototype.createMap = function (context) { 18 | if (!checkLayer(context.selection)) { 19 | return; 20 | } 21 | var viewIndex = []; 22 | var dialog = this.buildOptionDialog(viewIndex, context); 23 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 24 | if (!options) { 25 | return; 26 | } 27 | var shouldRemember = getOption('remember', 0, this.prefix); 28 | if (shouldRemember == 1) { 29 | setOption('lng', this.centerLng, this.prefix); 30 | setOption('lat', this.centerLat, this.prefix); 31 | setOption('zoom', this.zoom, this.prefix); 32 | } 33 | var layer = context.selection[0]; 34 | var layerSizes = layer.frame(); 35 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 36 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 37 | var imageUrl = 'https://api.map.baidu.com/staticimage/v2?center=' + encodeURIComponent(this.centerLng + ',' + this.centerLat) + '&width=' + width + '&height=' + height + '&zoom=' + (parseInt(this.zoom)) + '&scale=2©right=1&ak=' + this.ak; 38 | fillLayer(context, imageUrl, layer); 39 | } 40 | 41 | BaiduMap.prototype.buildOptionDialog = function (viewIndex, context) { 42 | var shouldRemember = getOption('remember', 0, this.prefix); 43 | 44 | var dialogWindow = NSAlert.alloc().init(); 45 | dialogWindow.setMessageText(tipsTargetCenter); 46 | var dialogContent = NSView.alloc().init(); 47 | dialogContent.setFlipped(true); 48 | dialogContent.frame = NSMakeRect(0, 0, 800, 400); 49 | dialogWindow.accessoryView = dialogContent; 50 | 51 | dialogWindow.addButtonWithTitle('OK'); 52 | dialogWindow.addButtonWithTitle('Cancel'); 53 | 54 | var webView = createWebView('baidu.html', context, NSMakeRect(0, 0, 800, 350)); 55 | var windowObject = webView.windowScriptObject(); 56 | var self = this; 57 | var delegate = new MochaJSDelegate({ 58 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 59 | if (shouldRemember == 1) { 60 | var options = { 61 | center: { 62 | lng: parseFloat(getOption('lng', 0, self.prefix)), 63 | lat: parseFloat(getOption('lat', 0, self.prefix)) 64 | }, 65 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 66 | }; 67 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 68 | } 69 | }), 70 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 71 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 72 | var hash = parseHash(locationHash); 73 | self.centerLng = hash.centerLng; 74 | self.centerLat = hash.centerLat; 75 | self.zoom = hash.zoom; 76 | }) 77 | }); 78 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 79 | dialogContent.addSubview(webView); 80 | 81 | var checkTag = 1; 82 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 360, 200, 20), checkTag); 83 | dialogContent.addSubview(remember); 84 | 85 | viewIndex.push({ 86 | key: 'remember', 87 | index: checkTag, 88 | type: 'string' 89 | }); 90 | 91 | return dialogWindow; 92 | } 93 | -------------------------------------------------------------------------------- /src/Contents/Sketch/google.js: -------------------------------------------------------------------------------- 1 | /** 2 | * google.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | 9 | function Google() { } 10 | 11 | Google.prototype.prefix = 'google'; 12 | Google.prototype.maxWidth = 640; 13 | Google.prototype.maxHeight = 640; 14 | Google.prototype.types = [ 15 | 'roadmap', 16 | 'satellite', 17 | 'terrain', 18 | 'hybrid' 19 | ]; 20 | Google.prototype.ak = 'AIzaSyApdHVaG_6lBal7DLBPVjzQ2lvlSLfykc8'; 21 | 22 | Google.prototype.createMap = function (context) { 23 | if (!checkLayer(context.selection)) { 24 | return; 25 | } 26 | var app = NSApplication.sharedApplication(); 27 | var viewIndex = []; 28 | var dialog = this.buildOptionDialog(viewIndex, context); 29 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 30 | if (!options) { 31 | return; 32 | } 33 | var shouldRemember = getOption('remember', 0, this.prefix); 34 | if (shouldRemember == 1) { 35 | setOption('lng', this.centerLng, this.prefix); 36 | setOption('lat', this.centerLat, this.prefix); 37 | setOption('zoom', this.zoom, this.prefix); 38 | } 39 | var layer = context.selection[0]; 40 | var layerSizes = layer.frame(); 41 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 42 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 43 | var imageUrl = 'https://maps.googleapis.com/maps/api/staticmap?center=' + this.centerLat + ',' + this.centerLng + '&zoom=' + this.zoom + '&size=' + width + 'x' + height + '&maptype=' + options.type + '&scale=2&key=' + this.ak; 44 | fillLayer(context, imageUrl, layer); 45 | } 46 | 47 | Google.prototype.buildOptionDialog = function (viewIndex, context) { 48 | var shouldRemember = getOption('remember', 0, this.prefix); 49 | 50 | var dialogWindow = NSAlert.alloc().init(); 51 | dialogWindow.setMessageText(tipsTargetCenter); 52 | var dialogContent = NSView.alloc().init(); 53 | dialogContent.setFlipped(true); 54 | dialogContent.frame = NSMakeRect(0, 0, 500, 430); 55 | dialogWindow.accessoryView = dialogContent; 56 | 57 | dialogWindow.addButtonWithTitle('OK'); 58 | dialogWindow.addButtonWithTitle('Cancel'); 59 | 60 | var typeIndex = getOption('type', 0, this.prefix); 61 | var webView = createWebView('google.html', context, NSMakeRect(0, 0, 500, 350)); 62 | var windowObject = webView.windowScriptObject(); 63 | var self = this; 64 | var delegate = new MochaJSDelegate({ 65 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 66 | if (shouldRemember == 1) { 67 | var options = { 68 | center: { 69 | lng: parseFloat(getOption('lng', 0, self.prefix)), 70 | lat: parseFloat(getOption('lat', 0, self.prefix)) 71 | }, 72 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 73 | }; 74 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 75 | var mapType = self.types[typeIndex]; 76 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 77 | } 78 | }), 79 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 80 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 81 | var hash = parseHash(locationHash); 82 | self.centerLng = hash.centerLng; 83 | self.centerLat = hash.centerLat; 84 | self.zoom = hash.zoom; 85 | }) 86 | }); 87 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 88 | dialogContent.addSubview(webView); 89 | 90 | var typeLabel = createLabel('Select map type', NSMakeRect(0, 360, 100, 20)); 91 | dialogContent.addSubview(typeLabel); 92 | 93 | var typeTag = 1; 94 | var type = createSelect(this.types, shouldRemember == 0 ? 0 : getOption('type', 0, this.prefix), NSMakeRect(120, 360, 200, 20), typeTag, function(sender) { 95 | var mapType = self.types[sender.indexOfSelectedItem()]; 96 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 97 | }); 98 | dialogContent.addSubview(type); 99 | 100 | var checkTag = 2; 101 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 390, 150, 20), checkTag); 102 | dialogContent.addSubview(remember); 103 | 104 | viewIndex.push({ 105 | key: 'type', 106 | index: typeTag, 107 | type: 'select' 108 | }); 109 | 110 | viewIndex.push({ 111 | key: 'remember', 112 | index: checkTag, 113 | type: 'string' 114 | }); 115 | 116 | return dialogWindow; 117 | } 118 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/google.js: -------------------------------------------------------------------------------- 1 | /** 2 | * google.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | 9 | function Google() { } 10 | 11 | Google.prototype.prefix = 'google'; 12 | Google.prototype.maxWidth = 640; 13 | Google.prototype.maxHeight = 640; 14 | Google.prototype.types = [ 15 | 'roadmap', 16 | 'satellite', 17 | 'terrain', 18 | 'hybrid' 19 | ]; 20 | Google.prototype.ak = 'AIzaSyApdHVaG_6lBal7DLBPVjzQ2lvlSLfykc8'; 21 | 22 | Google.prototype.createMap = function (context) { 23 | if (!checkLayer(context.selection)) { 24 | return; 25 | } 26 | var app = NSApplication.sharedApplication(); 27 | var viewIndex = []; 28 | var dialog = this.buildOptionDialog(viewIndex, context); 29 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 30 | if (!options) { 31 | return; 32 | } 33 | var shouldRemember = getOption('remember', 0, this.prefix); 34 | if (shouldRemember == 1) { 35 | setOption('lng', this.centerLng, this.prefix); 36 | setOption('lat', this.centerLat, this.prefix); 37 | setOption('zoom', this.zoom, this.prefix); 38 | } 39 | var layer = context.selection[0]; 40 | var layerSizes = layer.frame(); 41 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 42 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 43 | var imageUrl = 'https://maps.googleapis.com/maps/api/staticmap?center=' + this.centerLat + ',' + this.centerLng + '&zoom=' + this.zoom + '&size=' + width + 'x' + height + '&maptype=' + options.type + '&scale=2&key=' + this.ak; 44 | fillLayer(context, imageUrl, layer); 45 | } 46 | 47 | Google.prototype.buildOptionDialog = function (viewIndex, context) { 48 | var shouldRemember = getOption('remember', 0, this.prefix); 49 | 50 | var dialogWindow = NSAlert.alloc().init(); 51 | dialogWindow.setMessageText(tipsTargetCenter); 52 | var dialogContent = NSView.alloc().init(); 53 | dialogContent.setFlipped(true); 54 | dialogContent.frame = NSMakeRect(0, 0, 500, 430); 55 | dialogWindow.accessoryView = dialogContent; 56 | 57 | dialogWindow.addButtonWithTitle('OK'); 58 | dialogWindow.addButtonWithTitle('Cancel'); 59 | 60 | var typeIndex = getOption('type', 0, this.prefix); 61 | var webView = createWebView('google.html', context, NSMakeRect(0, 0, 500, 350)); 62 | var windowObject = webView.windowScriptObject(); 63 | var self = this; 64 | var delegate = new MochaJSDelegate({ 65 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 66 | if (shouldRemember == 1) { 67 | var options = { 68 | center: { 69 | lng: parseFloat(getOption('lng', 0, self.prefix)), 70 | lat: parseFloat(getOption('lat', 0, self.prefix)) 71 | }, 72 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 73 | }; 74 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 75 | var mapType = self.types[typeIndex]; 76 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 77 | } 78 | }), 79 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 80 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 81 | var hash = parseHash(locationHash); 82 | self.centerLng = hash.centerLng; 83 | self.centerLat = hash.centerLat; 84 | self.zoom = hash.zoom; 85 | }) 86 | }); 87 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 88 | dialogContent.addSubview(webView); 89 | 90 | var typeLabel = createLabel('Select map type', NSMakeRect(0, 360, 100, 20)); 91 | dialogContent.addSubview(typeLabel); 92 | 93 | var typeTag = 1; 94 | var type = createSelect(this.types, shouldRemember == 0 ? 0 : getOption('type', 0, this.prefix), NSMakeRect(120, 360, 200, 20), typeTag, function(sender) { 95 | var mapType = self.types[sender.indexOfSelectedItem()]; 96 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 97 | }); 98 | dialogContent.addSubview(type); 99 | 100 | var checkTag = 2; 101 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 390, 150, 20), checkTag); 102 | dialogContent.addSubview(remember); 103 | 104 | viewIndex.push({ 105 | key: 'type', 106 | index: typeTag, 107 | type: 'select' 108 | }); 109 | 110 | viewIndex.push({ 111 | key: 'remember', 112 | index: checkTag, 113 | type: 'string' 114 | }); 115 | 116 | return dialogWindow; 117 | } 118 | -------------------------------------------------------------------------------- /src/Contents/Sketch/mapbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * mapbox.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | 9 | function Mapbox() { } 10 | 11 | Mapbox.prototype.prefix = 'mapbox'; 12 | Mapbox.prototype.maxWidth = 1280; 13 | Mapbox.prototype.maxHeight = 1280; 14 | Mapbox.prototype.types = [ 15 | 'streets', 16 | 'light', 17 | 'dark', 18 | 'satellite', 19 | 'streets-satellite', 20 | 'wheatpaste', 21 | 'streets-basic', 22 | 'comic', 23 | 'outdoors', 24 | 'run-bike-hike', 25 | 'pencil', 26 | 'pirates', 27 | 'emerald', 28 | 'high-contrast' 29 | ]; 30 | Mapbox.prototype.ak = 'pk.eyJ1IjoidHJlbmNlMzIwIiwiYSI6ImNqNjRobjF0czFrZGMzMnBvN3VzYzQxenMifQ.BJml_qE3BhBJ2bPodjwfeg'; 31 | 32 | Mapbox.prototype.createMap = function (context) { 33 | if (!checkLayer(context.selection)) { 34 | return; 35 | } 36 | var app = NSApplication.sharedApplication(); 37 | var viewIndex = []; 38 | var dialog = this.buildOptionDialog(viewIndex, context); 39 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 40 | if (!options) { 41 | return; 42 | } 43 | var shouldRemember = getOption('remember', 0, this.prefix); 44 | if (shouldRemember == 1) { 45 | setOption('lng', this.centerLng, this.prefix); 46 | setOption('lat', this.centerLat, this.prefix); 47 | setOption('zoom', this.zoom, this.prefix); 48 | } 49 | var layer = context.selection[0]; 50 | var layerSizes = layer.frame(); 51 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 52 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 53 | var imageUrl = 'https://api.mapbox.com/v4/mapbox.' + options.type + '/' + this.centerLng + ',' + this.centerLat + ',' + this.zoom + '/' + width + 'x' + height + '.jpg90?access_token=' + this.ak; 54 | fillLayer(context, imageUrl, layer); 55 | } 56 | 57 | Mapbox.prototype.buildOptionDialog = function (viewIndex, context) { 58 | var shouldRemember = getOption('remember', 0, this.prefix); 59 | 60 | var dialogWindow = NSAlert.alloc().init(); 61 | dialogWindow.setMessageText(tipsTargetCenter); 62 | var dialogContent = NSView.alloc().init(); 63 | dialogContent.setFlipped(true); 64 | dialogContent.frame = NSMakeRect(0, 0, 500, 430); 65 | dialogWindow.accessoryView = dialogContent; 66 | 67 | dialogWindow.addButtonWithTitle('OK'); 68 | dialogWindow.addButtonWithTitle('Cancel'); 69 | 70 | var typeIndex = getOption('type', 0, this.prefix); 71 | var webView = createWebView('mapbox.html', context, NSMakeRect(0, 0, 500, 350)); 72 | var windowObject = webView.windowScriptObject(); 73 | var self = this; 74 | var delegate = new MochaJSDelegate({ 75 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 76 | if (shouldRemember == 1) { 77 | var options = { 78 | center: { 79 | lng: parseFloat(getOption('lng', 0, self.prefix)), 80 | lat: parseFloat(getOption('lat', 0, self.prefix)) 81 | }, 82 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 83 | }; 84 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 85 | var mapType = 'mapbox.' + self.types[typeIndex]; 86 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 87 | } 88 | }), 89 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 90 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 91 | var hash = parseHash(locationHash); 92 | self.centerLng = hash.centerLng; 93 | self.centerLat = hash.centerLat; 94 | self.zoom = hash.zoom; 95 | }) 96 | }); 97 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 98 | dialogContent.addSubview(webView); 99 | 100 | var typeLabel = createLabel('Select map type', NSMakeRect(0, 360, 100, 20)); 101 | dialogContent.addSubview(typeLabel); 102 | 103 | var typeTag = 1; 104 | var type = createSelect(this.types, shouldRemember == 0 ? 0 : getOption('type', 0, this.prefix), NSMakeRect(120, 360, 200, 20), typeTag, function(sender) { 105 | var mapType = 'mapbox.' + self.types[sender.indexOfSelectedItem()]; 106 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 107 | }); 108 | dialogContent.addSubview(type); 109 | 110 | var checkTag = 2; 111 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 390, 150, 20), checkTag); 112 | dialogContent.addSubview(remember); 113 | 114 | viewIndex.push({ 115 | key: 'type', 116 | index: typeTag, 117 | type: 'select' 118 | }); 119 | 120 | viewIndex.push({ 121 | key: 'remember', 122 | index: checkTag, 123 | type: 'string' 124 | }); 125 | 126 | return dialogWindow; 127 | } 128 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/mapbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * mapbox.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | @import "common.js"; 8 | 9 | function Mapbox() { } 10 | 11 | Mapbox.prototype.prefix = 'mapbox'; 12 | Mapbox.prototype.maxWidth = 1280; 13 | Mapbox.prototype.maxHeight = 1280; 14 | Mapbox.prototype.types = [ 15 | 'streets', 16 | 'light', 17 | 'dark', 18 | 'satellite', 19 | 'streets-satellite', 20 | 'wheatpaste', 21 | 'streets-basic', 22 | 'comic', 23 | 'outdoors', 24 | 'run-bike-hike', 25 | 'pencil', 26 | 'pirates', 27 | 'emerald', 28 | 'high-contrast' 29 | ]; 30 | Mapbox.prototype.ak = 'pk.eyJ1IjoidHJlbmNlMzIwIiwiYSI6ImNqNjRobjF0czFrZGMzMnBvN3VzYzQxenMifQ.BJml_qE3BhBJ2bPodjwfeg'; 31 | 32 | Mapbox.prototype.createMap = function (context) { 33 | if (!checkLayer(context.selection)) { 34 | return; 35 | } 36 | var app = NSApplication.sharedApplication(); 37 | var viewIndex = []; 38 | var dialog = this.buildOptionDialog(viewIndex, context); 39 | var options = handleDialog(dialog, viewIndex, this.prefix, dialog.runModal()); 40 | if (!options) { 41 | return; 42 | } 43 | var shouldRemember = getOption('remember', 0, this.prefix); 44 | if (shouldRemember == 1) { 45 | setOption('lng', this.centerLng, this.prefix); 46 | setOption('lat', this.centerLat, this.prefix); 47 | setOption('zoom', this.zoom, this.prefix); 48 | } 49 | var layer = context.selection[0]; 50 | var layerSizes = layer.frame(); 51 | var width = Math.min(parseInt([layerSizes width]), this.maxWidth); 52 | var height = Math.min(parseInt([layerSizes height]), this.maxHeight); 53 | var imageUrl = 'https://api.mapbox.com/v4/mapbox.' + options.type + '/' + this.centerLng + ',' + this.centerLat + ',' + this.zoom + '/' + width + 'x' + height + '.jpg90?access_token=' + this.ak; 54 | fillLayer(context, imageUrl, layer); 55 | } 56 | 57 | Mapbox.prototype.buildOptionDialog = function (viewIndex, context) { 58 | var shouldRemember = getOption('remember', 0, this.prefix); 59 | 60 | var dialogWindow = NSAlert.alloc().init(); 61 | dialogWindow.setMessageText(tipsTargetCenter); 62 | var dialogContent = NSView.alloc().init(); 63 | dialogContent.setFlipped(true); 64 | dialogContent.frame = NSMakeRect(0, 0, 500, 430); 65 | dialogWindow.accessoryView = dialogContent; 66 | 67 | dialogWindow.addButtonWithTitle('OK'); 68 | dialogWindow.addButtonWithTitle('Cancel'); 69 | 70 | var typeIndex = getOption('type', 0, this.prefix); 71 | var webView = createWebView('mapbox.html', context, NSMakeRect(0, 0, 500, 350)); 72 | var windowObject = webView.windowScriptObject(); 73 | var self = this; 74 | var delegate = new MochaJSDelegate({ 75 | "webView:didFinishLoadForFrame:" : (function(webView, webFrame) { 76 | if (shouldRemember == 1) { 77 | var options = { 78 | center: { 79 | lng: parseFloat(getOption('lng', 0, self.prefix)), 80 | lat: parseFloat(getOption('lat', 0, self.prefix)) 81 | }, 82 | zoom: parseInt(getOption('zoom', 11, self.prefix)) 83 | }; 84 | windowObject.evaluateWebScript('setOptions(' + JSON.stringify(options) + ')'); 85 | var mapType = 'mapbox.' + self.types[typeIndex]; 86 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 87 | } 88 | }), 89 | "webView:didChangeLocationWithinPageForFrame:" : (function(webView, webFrame) { 90 | var locationHash = windowObject.evaluateWebScript("window.location.hash"); 91 | var hash = parseHash(locationHash); 92 | self.centerLng = hash.centerLng; 93 | self.centerLat = hash.centerLat; 94 | self.zoom = hash.zoom; 95 | }) 96 | }); 97 | webView.setFrameLoadDelegate_(delegate.getClassInstance()); 98 | dialogContent.addSubview(webView); 99 | 100 | var typeLabel = createLabel('Select map type', NSMakeRect(0, 360, 100, 20)); 101 | dialogContent.addSubview(typeLabel); 102 | 103 | var typeTag = 1; 104 | var type = createSelect(this.types, shouldRemember == 0 ? 0 : getOption('type', 0, this.prefix), NSMakeRect(120, 360, 200, 20), typeTag, function(sender) { 105 | var mapType = 'mapbox.' + self.types[sender.indexOfSelectedItem()]; 106 | windowObject.evaluateWebScript('setType("' + mapType + '")'); 107 | }); 108 | dialogContent.addSubview(type); 109 | 110 | var checkTag = 2; 111 | var remember = createCheck('Remember my options', shouldRemember == 1, NSMakeRect(0, 390, 150, 20), checkTag); 112 | dialogContent.addSubview(remember); 113 | 114 | viewIndex.push({ 115 | key: 'type', 116 | index: typeTag, 117 | type: 'select' 118 | }); 119 | 120 | viewIndex.push({ 121 | key: 'remember', 122 | index: checkTag, 123 | type: 'string' 124 | }); 125 | 126 | return dialogWindow; 127 | } 128 | -------------------------------------------------------------------------------- /src/Contents/Resources/baidu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 47 | 48 | BaiduMap 49 | 50 | 51 |
    52 |
    53 |
    54 |
    55 |
    56 | 57 | 172 | -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Resources/baidu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 47 | 48 | BaiduMap 49 | 50 | 51 |
    52 |
    53 |
    54 |
    55 |
    56 | 57 | 172 | -------------------------------------------------------------------------------- /src/Contents/Sketch/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * common.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | var pluginIdentifier = 'io.terence.sketch.mapcreator'; 8 | 9 | var tipsTargetCenter = 'Move map to target the center you want'; 10 | 11 | function checkLayer(selectedLayers) { 12 | var app = NSApplication.sharedApplication(); 13 | if (!selectedLayers || selectedLayers.count() != 1) { 14 | app.displayDialog_withTitle('Please select exactly 1 shape layer.', 'Invalid shape layer selection'); 15 | return false; 16 | } 17 | var layer = selectedLayers[0]; 18 | var validSelection = true; 19 | if (MSApplicationMetadata.metadata().appVersion >= 52) { 20 | if (layer.edited === undefined) { 21 | validSelection = false; 22 | } 23 | } else if ([layer class] !== MSShapeGroup) { 24 | validSelection = false; 25 | } 26 | if (!validSelection) { 27 | app.displayDialog_withTitle('Your selection was a ' + [layer name] + ', that is not a shape layer. Please select a shape layer.', 'Invalid layer type'); 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | function createLabel(value, frame) { 34 | var textField = NSTextField.alloc().initWithFrame(frame); 35 | textField.setEditable(false); 36 | textField.setBordered(false); 37 | textField.setBackgroundColor(NSColor.colorWithRed_green_blue_alpha(0, 0, 0, 0)); 38 | if (value) { 39 | textField.setStringValue(value); 40 | } 41 | return textField; 42 | } 43 | 44 | function createTextField(value, placeholder, frame, tag) { 45 | var textField = NSTextField.alloc().initWithFrame(frame); 46 | if (value) { 47 | textField.setStringValue(value); 48 | } 49 | if (placeholder) { 50 | textField.setPlaceholderString(placeholder); 51 | } 52 | textField.setTag(tag); 53 | return textField; 54 | } 55 | 56 | function createSelect(options, selectedIndex, frame, tag, onSelectChange) { 57 | var selIdx = selectedIndex || 0; 58 | var select = NSPopUpButton.alloc().initWithFrame(frame); 59 | var i; 60 | if (options) { 61 | select.addItemsWithTitles(options); 62 | select.selectItemAtIndex(selIdx); 63 | } 64 | select.setTag(tag); 65 | if (onSelectChange) { 66 | select.setCOSJSTargetFunction(onSelectChange); 67 | } 68 | return select; 69 | } 70 | 71 | function createCheck(title, checked, frame, tag) { 72 | var check = NSButton.alloc().initWithFrame(frame); 73 | check.setButtonType(NSSwitchButton); 74 | check.setBezelStyle(NSRoundedBezelStyle); 75 | check.setTitle(title); 76 | check.setState(checked == 0 ? NSOffState : NSOnState); 77 | check.setTag(tag); 78 | return check; 79 | } 80 | 81 | function createWebView(uri, context, frame) { 82 | var webView = WebView.alloc().initWithFrame(frame); 83 | webView.setMainFrameURL_(context.plugin.urlForResourceNamed(uri).path()); 84 | return webView; 85 | } 86 | 87 | function fillLayer(context, imageUrl, layer) { 88 | var data = fetchImage(imageUrl); 89 | if (!data) { 90 | context.document.showMessage("Fetch map error, invalid request params"); 91 | return; 92 | } 93 | var result = NSString.alloc().initWithData_encoding(data, NSUTF8StringEncoding); 94 | if (result) { 95 | context.document.showMessage("Fetch map error, invalid request params, error info: " + result); 96 | return; 97 | } 98 | var imageData = NSImage.alloc().initWithData(data); 99 | var fill = layer.style().fills().firstObject(); 100 | fill.setFillType(4); 101 | if (MSApplicationMetadata.metadata().appVersion < 47) { 102 | fill.setImage(MSImageData.alloc().initWithImageConvertingColorSpace(imageData, false)); 103 | } else { 104 | fill.setImage(MSImageData.alloc().initWithImage(imageData)); 105 | } 106 | fill.setPatternFillType(1); 107 | context.document.showMessage("Map has been created"); 108 | } 109 | 110 | function fetchImage(url) { 111 | var request = NSURLRequest.requestWithURL(NSURL.URLWithString(url)); 112 | var response = NSURLConnection.sendSynchronousRequest_returningResponse_error(request, null, null); 113 | return response; 114 | } 115 | 116 | function handleDialog(dialog, viewIndex, prefix, responseCode) { 117 | saveOptions(dialog, viewIndex, prefix); 118 | if (responseCode == NSAlertFirstButtonReturn) { 119 | var result = {}; 120 | var i; 121 | for (i = 0; i < viewIndex.length; i++) { 122 | if (viewIndex[i].type === 'select') { 123 | result[viewIndex[i].key] = dialog.accessoryView().viewWithTag(viewIndex[i].index).titleOfSelectedItem(); 124 | } else if (viewIndex[i].type === 'string') { 125 | result[viewIndex[i].key] = dialog.accessoryView().viewWithTag(viewIndex[i].index).stringValue(); 126 | } 127 | }; 128 | return result; 129 | } 130 | return null; 131 | } 132 | 133 | function saveOptions(dialog, viewIndex, prefix) { 134 | var i; 135 | for (i = 0; i < viewIndex.length; i++) { 136 | if (viewIndex[i].type === 'select') { 137 | setOption(viewIndex[i].key, dialog.accessoryView().viewWithTag(viewIndex[i].index).indexOfSelectedItem(), prefix); 138 | } else if (viewIndex[i].type === 'string') { 139 | setOption(viewIndex[i].key, dialog.accessoryView().viewWithTag(viewIndex[i].index).stringValue(), prefix); 140 | } 141 | }; 142 | } 143 | 144 | function setOption(key, value, prefix) { 145 | return setPreferences(prefix + '.' + key, value); 146 | } 147 | 148 | function getOption(key, defaultValue, prefix) { 149 | return getPreferences(prefix + '.' + key, defaultValue); 150 | } 151 | 152 | function getPreferences(key, defaultValue) { 153 | var userDefaults = NSUserDefaults.standardUserDefaults(); 154 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) { 155 | var defaultPreferences = NSMutableDictionary.alloc().init(); 156 | userDefaults.setObject_forKey(defaultPreferences, pluginIdentifier); 157 | userDefaults.synchronize(); 158 | } 159 | var value = userDefaults.dictionaryForKey(pluginIdentifier).objectForKey(key); 160 | return value === undefined ? defaultValue : value; 161 | } 162 | 163 | function setPreferences(key, value) { 164 | var userDefaults = NSUserDefaults.standardUserDefaults(); 165 | var preferences; 166 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) { 167 | preferences = NSMutableDictionary.alloc().init(); 168 | } else { 169 | preferences = NSMutableDictionary.dictionaryWithDictionary(userDefaults.dictionaryForKey(pluginIdentifier)); 170 | } 171 | preferences.setObject_forKey(value, key); 172 | userDefaults.setObject_forKey(preferences, pluginIdentifier); 173 | userDefaults.synchronize(); 174 | } 175 | 176 | function parseHash(url) { 177 | url = url; 178 | var vars = {}; 179 | var hashes = url.slice(url.indexOf('#') + 1).split('&'); 180 | for(var i = 0; i < hashes.length; i++) { 181 | var hash = hashes[i].split('='); 182 | if(hash.length > 1) { 183 | vars[hash[0].toString()] = hash[1]; 184 | } else { 185 | vars[hash[0].toString()] = null; 186 | } 187 | } 188 | return vars; 189 | } -------------------------------------------------------------------------------- /MapCreator.sketchplugin/Contents/Sketch/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * common.js 3 | * 4 | * Copyright (c) 2017-present, Terence Wu. 5 | */ 6 | 7 | var pluginIdentifier = 'io.terence.sketch.mapcreator'; 8 | 9 | var tipsTargetCenter = 'Move map to target the center you want'; 10 | 11 | function checkLayer(selectedLayers) { 12 | var app = NSApplication.sharedApplication(); 13 | if (!selectedLayers || selectedLayers.count() != 1) { 14 | app.displayDialog_withTitle('Please select exactly 1 shape layer.', 'Invalid shape layer selection'); 15 | return false; 16 | } 17 | var layer = selectedLayers[0]; 18 | var validSelection = true; 19 | if (MSApplicationMetadata.metadata().appVersion >= 52) { 20 | if (layer.edited === undefined) { 21 | validSelection = false; 22 | } 23 | } else if ([layer class] !== MSShapeGroup) { 24 | validSelection = false; 25 | } 26 | if (!validSelection) { 27 | app.displayDialog_withTitle('Your selection was a ' + [layer name] + ', that is not a shape layer. Please select a shape layer.', 'Invalid layer type'); 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | function createLabel(value, frame) { 34 | var textField = NSTextField.alloc().initWithFrame(frame); 35 | textField.setEditable(false); 36 | textField.setBordered(false); 37 | textField.setBackgroundColor(NSColor.colorWithRed_green_blue_alpha(0, 0, 0, 0)); 38 | if (value) { 39 | textField.setStringValue(value); 40 | } 41 | return textField; 42 | } 43 | 44 | function createTextField(value, placeholder, frame, tag) { 45 | var textField = NSTextField.alloc().initWithFrame(frame); 46 | if (value) { 47 | textField.setStringValue(value); 48 | } 49 | if (placeholder) { 50 | textField.setPlaceholderString(placeholder); 51 | } 52 | textField.setTag(tag); 53 | return textField; 54 | } 55 | 56 | function createSelect(options, selectedIndex, frame, tag, onSelectChange) { 57 | var selIdx = selectedIndex || 0; 58 | var select = NSPopUpButton.alloc().initWithFrame(frame); 59 | var i; 60 | if (options) { 61 | select.addItemsWithTitles(options); 62 | select.selectItemAtIndex(selIdx); 63 | } 64 | select.setTag(tag); 65 | if (onSelectChange) { 66 | select.setCOSJSTargetFunction(onSelectChange); 67 | } 68 | return select; 69 | } 70 | 71 | function createCheck(title, checked, frame, tag) { 72 | var check = NSButton.alloc().initWithFrame(frame); 73 | check.setButtonType(NSSwitchButton); 74 | check.setBezelStyle(NSRoundedBezelStyle); 75 | check.setTitle(title); 76 | check.setState(checked == 0 ? NSOffState : NSOnState); 77 | check.setTag(tag); 78 | return check; 79 | } 80 | 81 | function createWebView(uri, context, frame) { 82 | var webView = WebView.alloc().initWithFrame(frame); 83 | webView.setMainFrameURL_(context.plugin.urlForResourceNamed(uri).path()); 84 | return webView; 85 | } 86 | 87 | function fillLayer(context, imageUrl, layer) { 88 | var data = fetchImage(imageUrl); 89 | if (!data) { 90 | context.document.showMessage("Fetch map error, invalid request params"); 91 | return; 92 | } 93 | var result = NSString.alloc().initWithData_encoding(data, NSUTF8StringEncoding); 94 | if (result) { 95 | context.document.showMessage("Fetch map error, invalid request params, error info: " + result); 96 | return; 97 | } 98 | var imageData = NSImage.alloc().initWithData(data); 99 | var fill = layer.style().fills().firstObject(); 100 | fill.setFillType(4); 101 | if (MSApplicationMetadata.metadata().appVersion < 47) { 102 | fill.setImage(MSImageData.alloc().initWithImageConvertingColorSpace(imageData, false)); 103 | } else { 104 | fill.setImage(MSImageData.alloc().initWithImage(imageData)); 105 | } 106 | fill.setPatternFillType(1); 107 | context.document.showMessage("Map has been created"); 108 | } 109 | 110 | function fetchImage(url) { 111 | var request = NSURLRequest.requestWithURL(NSURL.URLWithString(url)); 112 | var response = NSURLConnection.sendSynchronousRequest_returningResponse_error(request, null, null); 113 | return response; 114 | } 115 | 116 | function handleDialog(dialog, viewIndex, prefix, responseCode) { 117 | saveOptions(dialog, viewIndex, prefix); 118 | if (responseCode == NSAlertFirstButtonReturn) { 119 | var result = {}; 120 | var i; 121 | for (i = 0; i < viewIndex.length; i++) { 122 | if (viewIndex[i].type === 'select') { 123 | result[viewIndex[i].key] = dialog.accessoryView().viewWithTag(viewIndex[i].index).titleOfSelectedItem(); 124 | } else if (viewIndex[i].type === 'string') { 125 | result[viewIndex[i].key] = dialog.accessoryView().viewWithTag(viewIndex[i].index).stringValue(); 126 | } 127 | }; 128 | return result; 129 | } 130 | return null; 131 | } 132 | 133 | function saveOptions(dialog, viewIndex, prefix) { 134 | var i; 135 | for (i = 0; i < viewIndex.length; i++) { 136 | if (viewIndex[i].type === 'select') { 137 | setOption(viewIndex[i].key, dialog.accessoryView().viewWithTag(viewIndex[i].index).indexOfSelectedItem(), prefix); 138 | } else if (viewIndex[i].type === 'string') { 139 | setOption(viewIndex[i].key, dialog.accessoryView().viewWithTag(viewIndex[i].index).stringValue(), prefix); 140 | } 141 | }; 142 | } 143 | 144 | function setOption(key, value, prefix) { 145 | return setPreferences(prefix + '.' + key, value); 146 | } 147 | 148 | function getOption(key, defaultValue, prefix) { 149 | return getPreferences(prefix + '.' + key, defaultValue); 150 | } 151 | 152 | function getPreferences(key, defaultValue) { 153 | var userDefaults = NSUserDefaults.standardUserDefaults(); 154 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) { 155 | var defaultPreferences = NSMutableDictionary.alloc().init(); 156 | userDefaults.setObject_forKey(defaultPreferences, pluginIdentifier); 157 | userDefaults.synchronize(); 158 | } 159 | var value = userDefaults.dictionaryForKey(pluginIdentifier).objectForKey(key); 160 | return value === undefined ? defaultValue : value; 161 | } 162 | 163 | function setPreferences(key, value) { 164 | var userDefaults = NSUserDefaults.standardUserDefaults(); 165 | var preferences; 166 | if (!userDefaults.dictionaryForKey(pluginIdentifier)) { 167 | preferences = NSMutableDictionary.alloc().init(); 168 | } else { 169 | preferences = NSMutableDictionary.dictionaryWithDictionary(userDefaults.dictionaryForKey(pluginIdentifier)); 170 | } 171 | preferences.setObject_forKey(value, key); 172 | userDefaults.setObject_forKey(preferences, pluginIdentifier); 173 | userDefaults.synchronize(); 174 | } 175 | 176 | function parseHash(url) { 177 | url = url; 178 | var vars = {}; 179 | var hashes = url.slice(url.indexOf('#') + 1).split('&'); 180 | for(var i = 0; i < hashes.length; i++) { 181 | var hash = hashes[i].split('='); 182 | if(hash.length > 1) { 183 | vars[hash[0].toString()] = hash[1]; 184 | } else { 185 | vars[hash[0].toString()] = null; 186 | } 187 | } 188 | return vars; 189 | } --------------------------------------------------------------------------------