120
95

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VSCodeでSVGを編集できるやつ2.0(SVG Editor)

Last updated at Posted at 2018-08-26

これは何

VSCode上でSVGを画像編集ソフトっぽく編集したくて作っている拡張です。Marketplaceのページ。

2018/9/2 少し追記

capture.png

右側のウィンドウで図形を選択して動かしたりできます。この度Elmで書いていたのをすべてTypeScriptで書き直したので苦労話とかをまとめてみました。使って~

なぜElmをやめたの?

portが辛かった...辛かったんです...許して...

まあ実際のdom要素から取得しないといけない値とか結構あったので、だんだんきつくなっていったんですね。

はまった点

  • cssでwidthとかheightを指定するときはpxとか単位が必須、SVGと同じ気分で書いてはいけない
  • SVGの要素はdocument.createElementNSで名前空間を指定する
  • 単位換算
    • units-cssという便利ライブラリがあるがSVGにそのまま適用はできない
    • %の計算にライブラリではoffsetWidth, offsetHeightを使って要素の幅や高さを測っているがSVG要素にはそのプロパティはない...
    • あとex, emの計算がライブラリは何かおかしい
    • のでgetComputedStyleしまくる
  • viewBoxが難しい(つらい)多分負の値でまだバグがある
  • ネストされたsvg要素の当たり判定がそれの内部にある要素以上に拡大されない(ので透明のrectをこっそり挿入)
  • transform属性は頭が痛い。g要素と絡むともっと頭が痛い。
    • inkscapeはすごい
  • text要素の拡大とか
    • 「文字列の高さ(lineHeight)→フォントサイズ」を求める方法がない。逆はできる(フォントの属性を与えてlineHeightとかbaselineとかを測ってくれるライブラリはfont-measureが優秀)
    • 仕方ないので二分探索
  • 使用可能なフォントのリストが取れない(指定したフォントが使用可能かを判定することはできるらしい...: font-detect.js)。仕方ないのでOSごとにフォントが入っていそうなディレクトリを探索して(参考: system-font-families)フォントファイルのバイナリを読み込んでfontFamilyをもらってくる。始めはopentype.jsで読み込んでいたがファイルごとにすべてパースされるのが遅いので自力に切り替える(参考: ttfinfo)
  • WebViewAPIでlocalRootResourcesに許可をとってもSVGのuseタグのhrefで外部SVGリソースを参照するとはじかれる。APIのバグな気がする。htmlに埋め込むことで回避。

優秀なライブラリたち

  • font-measure フォントの属性を与えるといろいろな高さを測ってくれる。多分canvasで頑張っている。
  • incremental-dom vdomライブラリ。React、Vueは軟弱。ちゃんとSVGにも使える。
  • svgpath path要素のd属性の値をパースしていろいろいじってくれる感動ライブラリ。
  • transform-matrix transform属性のパース、行列計算のライブラリ。これも頼もしい。
  • tinycolor2 cssの色文字列を何でもパースしてくれる。

VSCodeの拡張を書いて得た知識

  • 最近できたWebview APIで色々便利になった。適用されているテーマの色をcss変数で取得できるところとか素敵。
  • untitledファイルを開く関数はvscode.workspace.openTextDocument。以下。
function workspace.openTextDocument(options?: {
    language?: string | undefined;
    content?: string | undefined;
} | undefined): Thenable<vscode.TextDocument>

おまけ Webview APIで継承されるcss変数一覧

リンクの色ってテーマで指定できないんですね。

