{"id":4990,"date":"2020-01-23T16:27:38","date_gmt":"2020-01-23T07:27:38","guid":{"rendered":"https:\/\/blog.bitmeister.jp\/?p=4990"},"modified":"2020-01-23T16:27:38","modified_gmt":"2020-01-23T07:27:38","slug":"fabric-js%e3%81%8c%e5%87%ba%e5%8a%9b%e3%81%99%e3%82%8bsvg%e3%82%92%e6%8b%a1%e5%bc%b5%e3%81%97%e3%81%a6%e7%8b%ac%e8%87%aa%e3%81%ae%e5%b1%9e%e6%80%a7%e3%82%92%e8%bf%bd%e5%8a%a0%e3%81%99%e3%82%8b","status":"publish","type":"post","link":"https:\/\/blog.bitmeister.jp\/?p=4990","title":{"rendered":"Fabric.js\u304c\u51fa\u529b\u3059\u308bSVG\u3092\u62e1\u5f35\u3057\u3066\u72ec\u81ea\u306e\u5c5e\u6027\u3092\u8ffd\u52a0\u3059\u308b"},"content":{"rendered":"<p><a href=\"http:\/\/fabricjs.com\/\">Fabric.js<\/a> \u3092\u4f7f\u7528\u3057\u3066Canvas\u4e0a\u306b\u30d5\u30ea\u30fc\u30cf\u30f3\u30c9\u3067\u63cf\u3044\u305f\u5185\u5bb9\u3092 <code>fabric.Canvas<\/code> \u306e<br \/>\n<code>toSVG<\/code> \u3067\u51fa\u529b\u3057\u3066\u30b5\u30fc\u30d0\u306b\u9001\u4fe1\u3057\u3001\u30b5\u30fc\u30d0\u5074\u3067\u53d7\u4fe1\u3057\u305fSVG\u6587\u5b57\u5217\u3092\u89e3\u6790\u3057\u3066\u3042\u308c\u3053\u308c\u3057\u3066\u3044\u305f\u306e\u3067\u3059\u304c\u3001 <code>toSVG<\/code> \u3067\u51fa\u529b\u3055\u308c\u308bSVG\u6587\u5b57\u5217\u3060\u3051\u3067\u306f\u60c5\u5831\u304c\u8db3\u308a\u306a\u3044&#8230;\u306a\u3093\u3068\u304bSVG\u306e\u306a\u304b\u306b\u5fc5\u8981\u306a\u60c5\u5831\u3092\u30bb\u30c3\u30c8\u3067\u304d\u306a\u3044\u304b\u306a\uff1f\u3068\u3044\u3046\u3053\u3068\u304c\u3042\u308a\u307e\u3057\u305f\u3002<\/p>\n<p><!--more--><\/p>\n<p>\u4f8b\u3048\u3070\u3001Canvas\u4e0a\u306b\u7d75\u3092\u63cf\u304f\u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u304c\u8907\u6570\u3042\u308b\u3068\u304d\u3001\u63cf\u304b\u308c\u305f\u7dda\u304c\u3069\u306e\u30d6\u30e9\u30b7\u3067\u63cf\u753b\u3055\u308c\u305f\u306e\u304bSVG\u3092\u307f\u3066\u5224\u65ad\u3067\u304d\u308b\u3088\u3046\u306b\u3001\u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u3092SVG\u306b\u542b\u3081\u308b\u306b\u306f\u3069\u3046\u3059\u308c\u3070\u3088\u3044\u3067\u3057\u3087\u3046\u304b\uff1f<\/p>\n<h3>SVG 1.1\u306e\u4ed5\u69d8\u3092\u307f\u3066\u307f\u308b<\/h3>\n<p>Fabric.js\u306e\u30d0\u30fc\u30b8\u30e7\u30f3 3.4.0 \u3067 <code>toSVG<\/code> \u3092\u5b9f\u884c\u3059\u308b\u3068\u3001SVG 1.1 \u306eSVG\u6587\u5b57\u5217\u304c\u51fa\u529b\u3055\u308c\u307e\u3059\u3002<a href=\"https:\/\/www.w3.org\/TR\/SVG11\/extend.html\">SVG 1.1 \u306e\u4ed5\u69d8\u3092\u898b\u3066\u307f\u308b\u3068<\/a>\u3001\u72ec\u81ea\u306e\u8981\u7d20\u3084\u5c5e\u6027\u3092\u8ffd\u52a0\u3067\u304d\u305d\u3046\u3067\u3059\u3002\u4eca\u56de\u306f <code>fabric.PencilBrush<\/code> \u3092\u3064\u304b\u3063\u3066Canvas\u306b\u7d75\u3092\u63cf\u3044\u3066\u3044\u305f\u306e\u3067\u3001\u624b\u3063\u53d6\u308a\u65e9\u304fPath\u8981\u7d20\u306b\u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u3092\u793a\u3059\u72ec\u81ea\u306e\u5c5e\u6027\u3092\u8ffd\u52a0\u3059\u308b\u3053\u3068\u306b\u3057\u307e\u3057\u305f\u3002\uff08 <code>fabric.PencilBrush<\/code> \u3092\u3064\u304b\u3063\u3066Canvas\u306b\u7d75\u3092\u63cf\u304f\u3068\u3001\u63cf\u3044\u305f\u5185\u5bb9\u304c <code>fabric.Path<\/code> \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3068\u3057\u3066Canvas\u306b\u8ffd\u52a0\u3055\u308c\u307e\u3059\u3002\uff09<br \/>\n<a href=\"https:\/\/www.w3.org\/TR\/SVG11\/extend.html#PrivateElementsAndAttribute\">view\u8981\u7d20\u306e\u62e1\u5f35\u4f8b<\/a>\u3092\u53c2\u8003\u306b\u3001\u72ec\u81ea\u306e\u5c5e\u6027 <code>bit:brushType<\/code> \u3092Path\u8981\u7d20\u306b\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n<h3>\u30b5\u30d6\u30af\u30e9\u30b9\u3092\u3064\u304f\u3063\u3066 toSVG \u306e\u51fa\u529b\u5185\u5bb9\u3092\u62e1\u5f35\u3059\u308b<\/h3>\n<p>Fabric.js\u306e\u30bd\u30fc\u30b9\u3092\u307f\u3066\u307f\u308b\u3068\u3001 <code>fabric.Canvas<\/code> \uff08\u5177\u4f53\u7684\u306a\u51e6\u7406\u306f\u89aa\u30af\u30e9\u30b9\u306e <code>fabric.StaticCanvas<\/code> \u3092\u53c2\u7167\uff09\u3068 <code>fabric.Path<\/code> \u3067DTD\u3084Path\u8981\u7d20\u306e\u751f\u6210\u304c\u884c\u308f\u308c\u3066\u3044\u308b\u3053\u3068\u304c\u308f\u304b\u308a\u307e\u3057\u305f\u3002<br \/>\n\u3053\u308c\u3089\u306e\u30af\u30e9\u30b9\u306e\u30b5\u30d6\u30af\u30e9\u30b9\u3092\u3064\u304f\u3063\u3066\u3001\u76ee\u7684\u306eSVG\u6587\u5b57\u5217\u304c\u51fa\u529b\u3055\u308c\u308b\u3088\u3046\u306b\u3057\u3066\u3084\u308c\u3070\u3088\u3055\u305d\u3046\u3067\u3059\u3002<\/p>\n<p>\u307e\u305a\u3001 <code>fabric.Canvas<\/code> \u306e\u30b5\u30d6\u30af\u30e9\u30b9 <code>fabric.ExCanvas<\/code> \u3092\u3064\u304f\u3063\u3066\u3001<code>_setSVGPreamble<\/code> \u3067DTD\u306b\u72ec\u81ea\u306e\u5c5e\u6027 <code>bit:brushType<\/code> \u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfabric.ExCanvas = fabric.util.createClass(fabric.Canvas, {\r\n\r\n  _setSVGPreamble (markup, options) {\r\n    if (options.suppressPreamble) {\r\n      return;\r\n    }\r\n\r\n    markup.push(\r\n      '&lt;?xml version=&quot;1.0&quot; encoding=&quot;', (options.encoding || 'UTF-8'), '&quot; standalone=&quot;no&quot; ?&gt;\\n',\r\n      '&lt;!DOCTYPE svg PUBLIC &quot;-\/\/W3C\/\/DTD SVG 1.1\/\/EN&quot; ',\r\n      '&quot;http:\/\/www.w3.org\/Graphics\/SVG\/1.1\/DTD\/svg11.dtd&quot; &#x5B;\\n',\r\n      '&lt;!ATTLIST path\\n',\r\n      ' xmlns:bit CDATA #FIXED &quot;http:\/\/www.bitmeister.jp\/example\/bit&quot;\\n',\r\n      ' bit:brushType CDATA #IMPLIED&gt;\\n',\r\n      ']&gt;\\n'\r\n    );\r\n  }\r\n\r\n});\r\n<\/pre>\n<p>\u6b21\u306b\u3001<code>fabric.Path<\/code> \u306e\u30b5\u30d6\u30af\u30e9\u30b9 <code>fabric.ExPath<\/code> \u3092\u4f5c\u3063\u3066\u3001 <code>fabric.ExCanvas<\/code> \u3067 <code>toSVG<\/code> \u3092\u5b9f\u884c\u3057\u305f\u3068\u304d\u306b\u3001\u72ec\u81ea\u306e\u5c5e\u6027 <code>bit:brushType<\/code> \u306b\u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u304c\u30bb\u30c3\u30c8\u3055\u308c\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<code>fabric.Path<\/code> \u3067Path\u8981\u7d20\u3092\u751f\u6210\u3057\u3066\u3044\u308b\u306e\u306f <code>_toSVG<\/code> \u306e\u51e6\u7406\u306a\u306e\u3067\u3001\u3053\u306e\u51e6\u7406\u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfabric.ExPath = fabric.util.createClass(fabric.Path, {\r\n  type: 'exPath',\r\n\r\n  brushType: undefined,\r\n\r\n  initialize (path, options) {\r\n    options || (options = {});\r\n\r\n    this.callSuper('initialize', path, options);\r\n\r\n    this.brushType = options.brushType || 'pencil';\r\n\r\n  },\r\n\r\n  _toSVG () {\r\n    var path = this.path.map((path) =&gt; {\r\n      return path.join(' ');\r\n    }).join(' ');\r\n    return &#x5B;\r\n      '&lt;path ', 'COMMON_PARTS',\r\n      'd=&quot;', path,\r\n      '&quot; stroke-linecap=&quot;round&quot; ',\r\n      \/\/ fabric.ExCanvas\u3067\u8ffd\u52a0\u3057\u305f\u72ec\u81ea\u5c5e\u6027\u3092\u30bb\u30c3\u30c8\r\n      `bit:brushType=&quot;${this.brushType}&quot; `,\r\n      '\/&gt;\\n'\r\n    ];\r\n  }\r\n\r\n});\r\n<\/pre>\n<p>\u6700\u5f8c\u306b\u3001<code>fabric.PencilBrush<\/code> \u306e\u30b5\u30d6\u30af\u30e9\u30b9\u3092\u3064\u304f\u3063\u3066\u3001 <code>fabric.ExPath<\/code> \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304cCanvas\u306b\u8ffd\u52a0\u3055\u308c\u308b\u3088\u3046\u306b <code>createPath<\/code> \u3067 <code>fabric.ExPath<\/code> \u3092new\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfabric.ExPencilBrush = fabric.util.createClass(fabric.PencilBrush, {\r\n  brushType: 'pencil',\r\n\r\n  createPath (pathData) {\r\n    const path = new fabric.ExPath(pathData, {\r\n      fill: null,\r\n      stroke: this.color,\r\n      strokeWidth: this.width,\r\n      strokeLineCap: this.strokeLineCap,\r\n      strokeMiterLimit: this.strokeMiterLimit,\r\n      strokeLineJoin: this.strokeLineJoin,\r\n      strokeDashArray: this.strokeDashArray,\r\n      brushType: this.brushType \/\/ \u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u3092\u30bb\u30c3\u30c8\r\n    });\r\n    if (this.shadow) {\r\n      this.shadow.affectStroke = true;\r\n      path.setShadow(this.shadow);\r\n    }\r\n\r\n    return path;\r\n  }\r\n});\r\n<\/pre>\n<h3>Path\u8981\u7d20\u306b\u72ec\u81ea\u5c5e\u6027\u3092\u6301\u3064SVG\u6587\u5b57\u5217\u3092\u51fa\u529b\u3059\u308b<\/h3>\n<p><code>fabric.ExCanvas<\/code> \u3068 <code>fabric.ExPencilBrush<\/code> \u3092\u3064\u304b\u3063\u3066Canvas\u3092\u3064\u304f\u308a\u307e\u3059\u3002<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nconst canvas = new fabric.ExCanvas('c', {\r\n  isDrawingMode: true\r\n});\r\n\r\ncanvas.freeDrawingBrush = new fabric.ExPencilBrush(canvas);\r\ncanvas.freeDrawingBrush.brushType = 'highlighter';\r\n<\/pre>\n<p>Canvas\u306b\u7dda\u3092\u63cf\u3044\u3066 <code>fabric.ExCanvas<\/code> \u306e <code>toSVG<\/code> \u3092\u5b9f\u884c\u3059\u308b\u3068\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306aSVG\u6587\u5b57\u5217\u304c\u51fa\u529b\u3055\u308c\u307e\u3057\u305f\u3002\u4e0a\u8a18\u306e <code>canvas.freeDrawingBrush.brushType<\/code> \u306b\u8a2d\u5b9a\u3057\u305f\u30d6\u30e9\u30b7\u306e\u7a2e\u985e\u304cPath\u8981\u7d20\u306e\u5c5e\u6027 <code>bit:brushType<\/code> \u306b\u51fa\u529b\u3055\u308c\u3066\u3044\u307e\u3059\u306d\u3002<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot; ?&gt;\r\n&lt;!DOCTYPE svg PUBLIC &quot;-\/\/W3C\/\/DTD SVG 1.1\/\/EN&quot; &quot;http:\/\/www.w3.org\/Graphics\/SVG\/1.1\/DTD\/svg11.dtd&quot; &#x5B;\r\n&lt;!ATTLIST path\r\n  xmlns:bit CDATA #FIXED &quot;http:\/\/www.bitmeister.jp\/example\/bit&quot;\r\n  bit:brushType CDATA #IMPLIED&gt;\r\n]&gt;\r\n&lt;svg xmlns=&quot;http:\/\/www.w3.org\/2000\/svg&quot; xmlns:xlink=&quot;http:\/\/www.w3.org\/1999\/xlink&quot; version=&quot;1.1&quot; width=&quot;893&quot; height=&quot;1263&quot; viewBox=&quot;0 0 893 1263&quot; xml:space=&quot;preserve&quot;&gt;\r\n&lt;desc&gt;Created with Fabric.js 3.4.0&lt;\/desc&gt;\r\n&lt;defs&gt;\r\n&lt;\/defs&gt;\r\n&lt;g transform=&quot;matrix(1 0 0 1 347.89 158.91)&quot;  &gt;\r\n&lt;path style=&quot;stroke: rgb(0,0,255); stroke-opacity: 0.2; stroke-width: 10; stroke-dasharray: none; stroke-linecap: round; stroke-dashoffset: 0; stroke-linejoin: round; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;&quot;  transform=&quot; translate(-347.89, -158.91)&quot; d=&quot;(\u7701\u7565)&quot; stroke-linecap=&quot;round&quot; bit:brushType=&quot;highlighter&quot; \/&gt;\r\n&lt;\/g&gt;\r\n&lt;\/svg&gt;\r\n<\/pre>\n<h3>Path\u8981\u7d20\u306b\u72ec\u81ea\u5c5e\u6027\u3092\u6301\u3064SVG\u3092Canvas\u306b\u30ed\u30fc\u30c9\u3059\u308b<\/h3>\n<p><code>fabric.loadSVGFromString<\/code> \u3067\u3001Path\u8981\u7d20\u306b\u72ec\u81ea\u306e\u5c5e\u6027 <code>bit:brushType<\/code> \u3092\u3082\u3064SVG\u6587\u5b57\u5217\u3092\u30ed\u30fc\u30c9\u3059\u308b\u3068\u304d\u3001SVG\u306ePath\u8981\u7d20\u3092\u5148\u307b\u3069\u3064\u304f\u3063\u305f <code>fabric.ExPath<\/code> \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3068\u3057\u3066\u8aad\u307f\u8fbc\u307e\u305b\u308b\u306b\u306f\u3001 <code>fabric.Path<\/code> \u306e <code>fromElement<\/code> \u3067\u72ec\u81ea\u5c5e\u6027\u3092\u89e3\u91c8\u3057\u3066 <code>fabric.ExPath<\/code> \u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u306b\u6e21\u3057\u3066\u3084\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<br \/>\n\u3053\u3093\u306a\u304b\u3093\u3058\u3067\u3001<code>fabric.Path.fromElement<\/code> \u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3057\u307e\u3057\u305f\u3002<\/p>\n<pre class=\"brush: jscript; gutter: false; title: ; notranslate\" title=\"\">\r\nfabric.Path.fromElement = (element, callback, options) =&gt; {\r\n  const parsedAttributes = fabric.parseAttributes(\r\n    element,\r\n    fabric.Path.ATTRIBUTE_NAMES.concat(&#x5B; 'bit:brushType' ]);\r\n  );\r\n\r\n  parsedAttributes.fromSVG = true;\r\n  parsedAttributes.brushType = parsedAttributes&#x5B;'bit:brushType'];\r\n  delete parsedAttributes&#x5B;'bit:brushType'];\r\n\r\n  callback(new fabric.ExPath(\r\n    parsedAttributes.d,\r\n    fabric.util.object.extend(parsedAttributes, options)\r\n  ));\r\n};\r\n<\/pre>\n<p>\u305d\u308c\u3067\u306f\u3001\u3088\u3044Fabric.js\u30e9\u30a4\u30d5\u3092\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fabric.js \u3092\u4f7f\u7528\u3057\u3066Canvas\u4e0a\u306b\u30d5\u30ea\u30fc\u30cf\u30f3\u30c9\u3067\u63cf\u3044\u305f\u5185\u5bb9\u3092 fabric.Canvas \u306e toSVG \u3067\u51fa\u529b\u3057\u3066\u30b5\u30fc\u30d0\u306b\u9001\u4fe1\u3057\u3001\u30b5\u30fc\u30d0\u5074\u3067\u53d7\u4fe1\u3057\u305fSVG\u6587\u5b57\u5217\u3092\u89e3\u6790\u3057\u3066\u3042\u308c\u3053\u308c\u3057\u3066\u3044\u305f\u306e\u3067\u3059\u304c\u3001 toSV [&hellip;]<\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[155,156],"class_list":["post-4990","post","type-post","status-publish","format-standard","hentry","category-tech","tag-fabric-js","tag-svg"],"_links":{"self":[{"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/posts\/4990","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4990"}],"version-history":[{"count":7,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/posts\/4990\/revisions"}],"predecessor-version":[{"id":4996,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=\/wp\/v2\/posts\/4990\/revisions\/4996"}],"wp:attachment":[{"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4990"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4990"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bitmeister.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4990"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}