:root {
    --background-color: #1e1e1e;
    --color: #d4d4d4;
    --font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", HelveticaNeue-Light, "Noto Sans", Meiryo, "Hiragino Kaku Gothic Pro", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", "Sazanami Gothic", "IPA Gothic", sans-serif;
    --font-size: 13px;
    --font-weight: normal;
    --link-active-color: #4080d0;
    --link-color: #4080d0;
    --vscode-activityBar-background: #333333;
    --vscode-activityBar-dropBackground: rgba(255, 255, 255, 0.12);
    --vscode-activityBar-foreground: #ffffff;
    --vscode-activityBarBadge-background: #007acc;
    --vscode-activityBarBadge-foreground: #ffffff;
    --vscode-badge-background: #4d4d4d;
    --vscode-badge-foreground: #ffffff;
    --vscode-button-background: #0e639c;
    --vscode-button-foreground: #ffffff;
    --vscode-button-hoverBackground: #1177bb;
    --vscode-debugExceptionWidget-background: #420b0d;
    --vscode-debugExceptionWidget-border: #a31515;
    --vscode-debugToolBar-background: #333333;
    --vscode-descriptionForeground: rgba(204, 204, 204, 0.7);
    --vscode-diffEditor-insertedTextBackground: rgba(155, 185, 85, 0.2);
    --vscode-diffEditor-removedTextBackground: rgba(255, 0, 0, 0.2);
    --vscode-dropdown-background: #3c3c3c;
    --vscode-dropdown-border: #3c3c3c;
    --vscode-dropdown-foreground: #f0f0f0;
    --vscode-editor-background: #1e1e1e;
    --vscode-editor-findMatchBackground: #515c6a;
    --vscode-editor-findMatchHighlightBackground: rgba(234, 92, 0, 0.33);
    --vscode-editor-findRangeHighlightBackground: rgba(58, 61, 65, 0.4);
    --vscode-editor-font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", HelveticaNeue-Light, "Noto Sans", Meiryo, "Hiragino Kaku Gothic Pro", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", "Sazanami Gothic", "IPA Gothic", sans-serif;
    --vscode-editor-font-size: 13px;
    --vscode-editor-font-weight: normal;
    --vscode-editor-foreground: #d4d4d4;
    --vscode-editor-hoverHighlightBackground: rgba(38, 79, 120, 0.25);
    --vscode-editor-inactiveSelectionBackground: #3a3d41;
    --vscode-editor-lineHighlightBorder: #282828;
    --vscode-editor-rangeHighlightBackground: rgba(255, 255, 255, 0.04);
    --vscode-editor-selectionBackground: #264f78;
    --vscode-editor-selectionHighlightBackground: rgba(173, 214, 255, 0.15);
    --vscode-editor-wordHighlightBackground: rgba(87, 87, 87, 0.72);
    --vscode-editor-wordHighlightStrongBackground: rgba(0, 73, 114, 0.72);
    --vscode-editorActiveLineNumber-foreground: #aaaaaa;
    --vscode-editorBracketMatch-background: rgba(0, 100, 0, 0.1);
    --vscode-editorBracketMatch-border: #888888;
    --vscode-editorCodeLens-foreground: #999999;
    --vscode-editorCursor-foreground: #aeafad;
    --vscode-editorError-foreground: #ea4646;
    --vscode-editorGroup-border: #444444;
    --vscode-editorGroup-dropBackground: rgba(83, 89, 93, 0.5);
    --vscode-editorGroupHeader-noTabsBackground: #1e1e1e;
    --vscode-editorGroupHeader-tabsBackground: #252526;
    --vscode-editorGutter-addedBackground: #587c0c;
    --vscode-editorGutter-background: #1e1e1e;
    --vscode-editorGutter-deletedBackground: #94151b;
    --vscode-editorGutter-modifiedBackground: #0c7d9d;
    --vscode-editorHint-foreground: rgba(238, 238, 238, 0.7);
    --vscode-editorHoverWidget-background: #2d2d30;
    --vscode-editorHoverWidget-border: #454545;
    --vscode-editorIndentGuide-activeBackground: #707070;
    --vscode-editorIndentGuide-background: #404040;
    --vscode-editorInfo-foreground: #008000;
    --vscode-editorLineNumber-activeForeground: #aaaaaa;
    --vscode-editorLineNumber-foreground: #5a5a5a;
    --vscode-editorLink-activeForeground: #4e94ce;
    --vscode-editorMarkerNavigation-background: #2d2d30;
    --vscode-editorMarkerNavigationError-background: #ea4646;
    --vscode-editorMarkerNavigationInfo-background: #008000;
    --vscode-editorMarkerNavigationWarning-background: #4d9e4d;
    --vscode-editorOverviewRuler-addedForeground: rgba(0, 122, 204, 0.6);
    --vscode-editorOverviewRuler-border: rgba(127, 127, 127, 0.3);
    --vscode-editorOverviewRuler-bracketMatchForeground: #a0a0a0;
    --vscode-editorOverviewRuler-commonContentForeground: rgba(96, 96, 96, 0.4);
    --vscode-editorOverviewRuler-currentContentForeground: rgba(64, 200, 174, 0.5);
    --vscode-editorOverviewRuler-deletedForeground: rgba(0, 122, 204, 0.6);
    --vscode-editorOverviewRuler-errorForeground: rgba(255, 18, 18, 0.7);
    --vscode-editorOverviewRuler-findMatchForeground: rgba(246, 185, 77, 0.7);
    --vscode-editorOverviewRuler-incomingContentForeground: rgba(64, 166, 255, 0.5);
    --vscode-editorOverviewRuler-infoForeground: rgba(18, 18, 136, 0.7);
    --vscode-editorOverviewRuler-modifiedForeground: rgba(0, 122, 204, 0.6);
    --vscode-editorOverviewRuler-rangeHighlightForeground: rgba(0, 122, 204, 0.6);
    --vscode-editorOverviewRuler-selectionHighlightForeground: rgba(160, 160, 160, 0.8);
    --vscode-editorOverviewRuler-warningForeground: rgba(18, 136, 18, 0.7);
    --vscode-editorOverviewRuler-wordHighlightForeground: rgba(160, 160, 160, 0.8);
    --vscode-editorOverviewRuler-wordHighlightStrongForeground: rgba(192, 160, 192, 0.8);
    --vscode-editorPane-background: #1e1e1e;
    --vscode-editorRuler-foreground: #5a5a5a;
    --vscode-editorSuggestWidget-background: #2d2d30;
    --vscode-editorSuggestWidget-border: #454545;
    --vscode-editorSuggestWidget-foreground: #d4d4d4;
    --vscode-editorSuggestWidget-highlightForeground: #0097fb;
    --vscode-editorSuggestWidget-selectedBackground: #073655;
    --vscode-editorUnnecessaryCode-opacity: rgba(0, 0, 0, 0.67);
    --vscode-editorWarning-foreground: #4d9e4d;
    --vscode-editorWhitespace-foreground: rgba(227, 228, 226, 0.16);
    --vscode-editorWidget-background: #2d2d30;
    --vscode-editorWidget-border: #454545;
    --vscode-errorForeground: #f48771;
    --vscode-extensionButton-prominentBackground: #327e36;
    --vscode-extensionButton-prominentForeground: #ffffff;
    --vscode-extensionButton-prominentHoverBackground: #28632b;
    --vscode-focusBorder: rgba(14, 99, 156, 0.6);
    --vscode-foreground: #cccccc;
    --vscode-gitDecoration-addedResourceForeground: #81b88b;
    --vscode-gitDecoration-conflictingResourceForeground: #6c6cc4;
    --vscode-gitDecoration-deletedResourceForeground: #c74e39;
    --vscode-gitDecoration-ignoredResourceForeground: #a7a8a9;
    --vscode-gitDecoration-modifiedResourceForeground: #e2c08d;
    --vscode-gitDecoration-submoduleResourceForeground: #8db9e2;
    --vscode-gitDecoration-untrackedResourceForeground: #73c991;
    --vscode-input-background: #3c3c3c;
    --vscode-input-foreground: #cccccc;
    --vscode-inputOption-activeBorder: #007acc;
    --vscode-inputValidation-errorBackground: #5a1d1d;
    --vscode-inputValidation-errorBorder: #be1100;
    --vscode-inputValidation-infoBackground: #063b49;
    --vscode-inputValidation-infoBorder: #007acc;
    --vscode-inputValidation-warningBackground: #352a05;
    --vscode-inputValidation-warningBorder: #b89500;
    --vscode-list-activeSelectionBackground: #094771;
    --vscode-list-activeSelectionForeground: #ffffff;
    --vscode-list-dropBackground: #383b3d;
    --vscode-list-errorForeground: #ea4646;
    --vscode-list-focusBackground: #073655;
    --vscode-list-highlightForeground: #0097fb;
    --vscode-list-hoverBackground: #2a2d2e;
    --vscode-list-inactiveFocusBackground: #313135;
    --vscode-list-inactiveSelectionBackground: #3f3f46;
    --vscode-list-invalidItemForeground: #b89500;
    --vscode-list-warningForeground: #4d9e4d;
    --vscode-merge-commonContentBackground: rgba(96, 96, 96, 0.16);
    --vscode-merge-commonHeaderBackground: rgba(96, 96, 96, 0.4);
    --vscode-merge-currentContentBackground: rgba(64, 200, 174, 0.2);
    --vscode-merge-currentHeaderBackground: rgba(64, 200, 174, 0.5);
    --vscode-merge-incomingContentBackground: rgba(64, 166, 255, 0.2);
    --vscode-merge-incomingHeaderBackground: rgba(64, 166, 255, 0.5);
    --vscode-notificationCenterHeader-background: #3b3b3e;
    --vscode-notificationLink-foreground: #4080d0;
    --vscode-notifications-background: #2d2d30;
    --vscode-notifications-border: #3b3b3e;
    --vscode-panel-background: #1e1e1e;
    --vscode-panel-border: rgba(128, 128, 128, 0.35);
    --vscode-panel-dropBackground: rgba(255, 255, 255, 0.12);
    --vscode-panelTitle-activeBorder: rgba(128, 128, 128, 0.35);
    --vscode-panelTitle-activeForeground: #e7e7e7;
    --vscode-panelTitle-inactiveForeground: rgba(231, 231, 231, 0.5);
    --vscode-peekView-border: #007acc;
    --vscode-peekViewEditor-background: #001f33;
    --vscode-peekViewEditor-matchHighlightBackground: rgba(255, 143, 0, 0.6);
    --vscode-peekViewEditorGutter-background: #001f33;
    --vscode-peekViewResult-background: #252526;
    --vscode-peekViewResult-fileForeground: #ffffff;
    --vscode-peekViewResult-lineForeground: #bbbbbb;
    --vscode-peekViewResult-matchHighlightBackground: rgba(234, 92, 0, 0.3);
    --vscode-peekViewResult-selectionBackground: rgba(51, 153, 255, 0.2);
    --vscode-peekViewResult-selectionForeground: #ffffff;
    --vscode-peekViewTitle-background: #1e1e1e;
    --vscode-peekViewTitleDescription-foreground: rgba(204, 204, 204, 0.7);
    --vscode-peekViewTitleLabel-foreground: #ffffff;
    --vscode-pickerGroup-border: #3f3f46;
    --vscode-pickerGroup-foreground: rgba(0, 151, 251, 0.6);
    --vscode-progressBar-background: #0e70c0;
    --vscode-scrollbar-shadow: #000000;
    --vscode-scrollbarSlider-activeBackground: rgba(191, 191, 191, 0.4);
    --vscode-scrollbarSlider-background: rgba(121, 121, 121, 0.4);
    --vscode-scrollbarSlider-hoverBackground: rgba(100, 100, 100, 0.7);
    --vscode-settings-modifiedItemForeground: #73c991;
    --vscode-sideBar-background: #252526;
    --vscode-sideBar-dropBackground: rgba(255, 255, 255, 0.12);
    --vscode-sideBarSectionHeader-background: rgba(128, 128, 128, 0.2);
    --vscode-sideBarTitle-foreground: #bbbbbb;
    --vscode-statusBar-background: #007acc;
    --vscode-statusBar-debuggingBackground: #cc6633;
    --vscode-statusBar-debuggingForeground: #ffffff;
    --vscode-statusBar-foreground: #ffffff;
    --vscode-statusBar-noFolderBackground: #68217a;
    --vscode-statusBar-noFolderForeground: #ffffff;
    --vscode-statusBarItem-activeBackground: rgba(255, 255, 255, 0.18);
    --vscode-statusBarItem-hoverBackground: rgba(255, 255, 255, 0.12);
    --vscode-statusBarItem-prominentBackground: #388a34;
    --vscode-statusBarItem-prominentHoverBackground: #369432;
    --vscode-tab-activeBackground: #1e1e1e;
    --vscode-tab-activeForeground: #ffffff;
    --vscode-tab-border: #252526;
    --vscode-tab-inactiveBackground: #2d2d2d;
    --vscode-tab-inactiveForeground: rgba(255, 255, 255, 0.5);
    --vscode-tab-unfocusedActiveForeground: rgba(255, 255, 255, 0.5);
    --vscode-tab-unfocusedInactiveForeground: rgba(255, 255, 255, 0.25);
    --vscode-terminal-ansiBlack: #000000;
    --vscode-terminal-ansiBlue: #2472c8;
    --vscode-terminal-ansiBrightBlack: #666666;
    --vscode-terminal-ansiBrightBlue: #3b8eea;
    --vscode-terminal-ansiBrightCyan: #29b8db;
    --vscode-terminal-ansiBrightGreen: #23d18b;
    --vscode-terminal-ansiBrightMagenta: #d670d6;
    --vscode-terminal-ansiBrightRed: #f14c4c;
    --vscode-terminal-ansiBrightWhite: #e5e5e5;
    --vscode-terminal-ansiBrightYellow: #f5f543;
    --vscode-terminal-ansiCyan: #11a8cd;
    --vscode-terminal-ansiGreen: #0dbc79;
    --vscode-terminal-ansiMagenta: #bc3fbc;
    --vscode-terminal-ansiRed: #cd3131;
    --vscode-terminal-ansiWhite: #e5e5e5;
    --vscode-terminal-ansiYellow: #e5e510;
    --vscode-terminal-foreground: #cccccc;
    --vscode-terminal-selectionBackground: rgba(255, 255, 255, 0.25);
    --vscode-textBlockQuote-background: rgba(127, 127, 127, 0.1);
    --vscode-textBlockQuote-border: rgba(0, 122, 204, 0.5);
    --vscode-textCodeBlock-background: rgba(10, 10, 10, 0.4);
    --vscode-textLink-activeForeground: #4080d0;
    --vscode-textLink-foreground: #4080d0;
    --vscode-textPreformat-foreground: #d7ba7d;
    --vscode-textSeparator-foreground: rgba(255, 255, 255, 0.18);
    --vscode-titleBar-activeBackground: #3c3c3c;
    --vscode-titleBar-activeForeground: #cccccc;
    --vscode-titleBar-inactiveBackground: rgba(60, 60, 60, 0.6);
    --vscode-titleBar-inactiveForeground: rgba(204, 204, 204, 0.6);
    --vscode-widget-shadow: #000000;
}
120
95
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
120
95

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?