Vendor SVGnest assets; remove stale submodule gitlink
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
!public/svgnest/**
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 1248dc21efd3f90d1aa52ba5785e27e5217ed2c9
|
||||
21
public/svgnest/LICENSE.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Jack Qiao
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
BIN
public/svgnest/favicon16.gif
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/svgnest/favicon32.gif
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
public/svgnest/font/fonts/LatoLatin-Bold.eot
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Bold.ttf
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Bold.woff
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Bold.woff2
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-BoldItalic.eot
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-BoldItalic.ttf
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-BoldItalic.woff
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-BoldItalic.woff2
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Light.eot
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Light.ttf
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Light.woff
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Light.woff2
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Regular.eot
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Regular.ttf
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Regular.woff
Normal file
BIN
public/svgnest/font/fonts/LatoLatin-Regular.woff2
Normal file
5
public/svgnest/font/generator_config.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Font Squirrel Font-face Generator Configuration File
|
||||
# Upload this file to the generator to recreate the settings
|
||||
# you used to create these fonts.
|
||||
|
||||
{"mode":"optimal","formats":["ttf","woff","eotz"],"tt_instructor":"default","fix_vertical_metrics":"Y","fix_gasp":"xy","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"}
|
||||
612
public/svgnest/font/lato-hai-demo.html
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="specimen_files/easytabs.js" type="text/javascript" charset="utf-8"></script>
|
||||
<link rel="stylesheet" href="specimen_files/specimen_stylesheet.css" type="text/css" charset="utf-8" />
|
||||
<link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" />
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: 'latohairline';
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>Lato Hairline Regular Specimen</title>
|
||||
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$(document).ready(function() {
|
||||
$('#container').easyTabs({defaultContent:1});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
Lato Hairline Regular </div>
|
||||
<ul class="tabs">
|
||||
<li><a href="#specimen">Specimen</a></li>
|
||||
<li><a href="#layout">Sample Layout</a></li>
|
||||
<li><a href="#glyphs">Glyphs & Languages</a></li>
|
||||
<li><a href="#installing">Installing Webfonts</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div id="main_content">
|
||||
|
||||
|
||||
<div id="specimen">
|
||||
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<div class="huge">AaBb</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="glyph_range">A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<table class="sample_table">
|
||||
<tr><td>10</td><td class="size10">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>11</td><td class="size11">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>12</td><td class="size12">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>13</td><td class="size13">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>14</td><td class="size14">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>16</td><td class="size16">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>18</td><td class="size18">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>20</td><td class="size20">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>24</td><td class="size24">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>30</td><td class="size30">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>36</td><td class="size36">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>48</td><td class="size48">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>60</td><td class="size60">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>72</td><td class="size72">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>90</td><td class="size90">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="section" id="bodycomparison">
|
||||
|
||||
|
||||
<div id="xheight">
|
||||
<div class="fontbody">◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body</div><div class="arialbody">body</div><div class="verdanabody">body</div><div class="georgiabody">body</div></div>
|
||||
<div class="fontbody" style="z-index:1">
|
||||
body<span>Lato Hairline Regular</span>
|
||||
</div>
|
||||
<div class="arialbody" style="z-index:1">
|
||||
body<span>Arial</span>
|
||||
</div>
|
||||
<div class="verdanabody" style="z-index:1">
|
||||
body<span>Verdana</span>
|
||||
</div>
|
||||
<div class="georgiabody" style="z-index:1">
|
||||
body<span>Georgia</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section psample psample_row1" id="">
|
||||
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
<div class="section psample psample_row2" id="">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row4" id="">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="section psample psample_row1 fullreverse">
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row2 fullreverse">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row4" id="" style="border-bottom: 20px #000 solid;">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="layout">
|
||||
|
||||
<div class="section">
|
||||
|
||||
<div class="grid12 firstcol">
|
||||
<h1>Lorem Ipsum Dolor</h1>
|
||||
<h2>Etiam porta sem malesuada magna mollis euismod</h2>
|
||||
|
||||
<p class="byline">By <a href="#link">Aenean Lacinia</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid8 firstcol">
|
||||
<p class="large">Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
<h3>Pellentesque ornare sem</h3>
|
||||
|
||||
<p>Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit. </p>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p>
|
||||
|
||||
<p>Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur. </p>
|
||||
|
||||
<p>Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla. </p>
|
||||
|
||||
<h3>Cras mattis consectetur</h3>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum. </p>
|
||||
|
||||
<p>Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid4 sidebar">
|
||||
|
||||
<div class="box reverse">
|
||||
<p class="last">Nullam quis risus eget urna mollis ornare vel eu leo. Donec ullamcorper nulla non metus auctor fringilla. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
|
||||
</div>
|
||||
|
||||
<p class="caption">Maecenas sed diam eget risus varius.</p>
|
||||
|
||||
<p>Vestibulum id ligula porta felis euismod semper. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Vestibulum id ligula porta felis euismod semper. Sed posuere consectetur est at lobortis. Maecenas sed diam eget risus varius blandit sit amet non magna. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
|
||||
<p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Aenean lacinia bibendum nulla sed consectetur. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo. </p>
|
||||
|
||||
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec ullamcorper nulla non metus auctor fringilla. Maecenas faucibus mollis interdum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="glyphs">
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
|
||||
<h1>Language Support</h1>
|
||||
<p>The subset of Lato Hairline Regular in this kit supports the following languages:<br />
|
||||
|
||||
Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Swedish </p>
|
||||
<h1>Glyph Chart</h1>
|
||||
<p>The subset of Lato Hairline Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.</p>
|
||||
<div id="glyph_chart">
|
||||
|
||||
<div><p>&#13;</p> </div>
|
||||
<div><p>&#32;</p> </div>
|
||||
<div><p>&#33;</p>!</div>
|
||||
<div><p>&#34;</p>"</div>
|
||||
<div><p>&#35;</p>#</div>
|
||||
<div><p>&#36;</p>$</div>
|
||||
<div><p>&#37;</p>%</div>
|
||||
<div><p>&#38;</p>&</div>
|
||||
<div><p>&#39;</p>'</div>
|
||||
<div><p>&#40;</p>(</div>
|
||||
<div><p>&#41;</p>)</div>
|
||||
<div><p>&#42;</p>*</div>
|
||||
<div><p>&#43;</p>+</div>
|
||||
<div><p>&#44;</p>,</div>
|
||||
<div><p>&#45;</p>-</div>
|
||||
<div><p>&#46;</p>.</div>
|
||||
<div><p>&#47;</p>/</div>
|
||||
<div><p>&#48;</p>0</div>
|
||||
<div><p>&#49;</p>1</div>
|
||||
<div><p>&#50;</p>2</div>
|
||||
<div><p>&#51;</p>3</div>
|
||||
<div><p>&#52;</p>4</div>
|
||||
<div><p>&#53;</p>5</div>
|
||||
<div><p>&#54;</p>6</div>
|
||||
<div><p>&#55;</p>7</div>
|
||||
<div><p>&#56;</p>8</div>
|
||||
<div><p>&#57;</p>9</div>
|
||||
<div><p>&#58;</p>:</div>
|
||||
<div><p>&#59;</p>;</div>
|
||||
<div><p>&#60;</p><</div>
|
||||
<div><p>&#61;</p>=</div>
|
||||
<div><p>&#62;</p>></div>
|
||||
<div><p>&#63;</p>?</div>
|
||||
<div><p>&#64;</p>@</div>
|
||||
<div><p>&#65;</p>A</div>
|
||||
<div><p>&#66;</p>B</div>
|
||||
<div><p>&#67;</p>C</div>
|
||||
<div><p>&#68;</p>D</div>
|
||||
<div><p>&#69;</p>E</div>
|
||||
<div><p>&#70;</p>F</div>
|
||||
<div><p>&#71;</p>G</div>
|
||||
<div><p>&#72;</p>H</div>
|
||||
<div><p>&#73;</p>I</div>
|
||||
<div><p>&#74;</p>J</div>
|
||||
<div><p>&#75;</p>K</div>
|
||||
<div><p>&#76;</p>L</div>
|
||||
<div><p>&#77;</p>M</div>
|
||||
<div><p>&#78;</p>N</div>
|
||||
<div><p>&#79;</p>O</div>
|
||||
<div><p>&#80;</p>P</div>
|
||||
<div><p>&#81;</p>Q</div>
|
||||
<div><p>&#82;</p>R</div>
|
||||
<div><p>&#83;</p>S</div>
|
||||
<div><p>&#84;</p>T</div>
|
||||
<div><p>&#85;</p>U</div>
|
||||
<div><p>&#86;</p>V</div>
|
||||
<div><p>&#87;</p>W</div>
|
||||
<div><p>&#88;</p>X</div>
|
||||
<div><p>&#89;</p>Y</div>
|
||||
<div><p>&#90;</p>Z</div>
|
||||
<div><p>&#91;</p>[</div>
|
||||
<div><p>&#92;</p>\</div>
|
||||
<div><p>&#93;</p>]</div>
|
||||
<div><p>&#94;</p>^</div>
|
||||
<div><p>&#95;</p>_</div>
|
||||
<div><p>&#96;</p>`</div>
|
||||
<div><p>&#97;</p>a</div>
|
||||
<div><p>&#98;</p>b</div>
|
||||
<div><p>&#99;</p>c</div>
|
||||
<div><p>&#100;</p>d</div>
|
||||
<div><p>&#101;</p>e</div>
|
||||
<div><p>&#102;</p>f</div>
|
||||
<div><p>&#103;</p>g</div>
|
||||
<div><p>&#104;</p>h</div>
|
||||
<div><p>&#105;</p>i</div>
|
||||
<div><p>&#106;</p>j</div>
|
||||
<div><p>&#107;</p>k</div>
|
||||
<div><p>&#108;</p>l</div>
|
||||
<div><p>&#109;</p>m</div>
|
||||
<div><p>&#110;</p>n</div>
|
||||
<div><p>&#111;</p>o</div>
|
||||
<div><p>&#112;</p>p</div>
|
||||
<div><p>&#113;</p>q</div>
|
||||
<div><p>&#114;</p>r</div>
|
||||
<div><p>&#115;</p>s</div>
|
||||
<div><p>&#116;</p>t</div>
|
||||
<div><p>&#117;</p>u</div>
|
||||
<div><p>&#118;</p>v</div>
|
||||
<div><p>&#119;</p>w</div>
|
||||
<div><p>&#120;</p>x</div>
|
||||
<div><p>&#121;</p>y</div>
|
||||
<div><p>&#122;</p>z</div>
|
||||
<div><p>&#123;</p>{</div>
|
||||
<div><p>&#124;</p>|</div>
|
||||
<div><p>&#125;</p>}</div>
|
||||
<div><p>&#126;</p>~</div>
|
||||
<div><p>&#160;</p> </div>
|
||||
<div><p>&#161;</p>¡</div>
|
||||
<div><p>&#162;</p>¢</div>
|
||||
<div><p>&#163;</p>£</div>
|
||||
<div><p>&#164;</p>¤</div>
|
||||
<div><p>&#165;</p>¥</div>
|
||||
<div><p>&#166;</p>¦</div>
|
||||
<div><p>&#167;</p>§</div>
|
||||
<div><p>&#168;</p>¨</div>
|
||||
<div><p>&#169;</p>©</div>
|
||||
<div><p>&#170;</p>ª</div>
|
||||
<div><p>&#171;</p>«</div>
|
||||
<div><p>&#172;</p>¬</div>
|
||||
<div><p>&#173;</p>­</div>
|
||||
<div><p>&#174;</p>®</div>
|
||||
<div><p>&#175;</p>¯</div>
|
||||
<div><p>&#176;</p>°</div>
|
||||
<div><p>&#177;</p>±</div>
|
||||
<div><p>&#178;</p>²</div>
|
||||
<div><p>&#179;</p>³</div>
|
||||
<div><p>&#180;</p>´</div>
|
||||
<div><p>&#181;</p>µ</div>
|
||||
<div><p>&#182;</p>¶</div>
|
||||
<div><p>&#183;</p>·</div>
|
||||
<div><p>&#184;</p>¸</div>
|
||||
<div><p>&#185;</p>¹</div>
|
||||
<div><p>&#186;</p>º</div>
|
||||
<div><p>&#187;</p>»</div>
|
||||
<div><p>&#188;</p>¼</div>
|
||||
<div><p>&#189;</p>½</div>
|
||||
<div><p>&#190;</p>¾</div>
|
||||
<div><p>&#191;</p>¿</div>
|
||||
<div><p>&#192;</p>À</div>
|
||||
<div><p>&#193;</p>Á</div>
|
||||
<div><p>&#194;</p>Â</div>
|
||||
<div><p>&#195;</p>Ã</div>
|
||||
<div><p>&#196;</p>Ä</div>
|
||||
<div><p>&#197;</p>Å</div>
|
||||
<div><p>&#198;</p>Æ</div>
|
||||
<div><p>&#199;</p>Ç</div>
|
||||
<div><p>&#200;</p>È</div>
|
||||
<div><p>&#201;</p>É</div>
|
||||
<div><p>&#202;</p>Ê</div>
|
||||
<div><p>&#203;</p>Ë</div>
|
||||
<div><p>&#204;</p>Ì</div>
|
||||
<div><p>&#205;</p>Í</div>
|
||||
<div><p>&#206;</p>Î</div>
|
||||
<div><p>&#207;</p>Ï</div>
|
||||
<div><p>&#208;</p>Ð</div>
|
||||
<div><p>&#209;</p>Ñ</div>
|
||||
<div><p>&#210;</p>Ò</div>
|
||||
<div><p>&#211;</p>Ó</div>
|
||||
<div><p>&#212;</p>Ô</div>
|
||||
<div><p>&#213;</p>Õ</div>
|
||||
<div><p>&#214;</p>Ö</div>
|
||||
<div><p>&#215;</p>×</div>
|
||||
<div><p>&#216;</p>Ø</div>
|
||||
<div><p>&#217;</p>Ù</div>
|
||||
<div><p>&#218;</p>Ú</div>
|
||||
<div><p>&#219;</p>Û</div>
|
||||
<div><p>&#220;</p>Ü</div>
|
||||
<div><p>&#221;</p>Ý</div>
|
||||
<div><p>&#222;</p>Þ</div>
|
||||
<div><p>&#223;</p>ß</div>
|
||||
<div><p>&#224;</p>à</div>
|
||||
<div><p>&#225;</p>á</div>
|
||||
<div><p>&#226;</p>â</div>
|
||||
<div><p>&#227;</p>ã</div>
|
||||
<div><p>&#228;</p>ä</div>
|
||||
<div><p>&#229;</p>å</div>
|
||||
<div><p>&#230;</p>æ</div>
|
||||
<div><p>&#231;</p>ç</div>
|
||||
<div><p>&#232;</p>è</div>
|
||||
<div><p>&#233;</p>é</div>
|
||||
<div><p>&#234;</p>ê</div>
|
||||
<div><p>&#235;</p>ë</div>
|
||||
<div><p>&#236;</p>ì</div>
|
||||
<div><p>&#237;</p>í</div>
|
||||
<div><p>&#238;</p>î</div>
|
||||
<div><p>&#239;</p>ï</div>
|
||||
<div><p>&#240;</p>ð</div>
|
||||
<div><p>&#241;</p>ñ</div>
|
||||
<div><p>&#242;</p>ò</div>
|
||||
<div><p>&#243;</p>ó</div>
|
||||
<div><p>&#244;</p>ô</div>
|
||||
<div><p>&#245;</p>õ</div>
|
||||
<div><p>&#246;</p>ö</div>
|
||||
<div><p>&#247;</p>÷</div>
|
||||
<div><p>&#248;</p>ø</div>
|
||||
<div><p>&#249;</p>ù</div>
|
||||
<div><p>&#250;</p>ú</div>
|
||||
<div><p>&#251;</p>û</div>
|
||||
<div><p>&#252;</p>ü</div>
|
||||
<div><p>&#253;</p>ý</div>
|
||||
<div><p>&#254;</p>þ</div>
|
||||
<div><p>&#255;</p>ÿ</div>
|
||||
<div><p>&#338;</p>Œ</div>
|
||||
<div><p>&#339;</p>œ</div>
|
||||
<div><p>&#376;</p>Ÿ</div>
|
||||
<div><p>&#710;</p>ˆ</div>
|
||||
<div><p>&#732;</p>˜</div>
|
||||
<div><p>&#8192;</p> </div>
|
||||
<div><p>&#8193;</p> </div>
|
||||
<div><p>&#8194;</p> </div>
|
||||
<div><p>&#8195;</p> </div>
|
||||
<div><p>&#8196;</p> </div>
|
||||
<div><p>&#8197;</p> </div>
|
||||
<div><p>&#8198;</p> </div>
|
||||
<div><p>&#8199;</p> </div>
|
||||
<div><p>&#8200;</p> </div>
|
||||
<div><p>&#8201;</p> </div>
|
||||
<div><p>&#8202;</p> </div>
|
||||
<div><p>&#8208;</p>‐</div>
|
||||
<div><p>&#8209;</p>‑</div>
|
||||
<div><p>&#8210;</p>‒</div>
|
||||
<div><p>&#8211;</p>–</div>
|
||||
<div><p>&#8212;</p>—</div>
|
||||
<div><p>&#8216;</p>‘</div>
|
||||
<div><p>&#8217;</p>’</div>
|
||||
<div><p>&#8218;</p>‚</div>
|
||||
<div><p>&#8220;</p>“</div>
|
||||
<div><p>&#8221;</p>”</div>
|
||||
<div><p>&#8222;</p>„</div>
|
||||
<div><p>&#8226;</p>•</div>
|
||||
<div><p>&#8230;</p>…</div>
|
||||
<div><p>&#8239;</p> </div>
|
||||
<div><p>&#8249;</p>‹</div>
|
||||
<div><p>&#8250;</p>›</div>
|
||||
<div><p>&#8287;</p> </div>
|
||||
<div><p>&#8364;</p>€</div>
|
||||
<div><p>&#8482;</p>™</div>
|
||||
<div><p>&#9724;</p>◼</div>
|
||||
<div><p>&#64257;</p>fi</div>
|
||||
<div><p>&#64258;</p>fl</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="specs">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="installing">
|
||||
<div class="section">
|
||||
<div class="grid7 firstcol">
|
||||
<h1>Installing Webfonts</h1>
|
||||
|
||||
<p>Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.</p>
|
||||
|
||||
<h2>1. Upload your webfonts</h2>
|
||||
<p>You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.</p>
|
||||
|
||||
<h2>2. Include the webfont stylesheet</h2>
|
||||
<p>A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the <a href="http://www.fontspring.com/blog/further-hardening-of-the-bulletproof-syntax">Fontspring blog post</a> about it. The code for it is as follows:</p>
|
||||
|
||||
|
||||
<code>
|
||||
@font-face{
|
||||
font-family: 'MyWebFont';
|
||||
src: url('WebFont.eot');
|
||||
src: url('WebFont.eot?#iefix') format('embedded-opentype'),
|
||||
url('WebFont.woff') format('woff'),
|
||||
url('WebFont.ttf') format('truetype'),
|
||||
url('WebFont.svg#webfont') format('svg');
|
||||
}
|
||||
</code>
|
||||
|
||||
<p>We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:</p>
|
||||
<code><link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /></code>
|
||||
|
||||
<h2>3. Modify your own stylesheet</h2>
|
||||
<p>To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:</p>
|
||||
<code>p { font-family: 'WebFont', Arial, sans-serif; }</code>
|
||||
|
||||
<h2>4. Test</h2>
|
||||
<p>Getting webfonts to work cross-browser <em>can</em> be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid5 sidebar">
|
||||
<div class="box">
|
||||
<h2>Troubleshooting<br />Font-Face Problems</h2>
|
||||
<p>Having trouble getting your webfonts to load in your new website? Here are some tips to sort out what might be the problem.</p>
|
||||
|
||||
<h3>Fonts not showing in any browser</h3>
|
||||
|
||||
<p>This sounds like you need to work on the plumbing. You either did not upload the fonts to the correct directory, or you did not link the fonts properly in the CSS. If you've confirmed that all this is correct and you still have a problem, take a look at your .htaccess file and see if requests are getting intercepted.</p>
|
||||
|
||||
<h3>Fonts not loading in iPhone or iPad</h3>
|
||||
|
||||
<p>The most common problem here is that you are serving the fonts from an IIS server. IIS refuses to serve files that have unknown MIME types. If that is the case, you must set the MIME type for SVG to "image/svg+xml" in the server settings. Follow these instructions from Microsoft if you need help.</p>
|
||||
|
||||
<h3>Fonts not loading in Firefox</h3>
|
||||
|
||||
<p>The primary reason for this failure? You are still using a version Firefox older than 3.5. So upgrade already! If that isn't it, then you are very likely serving fonts from a different domain. Firefox requires that all font assets be served from the same domain. Lastly it is possible that you need to add WOFF to your list of MIME types (if you are serving via IIS.)</p>
|
||||
|
||||
<h3>Fonts not loading in IE</h3>
|
||||
|
||||
<p>Are you looking at Internet Explorer on an actual Windows machine or are you cheating by using a service like Adobe BrowserLab? Many of these screenshot services do not render @font-face for IE. Best to test it on a real machine.</p>
|
||||
|
||||
<h3>Fonts not loading in IE9</h3>
|
||||
|
||||
<p>IE9, like Firefox, requires that fonts be served from the same domain as the website. Make sure that is the case.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>©2010-2011 Font Squirrel. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/svgnest/font/lato-hai-webfont.eot
Normal file
4241
public/svgnest/font/lato-hai-webfont.svg
Normal file
|
After Width: | Height: | Size: 229 KiB |
BIN
public/svgnest/font/lato-hai-webfont.ttf
Normal file
BIN
public/svgnest/font/lato-hai-webfont.woff
Normal file
612
public/svgnest/font/lato-lig-demo.html
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="specimen_files/easytabs.js" type="text/javascript" charset="utf-8"></script>
|
||||
<link rel="stylesheet" href="specimen_files/specimen_stylesheet.css" type="text/css" charset="utf-8" />
|
||||
<link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" />
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: 'latolight';
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>Lato Light Regular Specimen</title>
|
||||
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$(document).ready(function() {
|
||||
$('#container').easyTabs({defaultContent:1});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
Lato Light Regular </div>
|
||||
<ul class="tabs">
|
||||
<li><a href="#specimen">Specimen</a></li>
|
||||
<li><a href="#layout">Sample Layout</a></li>
|
||||
<li><a href="#glyphs">Glyphs & Languages</a></li>
|
||||
<li><a href="#installing">Installing Webfonts</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div id="main_content">
|
||||
|
||||
|
||||
<div id="specimen">
|
||||
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<div class="huge">AaBb</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="glyph_range">A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
<table class="sample_table">
|
||||
<tr><td>10</td><td class="size10">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>11</td><td class="size11">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>12</td><td class="size12">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>13</td><td class="size13">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>14</td><td class="size14">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>16</td><td class="size16">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>18</td><td class="size18">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>20</td><td class="size20">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>24</td><td class="size24">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>30</td><td class="size30">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>36</td><td class="size36">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>48</td><td class="size48">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>60</td><td class="size60">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>72</td><td class="size72">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
<tr><td>90</td><td class="size90">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ</td></tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="section" id="bodycomparison">
|
||||
|
||||
|
||||
<div id="xheight">
|
||||
<div class="fontbody">◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body</div><div class="arialbody">body</div><div class="verdanabody">body</div><div class="georgiabody">body</div></div>
|
||||
<div class="fontbody" style="z-index:1">
|
||||
body<span>Lato Light Regular</span>
|
||||
</div>
|
||||
<div class="arialbody" style="z-index:1">
|
||||
body<span>Arial</span>
|
||||
</div>
|
||||
<div class="verdanabody" style="z-index:1">
|
||||
body<span>Verdana</span>
|
||||
</div>
|
||||
<div class="georgiabody" style="z-index:1">
|
||||
body<span>Georgia</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section psample psample_row1" id="">
|
||||
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
<div class="section psample psample_row2" id="">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row4" id="">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="white_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="section psample psample_row1 fullreverse">
|
||||
<div class="grid2 firstcol">
|
||||
<p class="size10"><span>10.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size11"><span>11.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid3">
|
||||
<p class="size12"><span>12.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size13"><span>13.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample psample_row2 fullreverse">
|
||||
<div class="grid3 firstcol">
|
||||
<p class="size14"><span>14.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid4">
|
||||
<p class="size16"><span>16.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="grid5">
|
||||
<p class="size18"><span>18.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row3" id="">
|
||||
<div class="grid5 firstcol">
|
||||
<p class="size20"><span>20.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="grid7">
|
||||
<p class="size24"><span>24.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section psample fullreverse psample_row4" id="" style="border-bottom: 20px #000 solid;">
|
||||
<div class="grid12 firstcol">
|
||||
<p class="size30"><span>30.</span>Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.</p>
|
||||
</div>
|
||||
<div class="black_blend"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="layout">
|
||||
|
||||
<div class="section">
|
||||
|
||||
<div class="grid12 firstcol">
|
||||
<h1>Lorem Ipsum Dolor</h1>
|
||||
<h2>Etiam porta sem malesuada magna mollis euismod</h2>
|
||||
|
||||
<p class="byline">By <a href="#link">Aenean Lacinia</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="grid8 firstcol">
|
||||
<p class="large">Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
<h3>Pellentesque ornare sem</h3>
|
||||
|
||||
<p>Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit. </p>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p>
|
||||
|
||||
<p>Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur. </p>
|
||||
|
||||
<p>Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla. </p>
|
||||
|
||||
<h3>Cras mattis consectetur</h3>
|
||||
|
||||
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum. </p>
|
||||
|
||||
<p>Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid4 sidebar">
|
||||
|
||||
<div class="box reverse">
|
||||
<p class="last">Nullam quis risus eget urna mollis ornare vel eu leo. Donec ullamcorper nulla non metus auctor fringilla. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
|
||||
</div>
|
||||
|
||||
<p class="caption">Maecenas sed diam eget risus varius.</p>
|
||||
|
||||
<p>Vestibulum id ligula porta felis euismod semper. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Vestibulum id ligula porta felis euismod semper. Sed posuere consectetur est at lobortis. Maecenas sed diam eget risus varius blandit sit amet non magna. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
|
||||
|
||||
<p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Aenean lacinia bibendum nulla sed consectetur. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo. </p>
|
||||
|
||||
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec ullamcorper nulla non metus auctor fringilla. Maecenas faucibus mollis interdum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="glyphs">
|
||||
<div class="section">
|
||||
<div class="grid12 firstcol">
|
||||
|
||||
<h1>Language Support</h1>
|
||||
<p>The subset of Lato Light Regular in this kit supports the following languages:<br />
|
||||
|
||||
Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Swedish </p>
|
||||
<h1>Glyph Chart</h1>
|
||||
<p>The subset of Lato Light Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.</p>
|
||||
<div id="glyph_chart">
|
||||
|
||||
<div><p>&#13;</p> </div>
|
||||
<div><p>&#32;</p> </div>
|
||||
<div><p>&#33;</p>!</div>
|
||||
<div><p>&#34;</p>"</div>
|
||||
<div><p>&#35;</p>#</div>
|
||||
<div><p>&#36;</p>$</div>
|
||||
<div><p>&#37;</p>%</div>
|
||||
<div><p>&#38;</p>&</div>
|
||||
<div><p>&#39;</p>'</div>
|
||||
<div><p>&#40;</p>(</div>
|
||||
<div><p>&#41;</p>)</div>
|
||||
<div><p>&#42;</p>*</div>
|
||||
<div><p>&#43;</p>+</div>
|
||||
<div><p>&#44;</p>,</div>
|
||||
<div><p>&#45;</p>-</div>
|
||||
<div><p>&#46;</p>.</div>
|
||||
<div><p>&#47;</p>/</div>
|
||||
<div><p>&#48;</p>0</div>
|
||||
<div><p>&#49;</p>1</div>
|
||||
<div><p>&#50;</p>2</div>
|
||||
<div><p>&#51;</p>3</div>
|
||||
<div><p>&#52;</p>4</div>
|
||||
<div><p>&#53;</p>5</div>
|
||||
<div><p>&#54;</p>6</div>
|
||||
<div><p>&#55;</p>7</div>
|
||||
<div><p>&#56;</p>8</div>
|
||||
<div><p>&#57;</p>9</div>
|
||||
<div><p>&#58;</p>:</div>
|
||||
<div><p>&#59;</p>;</div>
|
||||
<div><p>&#60;</p><</div>
|
||||
<div><p>&#61;</p>=</div>
|
||||
<div><p>&#62;</p>></div>
|
||||
<div><p>&#63;</p>?</div>
|
||||
<div><p>&#64;</p>@</div>
|
||||
<div><p>&#65;</p>A</div>
|
||||
<div><p>&#66;</p>B</div>
|
||||
<div><p>&#67;</p>C</div>
|
||||
<div><p>&#68;</p>D</div>
|
||||
<div><p>&#69;</p>E</div>
|
||||
<div><p>&#70;</p>F</div>
|
||||
<div><p>&#71;</p>G</div>
|
||||
<div><p>&#72;</p>H</div>
|
||||
<div><p>&#73;</p>I</div>
|
||||
<div><p>&#74;</p>J</div>
|
||||
<div><p>&#75;</p>K</div>
|
||||
<div><p>&#76;</p>L</div>
|
||||
<div><p>&#77;</p>M</div>
|
||||
<div><p>&#78;</p>N</div>
|
||||
<div><p>&#79;</p>O</div>
|
||||
<div><p>&#80;</p>P</div>
|
||||
<div><p>&#81;</p>Q</div>
|
||||
<div><p>&#82;</p>R</div>
|
||||
<div><p>&#83;</p>S</div>
|
||||
<div><p>&#84;</p>T</div>
|
||||
<div><p>&#85;</p>U</div>
|
||||
<div><p>&#86;</p>V</div>
|
||||
<div><p>&#87;</p>W</div>
|
||||
<div><p>&#88;</p>X</div>
|
||||
<div><p>&#89;</p>Y</div>
|
||||
<div><p>&#90;</p>Z</div>
|
||||
<div><p>&#91;</p>[</div>
|
||||
<div><p>&#92;</p>\</div>
|
||||
<div><p>&#93;</p>]</div>
|
||||
<div><p>&#94;</p>^</div>
|
||||
<div><p>&#95;</p>_</div>
|
||||
<div><p>&#96;</p>`</div>
|
||||
<div><p>&#97;</p>a</div>
|
||||
<div><p>&#98;</p>b</div>
|
||||
<div><p>&#99;</p>c</div>
|
||||
<div><p>&#100;</p>d</div>
|
||||
<div><p>&#101;</p>e</div>
|
||||
<div><p>&#102;</p>f</div>
|
||||
<div><p>&#103;</p>g</div>
|
||||
<div><p>&#104;</p>h</div>
|
||||
<div><p>&#105;</p>i</div>
|
||||
<div><p>&#106;</p>j</div>
|
||||
<div><p>&#107;</p>k</div>
|
||||
<div><p>&#108;</p>l</div>
|
||||
<div><p>&#109;</p>m</div>
|
||||
<div><p>&#110;</p>n</div>
|
||||
<div><p>&#111;</p>o</div>
|
||||
<div><p>&#112;</p>p</div>
|
||||
<div><p>&#113;</p>q</div>
|
||||
<div><p>&#114;</p>r</div>
|
||||
<div><p>&#115;</p>s</div>
|
||||
<div><p>&#116;</p>t</div>
|
||||
<div><p>&#117;</p>u</div>
|
||||
<div><p>&#118;</p>v</div>
|
||||
<div><p>&#119;</p>w</div>
|
||||
<div><p>&#120;</p>x</div>
|
||||
<div><p>&#121;</p>y</div>
|
||||
<div><p>&#122;</p>z</div>
|
||||
<div><p>&#123;</p>{</div>
|
||||
<div><p>&#124;</p>|</div>
|
||||
<div><p>&#125;</p>}</div>
|
||||
<div><p>&#126;</p>~</div>
|
||||
<div><p>&#160;</p> </div>
|
||||
<div><p>&#161;</p>¡</div>
|
||||
<div><p>&#162;</p>¢</div>
|
||||
<div><p>&#163;</p>£</div>
|
||||
<div><p>&#164;</p>¤</div>
|
||||
<div><p>&#165;</p>¥</div>
|
||||
<div><p>&#166;</p>¦</div>
|
||||
<div><p>&#167;</p>§</div>
|
||||
<div><p>&#168;</p>¨</div>
|
||||
<div><p>&#169;</p>©</div>
|
||||
<div><p>&#170;</p>ª</div>
|
||||
<div><p>&#171;</p>«</div>
|
||||
<div><p>&#172;</p>¬</div>
|
||||
<div><p>&#173;</p>­</div>
|
||||
<div><p>&#174;</p>®</div>
|
||||
<div><p>&#175;</p>¯</div>
|
||||
<div><p>&#176;</p>°</div>
|
||||
<div><p>&#177;</p>±</div>
|
||||
<div><p>&#178;</p>²</div>
|
||||
<div><p>&#179;</p>³</div>
|
||||
<div><p>&#180;</p>´</div>
|
||||
<div><p>&#181;</p>µ</div>
|
||||
<div><p>&#182;</p>¶</div>
|
||||
<div><p>&#183;</p>·</div>
|
||||
<div><p>&#184;</p>¸</div>
|
||||
<div><p>&#185;</p>¹</div>
|
||||
<div><p>&#186;</p>º</div>
|
||||
<div><p>&#187;</p>»</div>
|
||||
<div><p>&#188;</p>¼</div>
|
||||
<div><p>&#189;</p>½</div>
|
||||
<div><p>&#190;</p>¾</div>
|
||||
<div><p>&#191;</p>¿</div>
|
||||
<div><p>&#192;</p>À</div>
|
||||
<div><p>&#193;</p>Á</div>
|
||||
<div><p>&#194;</p>Â</div>
|
||||
<div><p>&#195;</p>Ã</div>
|
||||
<div><p>&#196;</p>Ä</div>
|
||||
<div><p>&#197;</p>Å</div>
|
||||
<div><p>&#198;</p>Æ</div>
|
||||
<div><p>&#199;</p>Ç</div>
|
||||
<div><p>&#200;</p>È</div>
|
||||
<div><p>&#201;</p>É</div>
|
||||
<div><p>&#202;</p>Ê</div>
|
||||
<div><p>&#203;</p>Ë</div>
|
||||
<div><p>&#204;</p>Ì</div>
|
||||
<div><p>&#205;</p>Í</div>
|
||||
<div><p>&#206;</p>Î</div>
|
||||
<div><p>&#207;</p>Ï</div>
|
||||
<div><p>&#208;</p>Ð</div>
|
||||
<div><p>&#209;</p>Ñ</div>
|
||||
<div><p>&#210;</p>Ò</div>
|
||||
<div><p>&#211;</p>Ó</div>
|
||||
<div><p>&#212;</p>Ô</div>
|
||||
<div><p>&#213;</p>Õ</div>
|
||||
<div><p>&#214;</p>Ö</div>
|
||||
<div><p>&#215;</p>×</div>
|
||||
<div><p>&#216;</p>Ø</div>
|
||||
<div><p>&#217;</p>Ù</div>
|
||||
<div><p>&#218;</p>Ú</div>
|
||||
<div><p>&#219;</p>Û</div>
|
||||
<div><p>&#220;</p>Ü</div>
|
||||
<div><p>&#221;</p>Ý</div>
|
||||
<div><p>&#222;</p>Þ</div>
|
||||
<div><p>&#223;</p>ß</div>
|
||||
<div><p>&#224;</p>à</div>
|
||||
<div><p>&#225;</p>á</div>
|
||||
<div><p>&#226;</p>â</div>
|
||||
<div><p>&#227;</p>ã</div>
|
||||
<div><p>&#228;</p>ä</div>
|
||||
<div><p>&#229;</p>å</div>
|
||||
<div><p>&#230;</p>æ</div>
|
||||
<div><p>&#231;</p>ç</div>
|
||||
<div><p>&#232;</p>è</div>
|
||||
<div><p>&#233;</p>é</div>
|
||||
<div><p>&#234;</p>ê</div>
|
||||
<div><p>&#235;</p>ë</div>
|
||||
<div><p>&#236;</p>ì</div>
|
||||
<div><p>&#237;</p>í</div>
|
||||
<div><p>&#238;</p>î</div>
|
||||
<div><p>&#239;</p>ï</div>
|
||||
<div><p>&#240;</p>ð</div>
|
||||
<div><p>&#241;</p>ñ</div>
|
||||
<div><p>&#242;</p>ò</div>
|
||||
<div><p>&#243;</p>ó</div>
|
||||
<div><p>&#244;</p>ô</div>
|
||||
<div><p>&#245;</p>õ</div>
|
||||
<div><p>&#246;</p>ö</div>
|
||||
<div><p>&#247;</p>÷</div>
|
||||
<div><p>&#248;</p>ø</div>
|
||||
<div><p>&#249;</p>ù</div>
|
||||
<div><p>&#250;</p>ú</div>
|
||||
<div><p>&#251;</p>û</div>
|
||||
<div><p>&#252;</p>ü</div>
|
||||
<div><p>&#253;</p>ý</div>
|
||||
<div><p>&#254;</p>þ</div>
|
||||
<div><p>&#255;</p>ÿ</div>
|
||||
<div><p>&#338;</p>Œ</div>
|
||||
<div><p>&#339;</p>œ</div>
|
||||
<div><p>&#376;</p>Ÿ</div>
|
||||
<div><p>&#710;</p>ˆ</div>
|
||||
<div><p>&#732;</p>˜</div>
|
||||
<div><p>&#8192;</p> </div>
|
||||
<div><p>&#8193;</p> </div>
|
||||
<div><p>&#8194;</p> </div>
|
||||
<div><p>&#8195;</p> </div>
|
||||
<div><p>&#8196;</p> </div>
|
||||
<div><p>&#8197;</p> </div>
|
||||
<div><p>&#8198;</p> </div>
|
||||
<div><p>&#8199;</p> </div>
|
||||
<div><p>&#8200;</p> </div>
|
||||
<div><p>&#8201;</p> </div>
|
||||
<div><p>&#8202;</p> </div>
|
||||
<div><p>&#8208;</p>‐</div>
|
||||
<div><p>&#8209;</p>‑</div>
|
||||
<div><p>&#8210;</p>‒</div>
|
||||
<div><p>&#8211;</p>–</div>
|
||||
<div><p>&#8212;</p>—</div>
|
||||
<div><p>&#8216;</p>‘</div>
|
||||
<div><p>&#8217;</p>’</div>
|
||||
<div><p>&#8218;</p>‚</div>
|
||||
<div><p>&#8220;</p>“</div>
|
||||
<div><p>&#8221;</p>”</div>
|
||||
<div><p>&#8222;</p>„</div>
|
||||
<div><p>&#8226;</p>•</div>
|
||||
<div><p>&#8230;</p>…</div>
|
||||
<div><p>&#8239;</p> </div>
|
||||
<div><p>&#8249;</p>‹</div>
|
||||
<div><p>&#8250;</p>›</div>
|
||||
<div><p>&#8287;</p> </div>
|
||||
<div><p>&#8364;</p>€</div>
|
||||
<div><p>&#8482;</p>™</div>
|
||||
<div><p>&#9724;</p>◼</div>
|
||||
<div><p>&#64257;</p>fi</div>
|
||||
<div><p>&#64258;</p>fl</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="specs">
|
||||
|
||||
</div>
|
||||
|
||||
<div id="installing">
|
||||
<div class="section">
|
||||
<div class="grid7 firstcol">
|
||||
<h1>Installing Webfonts</h1>
|
||||
|
||||
<p>Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.</p>
|
||||
|
||||
<h2>1. Upload your webfonts</h2>
|
||||
<p>You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.</p>
|
||||
|
||||
<h2>2. Include the webfont stylesheet</h2>
|
||||
<p>A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the <a href="http://www.fontspring.com/blog/further-hardening-of-the-bulletproof-syntax">Fontspring blog post</a> about it. The code for it is as follows:</p>
|
||||
|
||||
|
||||
<code>
|
||||
@font-face{
|
||||
font-family: 'MyWebFont';
|
||||
src: url('WebFont.eot');
|
||||
src: url('WebFont.eot?#iefix') format('embedded-opentype'),
|
||||
url('WebFont.woff') format('woff'),
|
||||
url('WebFont.ttf') format('truetype'),
|
||||
url('WebFont.svg#webfont') format('svg');
|
||||
}
|
||||
</code>
|
||||
|
||||
<p>We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:</p>
|
||||
<code><link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /></code>
|
||||
|
||||
<h2>3. Modify your own stylesheet</h2>
|
||||
<p>To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:</p>
|
||||
<code>p { font-family: 'WebFont', Arial, sans-serif; }</code>
|
||||
|
||||
<h2>4. Test</h2>
|
||||
<p>Getting webfonts to work cross-browser <em>can</em> be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid5 sidebar">
|
||||
<div class="box">
|
||||
<h2>Troubleshooting<br />Font-Face Problems</h2>
|
||||
<p>Having trouble getting your webfonts to load in your new website? Here are some tips to sort out what might be the problem.</p>
|
||||
|
||||
<h3>Fonts not showing in any browser</h3>
|
||||
|
||||
<p>This sounds like you need to work on the plumbing. You either did not upload the fonts to the correct directory, or you did not link the fonts properly in the CSS. If you've confirmed that all this is correct and you still have a problem, take a look at your .htaccess file and see if requests are getting intercepted.</p>
|
||||
|
||||
<h3>Fonts not loading in iPhone or iPad</h3>
|
||||
|
||||
<p>The most common problem here is that you are serving the fonts from an IIS server. IIS refuses to serve files that have unknown MIME types. If that is the case, you must set the MIME type for SVG to "image/svg+xml" in the server settings. Follow these instructions from Microsoft if you need help.</p>
|
||||
|
||||
<h3>Fonts not loading in Firefox</h3>
|
||||
|
||||
<p>The primary reason for this failure? You are still using a version Firefox older than 3.5. So upgrade already! If that isn't it, then you are very likely serving fonts from a different domain. Firefox requires that all font assets be served from the same domain. Lastly it is possible that you need to add WOFF to your list of MIME types (if you are serving via IIS.)</p>
|
||||
|
||||
<h3>Fonts not loading in IE</h3>
|
||||
|
||||
<p>Are you looking at Internet Explorer on an actual Windows machine or are you cheating by using a service like Adobe BrowserLab? Many of these screenshot services do not render @font-face for IE. Best to test it on a real machine.</p>
|
||||
|
||||
<h3>Fonts not loading in IE9</h3>
|
||||
|
||||
<p>IE9, like Firefox, requires that fonts be served from the same domain as the website. Make sure that is the case.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="footer">
|
||||
<p>©2010-2011 Font Squirrel. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/svgnest/font/lato-lig-webfont.eot
Normal file
4241
public/svgnest/font/lato-lig-webfont.svg
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
public/svgnest/font/lato-lig-webfont.ttf
Normal file
BIN
public/svgnest/font/lato-lig-webfont.woff
Normal file
35
public/svgnest/font/latolatinfonts.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* Webfont: LatoLatin-Bold */@font-face {
|
||||
font-family: 'LatoLatinWeb';
|
||||
src: url('fonts/LatoLatin-Bold.eot'); /* IE9 Compat Modes */
|
||||
src: url('fonts/LatoLatin-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('fonts/LatoLatin-Bold.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Bold.woff') format('woff'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Bold.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* Webfont: LatoLatin-Regular */@font-face {
|
||||
font-family: 'LatoLatinWeb';
|
||||
src: url('fonts/LatoLatin-Regular.eot'); /* IE9 Compat Modes */
|
||||
src: url('fonts/LatoLatin-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('fonts/LatoLatin-Regular.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Regular.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* Webfont: LatoLatin-Light */@font-face {
|
||||
font-family: 'LatoLatinWebLight';
|
||||
src: url('fonts/LatoLatin-Light.eot'); /* IE9 Compat Modes */
|
||||
src: url('fonts/LatoLatin-Light.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('fonts/LatoLatin-Light.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Light.woff') format('woff'), /* Modern Browsers */
|
||||
url('fonts/LatoLatin-Light.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
7
public/svgnest/font/specimen_files/easytabs.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
(function($){$.fn.easyTabs=function(option){var param=jQuery.extend({fadeSpeed:"fast",defaultContent:1,activeClass:'active'},option);$(this).each(function(){var thisId="#"+this.id;if(param.defaultContent==''){param.defaultContent=1;}
|
||||
if(typeof param.defaultContent=="number")
|
||||
{var defaultTab=$(thisId+" .tabs li:eq("+(param.defaultContent-1)+") a").attr('href').substr(1);}else{var defaultTab=param.defaultContent;}
|
||||
$(thisId+" .tabs li a").each(function(){var tabToHide=$(this).attr('href').substr(1);$("#"+tabToHide).addClass('easytabs-tab-content');});hideAll();changeContent(defaultTab);function hideAll(){$(thisId+" .easytabs-tab-content").hide();}
|
||||
function changeContent(tabId){hideAll();$(thisId+" .tabs li").removeClass(param.activeClass);$(thisId+" .tabs li a[href=#"+tabId+"]").closest('li').addClass(param.activeClass);if(param.fadeSpeed!="none")
|
||||
{$(thisId+" #"+tabId).fadeIn(param.fadeSpeed);}else{$(thisId+" #"+tabId).show();}}
|
||||
$(thisId+" .tabs li").click(function(){var tabId=$(this).find('a').attr('href').substr(1);changeContent(tabId);return false;});});}})(jQuery);
|
||||
129
public/svgnest/font/specimen_files/grid_12-825-55-15.css
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*Notes about grid:
|
||||
Columns: 12
|
||||
Grid Width: 825px
|
||||
Column Width: 55px
|
||||
Gutter Width: 15px
|
||||
-------------------------------*/
|
||||
|
||||
|
||||
|
||||
.section {margin-bottom: 18px;
|
||||
}
|
||||
.section:after {content: ".";display: block;height: 0;clear: both;visibility: hidden;}
|
||||
.section {*zoom: 1;}
|
||||
|
||||
.section .firstcolumn,
|
||||
.section .firstcol {margin-left: 0;}
|
||||
|
||||
|
||||
/* Border on left hand side of a column. */
|
||||
.border {
|
||||
padding-left: 7px;
|
||||
margin-left: 7px;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* Border with more whitespace, spans one column. */
|
||||
.colborder {
|
||||
padding-left: 42px;
|
||||
margin-left: 42px;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The Grid Classes */
|
||||
.grid1, .grid1_2cols, .grid1_3cols, .grid1_4cols, .grid2, .grid2_3cols, .grid2_4cols, .grid3, .grid3_2cols, .grid3_4cols, .grid4, .grid4_3cols, .grid5, .grid5_2cols, .grid5_3cols, .grid5_4cols, .grid6, .grid6_4cols, .grid7, .grid7_2cols, .grid7_3cols, .grid7_4cols, .grid8, .grid8_3cols, .grid9, .grid9_2cols, .grid9_4cols, .grid10, .grid10_3cols, .grid10_4cols, .grid11, .grid11_2cols, .grid11_3cols, .grid11_4cols, .grid12
|
||||
{margin-left: 15px;float: left;display: inline; overflow: hidden;}
|
||||
|
||||
|
||||
.width1, .grid1, .span-1 {width: 55px;}
|
||||
.width1_2cols,.grid1_2cols {width: 20px;}
|
||||
.width1_3cols,.grid1_3cols {width: 8px;}
|
||||
.width1_4cols,.grid1_4cols {width: 2px;}
|
||||
.input_width1 {width: 49px;}
|
||||
|
||||
.width2, .grid2, .span-2 {width: 125px;}
|
||||
.width2_3cols,.grid2_3cols {width: 31px;}
|
||||
.width2_4cols,.grid2_4cols {width: 20px;}
|
||||
.input_width2 {width: 119px;}
|
||||
|
||||
.width3, .grid3, .span-3 {width: 195px;}
|
||||
.width3_2cols,.grid3_2cols {width: 90px;}
|
||||
.width3_4cols,.grid3_4cols {width: 37px;}
|
||||
.input_width3 {width: 189px;}
|
||||
|
||||
.width4, .grid4, .span-4 {width: 265px;}
|
||||
.width4_3cols,.grid4_3cols {width: 78px;}
|
||||
.input_width4 {width: 259px;}
|
||||
|
||||
.width5, .grid5, .span-5 {width: 335px;}
|
||||
.width5_2cols,.grid5_2cols {width: 160px;}
|
||||
.width5_3cols,.grid5_3cols {width: 101px;}
|
||||
.width5_4cols,.grid5_4cols {width: 72px;}
|
||||
.input_width5 {width: 329px;}
|
||||
|
||||
.width6, .grid6, .span-6 {width: 405px;}
|
||||
.width6_4cols,.grid6_4cols {width: 90px;}
|
||||
.input_width6 {width: 399px;}
|
||||
|
||||
.width7, .grid7, .span-7 {width: 475px;}
|
||||
.width7_2cols,.grid7_2cols {width: 230px;}
|
||||
.width7_3cols,.grid7_3cols {width: 148px;}
|
||||
.width7_4cols,.grid7_4cols {width: 107px;}
|
||||
.input_width7 {width: 469px;}
|
||||
|
||||
.width8, .grid8, .span-8 {width: 545px;}
|
||||
.width8_3cols,.grid8_3cols {width: 171px;}
|
||||
.input_width8 {width: 539px;}
|
||||
|
||||
.width9, .grid9, .span-9 {width: 615px;}
|
||||
.width9_2cols,.grid9_2cols {width: 300px;}
|
||||
.width9_4cols,.grid9_4cols {width: 142px;}
|
||||
.input_width9 {width: 609px;}
|
||||
|
||||
.width10, .grid10, .span-10 {width: 685px;}
|
||||
.width10_3cols,.grid10_3cols {width: 218px;}
|
||||
.width10_4cols,.grid10_4cols {width: 160px;}
|
||||
.input_width10 {width: 679px;}
|
||||
|
||||
.width11, .grid11, .span-11 {width: 755px;}
|
||||
.width11_2cols,.grid11_2cols {width: 370px;}
|
||||
.width11_3cols,.grid11_3cols {width: 241px;}
|
||||
.width11_4cols,.grid11_4cols {width: 177px;}
|
||||
.input_width11 {width: 749px;}
|
||||
|
||||
.width12, .grid12, .span-12 {width: 825px;}
|
||||
.input_width12 {width: 819px;}
|
||||
|
||||
/* Subdivided grid spaces */
|
||||
.emptycols_left1, .prepend-1 {padding-left: 70px;}
|
||||
.emptycols_right1, .append-1 {padding-right: 70px;}
|
||||
.emptycols_left2, .prepend-2 {padding-left: 140px;}
|
||||
.emptycols_right2, .append-2 {padding-right: 140px;}
|
||||
.emptycols_left3, .prepend-3 {padding-left: 210px;}
|
||||
.emptycols_right3, .append-3 {padding-right: 210px;}
|
||||
.emptycols_left4, .prepend-4 {padding-left: 280px;}
|
||||
.emptycols_right4, .append-4 {padding-right: 280px;}
|
||||
.emptycols_left5, .prepend-5 {padding-left: 350px;}
|
||||
.emptycols_right5, .append-5 {padding-right: 350px;}
|
||||
.emptycols_left6, .prepend-6 {padding-left: 420px;}
|
||||
.emptycols_right6, .append-6 {padding-right: 420px;}
|
||||
.emptycols_left7, .prepend-7 {padding-left: 490px;}
|
||||
.emptycols_right7, .append-7 {padding-right: 490px;}
|
||||
.emptycols_left8, .prepend-8 {padding-left: 560px;}
|
||||
.emptycols_right8, .append-8 {padding-right: 560px;}
|
||||
.emptycols_left9, .prepend-9 {padding-left: 630px;}
|
||||
.emptycols_right9, .append-9 {padding-right: 630px;}
|
||||
.emptycols_left10, .prepend-10 {padding-left: 700px;}
|
||||
.emptycols_right10, .append-10 {padding-right: 700px;}
|
||||
.emptycols_left11, .prepend-11 {padding-left: 770px;}
|
||||
.emptycols_right11, .append-11 {padding-right: 770px;}
|
||||
.pull-1 {margin-left: -70px;}
|
||||
.push-1 {margin-right: -70px;margin-left: 18px;float: right;}
|
||||
.pull-2 {margin-left: -140px;}
|
||||
.push-2 {margin-right: -140px;margin-left: 18px;float: right;}
|
||||
.pull-3 {margin-left: -210px;}
|
||||
.push-3 {margin-right: -210px;margin-left: 18px;float: right;}
|
||||
.pull-4 {margin-left: -280px;}
|
||||
.push-4 {margin-right: -280px;margin-left: 18px;float: right;}
|
||||
396
public/svgnest/font/specimen_files/specimen_stylesheet.css
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
@import url('grid_12-825-55-15.css');
|
||||
|
||||
/*
|
||||
CSS Reset by Eric Meyer - Released under Public Domain
|
||||
http://meyerweb.com/eric/tools/css/reset/
|
||||
*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center, dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend, table,
|
||||
caption, tbody, tfoot, thead, tr, th, td
|
||||
{margin: 0;padding: 0;border: 0;outline: 0;
|
||||
font-size: 100%;vertical-align: baseline;
|
||||
background: transparent;}
|
||||
body {line-height: 1;}
|
||||
ol, ul {list-style: none;}
|
||||
blockquote, q {quotes: none;}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {content: ''; content: none;}
|
||||
:focus {outline: 0;}
|
||||
ins {text-decoration: none;}
|
||||
del {text-decoration: line-through;}
|
||||
table {border-collapse: collapse;border-spacing: 0;}
|
||||
|
||||
|
||||
|
||||
|
||||
body {
|
||||
color: #000;
|
||||
background-color: #dcdcdc;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1883ba;
|
||||
}
|
||||
|
||||
h1{
|
||||
font-size: 32px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
h2{
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#container {
|
||||
width: 865px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
|
||||
|
||||
#header {
|
||||
padding: 20px;
|
||||
font-size: 36px;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#header span {
|
||||
color: #666;
|
||||
}
|
||||
#main_content {
|
||||
background-color: #fff;
|
||||
padding: 60px 20px 20px;
|
||||
}
|
||||
|
||||
|
||||
#footer p {
|
||||
margin: 0;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 50px;
|
||||
color: #333;
|
||||
font: 10px Arial, sans-serif;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
width: 100%;
|
||||
height: 31px;
|
||||
background-color: #444;
|
||||
}
|
||||
.tabs li {
|
||||
float: left;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: #444;
|
||||
}
|
||||
.tabs li a {
|
||||
display: block;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font: bold 11px/11px 'Arial';
|
||||
text-transform: uppercase;
|
||||
padding: 10px 15px;
|
||||
border-right: 1px solid #fff;
|
||||
}
|
||||
|
||||
.tabs li a:hover {
|
||||
background-color: #00b3ff;
|
||||
|
||||
}
|
||||
|
||||
.tabs li.active a {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.huge {
|
||||
|
||||
font-size: 300px;
|
||||
line-height: 1em;
|
||||
padding: 0;
|
||||
letter-spacing: -.02em;
|
||||
overflow: hidden;
|
||||
}
|
||||
div.glyph_range {
|
||||
font-size: 72px;
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
.size10{ font-size: 10px; }
|
||||
.size11{ font-size: 11px; }
|
||||
.size12{ font-size: 12px; }
|
||||
.size13{ font-size: 13px; }
|
||||
.size14{ font-size: 14px; }
|
||||
.size16{ font-size: 16px; }
|
||||
.size18{ font-size: 18px; }
|
||||
.size20{ font-size: 20px; }
|
||||
.size24{ font-size: 24px; }
|
||||
.size30{ font-size: 30px; }
|
||||
.size36{ font-size: 36px; }
|
||||
.size48{ font-size: 48px; }
|
||||
.size60{ font-size: 60px; }
|
||||
.size72{ font-size: 72px; }
|
||||
.size90{ font-size: 90px; }
|
||||
|
||||
|
||||
.psample_row1 { height: 120px;}
|
||||
.psample_row1 { height: 120px;}
|
||||
.psample_row2 { height: 160px;}
|
||||
.psample_row3 { height: 160px;}
|
||||
.psample_row4 { height: 160px;}
|
||||
|
||||
.psample {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.psample p {
|
||||
line-height: 1.3em;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.psample span {
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.white_blend {
|
||||
width: 100%;
|
||||
height: 61px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNrs3TsKgFAMRUE/eer+NxztxMYuEWQG3ECKwwUF58ycAKixOAGAyAKILAAiCyCyACILgMgCiCyAyAIgsgAiCyCyAIgsgMgCiCwAIgsgsgAiC4DIAogsACIL0CWuZ3UGgLrIhjMA1EV2OAOAJQtgyQLwjOzmDAAiCyCyAIgsQFtkd2cAEFkAkQVAZAHaIns4A4AlC2DJAiCyACILILIAiCzAV5H1dQGAJQsgsgCILIDIAvwisl58AViyAJYsACILILIAIgvAe2T9EhxAZAFEFgCRBeiL7HAGgLrIhjMAWLIAliwAt1OAAQDwygTBulLIlQAAAABJRU5ErkJggg==);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
.black_blend {
|
||||
width: 100%;
|
||||
height: 61px;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNrs3TEKhTAQRVGjibr/9QoxhY2N3Ywo50A28IrLwP9g6b1PAMSYTQAgsgAiC4DIAogsgMgCILIAIgsgsgCILIDIAogsACILILIAIguAyAKILIDIAiCyACILgMgCZCnjLWYAiFGvB0BQZJsZAFyyAC5ZAO6RXc0AILIAIguAyAKkRXYzA4DIAogsACILkBbZ3QwALlkAlywAIgsgsgAiC4DIArwVWf8uAHDJAogsACILILIAv4isH74AXLIALlkARBZAZAFEFoDnyPokOIDIAogsACILkBfZZgaAuMhWMwC4ZAE+p4x3mAEgxinAAJ+XBbPWGkwAAAAAAElFTkSuQmCC);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
.fullreverse {
|
||||
background: #000 !important;
|
||||
color: #fff !important;
|
||||
margin-left: -20px;
|
||||
padding-left: 20px;
|
||||
margin-right: -20px;
|
||||
padding-right: 20px;
|
||||
padding: 20px;
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
|
||||
.sample_table td {
|
||||
padding-top: 3px;
|
||||
padding-bottom:5px;
|
||||
padding-left: 5px;
|
||||
vertical-align: middle;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
.sample_table td:first-child {
|
||||
background-color: #eee;
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
padding-left: 0;
|
||||
padding: 5px;
|
||||
font: 11px/12px "Courier New", Courier, mono;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: pre;
|
||||
background-color: #eee;
|
||||
display: block;
|
||||
padding: 10px;
|
||||
margin-bottom: 18px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.bottom,.last {margin-bottom:0 !important; padding-bottom:0 !important;}
|
||||
|
||||
.box {
|
||||
padding: 18px;
|
||||
margin-bottom: 18px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.reverse,.reversed { background: #000 !important;color: #fff !important; border: none !important;}
|
||||
|
||||
#bodycomparison {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
font-size: 72px;
|
||||
height: 90px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#bodycomparison div{
|
||||
font-size: 72px;
|
||||
line-height: 90px;
|
||||
display: inline;
|
||||
margin: 0 15px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#bodycomparison div span{
|
||||
font: 10px Arial;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
#xheight {
|
||||
float: none;
|
||||
position: absolute;
|
||||
color: #d9f3ff;
|
||||
font-size: 72px;
|
||||
line-height: 90px;
|
||||
}
|
||||
|
||||
.fontbody {
|
||||
position: relative;
|
||||
}
|
||||
.arialbody{
|
||||
font-family: Arial;
|
||||
position: relative;
|
||||
}
|
||||
.verdanabody{
|
||||
font-family: Verdana;
|
||||
position: relative;
|
||||
}
|
||||
.georgiabody{
|
||||
font-family: Georgia;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* @group Layout page
|
||||
*/
|
||||
|
||||
#layout h1 {
|
||||
font-size: 36px;
|
||||
line-height: 42px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#layout h2 {
|
||||
font-size: 24px;
|
||||
line-height: 23px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#layout h3 {
|
||||
font-size: 22px;
|
||||
line-height: 1.4em;
|
||||
margin-top: 1em;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
#layout p.byline {
|
||||
font-size: 12px;
|
||||
margin-top: 18px;
|
||||
line-height: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#layout p {
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
#layout p.large{
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
#layout .sidebar p{
|
||||
font-size: 12px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
#layout p.caption {
|
||||
font-size: 10px;
|
||||
margin-top: -16px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Glyphs */
|
||||
|
||||
#glyph_chart div{
|
||||
background-color: #d9f3ff;
|
||||
color: black;
|
||||
float: left;
|
||||
font-size: 36px;
|
||||
height: 1.2em;
|
||||
line-height: 1.2em;
|
||||
margin-bottom: 1px;
|
||||
margin-right: 1px;
|
||||
text-align: center;
|
||||
width: 1.2em;
|
||||
position: relative;
|
||||
padding: .6em .2em .2em;
|
||||
}
|
||||
|
||||
#glyph_chart div p {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: block;
|
||||
text-align: center;
|
||||
font: bold 9px Arial, sans-serif;
|
||||
background-color: #3a768f;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
|
||||
#glyphs h1 {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
/* @end */
|
||||
|
||||
/* @group Installing */
|
||||
|
||||
#installing {
|
||||
font: 13px Arial, sans-serif;
|
||||
}
|
||||
|
||||
#installing p,
|
||||
#glyphs p{
|
||||
line-height: 1.2em;
|
||||
margin-bottom: 18px;
|
||||
font: 13px Arial, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#installing h3{
|
||||
font-size: 15px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
#rendering h1 {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.render_table td {
|
||||
font: 11px "Courier New", Courier, mono;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
30
public/svgnest/font/stylesheet.css
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* Generated by Font Squirrel (http://www.fontsquirrel.com) on July 12, 2014 */
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'latohairline';
|
||||
src: url('lato-hai-webfont.eot');
|
||||
src: url('lato-hai-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('lato-hai-webfont.woff') format('woff'),
|
||||
url('lato-hai-webfont.ttf') format('truetype'),
|
||||
url('lato-hai-webfont.svg#latohairline') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'latolight';
|
||||
src: url('lato-lig-webfont.eot');
|
||||
src: url('lato-lig-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('lato-lig-webfont.woff') format('woff'),
|
||||
url('lato-lig-webfont.ttf') format('truetype'),
|
||||
url('lato-lig-webfont.svg#latolight') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
BIN
public/svgnest/img/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
13
public/svgnest/img/close.svg
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st0{fill:#dddddd;}
|
||||
]]>
|
||||
</style>
|
||||
<polygon class="st0" points="340.2,160 255.8,244.3 171.8,160.4 160,172.2 244,256 160,339.9 171.8,351.6 255.8,267.8 340.2,352
|
||||
352,340.3 267.6,256 352,171.8 "/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 713 B |
21
public/svgnest/img/code.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<circle fill="#3bb34a" cx="173.602" cy="256.19" r="27.529"/>
|
||||
<circle fill="#3bb34a" cx="256.19" cy="256.19" r="27.529"/>
|
||||
<circle fill="#3bb34a" cx="338.778" cy="256.19" r="27.529"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#3bb34a" d="M155.059,412c-7.046,0-14.092-2.688-19.467-8.063L7.121,275.467c-10.751-10.752-10.751-28.183,0-38.933
|
||||
l128.471-128.47c10.751-10.75,28.182-10.75,38.933,0c10.749,10.75,10.749,28.181,0,38.932L65.521,256l109.004,109.004
|
||||
c10.749,10.751,10.749,28.181,0,38.932C169.148,409.312,162.105,412,155.059,412z"/>
|
||||
<path fill="#3bb34a" d="M356.941,412c7.046,0,14.092-2.688,19.467-8.063l128.47-128.47c10.752-10.752,10.752-28.183,0-38.933
|
||||
l-128.47-128.47c-10.752-10.75-28.182-10.75-38.934,0c-10.748,10.75-10.748,28.181,0,38.932L446.479,256L337.475,365.004
|
||||
c-10.748,10.751-10.748,28.181,0,38.932C342.852,409.312,349.896,412,356.941,412z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
public/svgnest/img/download.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a"> <path d="M 48.00,38.994c0.00,4.971-4.029,9.00-9.00,9.00l-5.268,0.00 l 2.64-2.64 c 0.966-0.972, 1.68-2.124, 2.115-3.36L39.00,41.994 c 1.659,0.00, 3.00-1.341, 3.00-3.00L42.00,11.997 L6.00,11.997 l0.00,26.997 c0.00,1.659, 1.344,3.00, 3.00,3.00l0.51,0.00 c 0.438,1.242, 1.152,2.397, 2.124,3.369l 2.634,2.631L9.00,47.994 c-4.971,0.00-9.00-4.029-9.00-9.00L0.00,8.997 c0.00-4.971, 4.029-9.00, 9.00-9.00l30.00,0.00 c 4.971,0.00, 9.00,4.029, 9.00,9.00L48.00,38.994 z M 9.00,2.997c-1.656,0.00-3.00,1.344-3.00,3.00s 1.344,3.00, 3.00,3.00s 3.00-1.344, 3.00-3.00S 10.656,2.997, 9.00,2.997z M 18.00,35.994l3.00,0.00 L21.00,26.997 c0.00-1.659, 1.344-3.00, 3.00-3.00 c 1.659,0.00, 3.00,1.341, 3.00,3.00l0.00,8.997 l3.00,0.00 c 1.212,0.00, 2.31,0.732, 2.772,1.854c 0.462,1.125, 0.204,2.415-0.651,3.27l-6.00,6.00C 25.536,47.703, 24.768,48.00, 24.00,48.00 s-1.536-0.297-2.121-0.882l-6.00-6.00c-0.858-0.855-1.113-2.151-0.651-3.27C 15.69,36.726, 16.788,35.994, 18.00,35.994z" ></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
46
public/svgnest/img/logo.svg
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="1000mm"
|
||||
height="1000mm"
|
||||
viewBox="0 0 1000 1000"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="logo.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#2d2d2d"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#454545"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="0.057101021"
|
||||
inkscape:cx="192.64104"
|
||||
inkscape:cy="-604.19235"
|
||||
inkscape:window-width="2194"
|
||||
inkscape:window-height="1138"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"><g
|
||||
id="g1"
|
||||
transform="translate(13.547694,22.337196)"><path
|
||||
style="fill:#20c5b5;fill-opacity:1"
|
||||
d="m 271.56929,741.91167 c -0.091,-0.14756 0.1372,-1.00514 0.5075,-1.90572 0.6346,-1.54353 22.1751,-50.80875 148.417,-339.44407 28.7625,-65.7615 52.7197,-120.551 53.2383,-121.7544 l 0.9428,-2.1881 h -18.0158 -18.0158 l -76.317,174.2676 c -41.9744,95.84719 -87.5411,199.9074 -101.2593,231.24493 -13.7182,31.33753 -25.1333,57.34685 -25.3668,57.79849 -0.2336,0.45164 -0.7092,0.98013 -1.057,1.17442 -0.4996,0.2791 -8.4542,0.33402 -37.8997,0.26166 -20.4971,-0.0504 -37.3083,-0.12994 -37.3582,-0.17681 -0.05,-0.0469 6.7005,-15.62895 15.0009,-34.62685 19.3618,-44.31487 155.6842,-356.26024 173.9466,-398.04024 l 13.8835,-31.762 -17.5022,-0.073 c -9.6261,-0.04 -17.59,0.024 -17.6974,0.1411 -0.166,0.1819 -160.2068,365.52815 -192.0371,438.38856 -7.4539,17.06209 -10.979,24.82126 -11.544,25.40961 l -0.8134,0.84698 h -5.8534 c -38.009999,0 -68.953899,-0.18458 -68.953899,-0.41132 0,-0.14858 5.5115,-12.88515 12.2477,-28.30348 15.9566,-36.52257 184.113899,-421.31205 203.429599,-465.50215 l 14.8707,-34.0206 150.1152,-0.071 c 82.5635,-0.039 150.1153,-0.018 150.1153,0.046 0,0.2284 -3.7189,8.7317 -84.8383,193.9853 -45.1487,103.10657 -96.5512,220.49706 -114.2278,260.86778 -17.6767,40.37073 -32.3592,73.56203 -32.6278,73.75846 -0.388,0.2837 -8.1659,0.35714 -37.8264,0.35714 -23.2847,0 -37.4004,-0.10098 -37.5038,-0.26829 z"
|
||||
id="path2" /><path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
d="m 394.13379,741.87517 c -0.073,-0.11762 5.8119,-13.80705 13.077,-30.42095 7.2651,-16.6139 48.2414,-110.31089 91.0584,-208.21553 42.817,-97.90465 87.3104,-199.67015 98.8743,-226.14555 11.5638,-26.4754 22.42275,-51.3319 24.13095,-55.2368 2.143,-4.8988 3.3665,-7.3494 3.9466,-7.9052 l 0.8407,-0.8055 h 33.7134 33.7134 l 0.7136,0.7137 c 0.4491,0.449 4.2591,8.823 10.2764,22.5863 5.2596,12.0299 19.0587,43.5979 30.6648,70.1509 33.8184,77.3715 90.147,206.18781 141.1725,322.84322 26.0474,59.55024 47.7254,109.15363 48.1733,110.22975 0.6285,1.51036 0.7326,2.00838 0.4564,2.18372 -0.1969,0.12494 -16.8487,0.2291 -37.0041,0.23148 -40.0627,0.005 -37.6025,0.10707 -38.8194,-1.61481 -0.3034,-0.42937 -4.8376,-10.94451 -10.0759,-23.36699 -32.5572,-77.2083 -177.6141,-420.70687 -178.8963,-423.63117 l -0.5556,-1.267 -3.0975,7.3371 c -1.7036,4.0354 -44.29755,104.956 -94.65315,224.26813 -54.5055,129.14474 -91.8182,217.20384 -92.2044,217.60508 l -0.6487,0.67398 h -37.3623 c -20.5492,0 -37.4218,-0.0962 -37.4944,-0.21386 z"
|
||||
id="path1" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
1
public/svgnest/img/settings.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a"> <path d="M 45.00,21.00l-3.00,0.00 c-0.105,0.00-0.192,0.051-0.297,0.06 c-0.456-2.769-1.527-5.316-3.093-7.506c 0.075-0.063, 0.168-0.087, 0.24-0.159l 2.121-2.121c 1.173-1.173, 1.173-3.069,0.00-4.242 s-3.072-1.173-4.245,0.00L 34.605,9.15c-0.069,0.069-0.096,0.165-0.159,0.24C 32.259,7.821, 29.709,6.753, 26.94,6.297 C 26.949,6.192, 27.00,6.105, 27.00,6.00L27.00,3.00 c0.00-1.656-1.341-3.00-3.00-3.00S 21.00,1.344, 21.00,3.00l0.00,3.00 c0.00,0.105, 0.051,0.192, 0.06,0.297 C 18.291,6.753, 15.741,7.821, 13.554,9.39C 13.491,9.315, 13.464,9.222, 13.395,9.15L 11.274,7.029c-1.173-1.173-3.072-1.173-4.245,0.00 c-1.17,1.173-1.17,3.069,0.00,4.242l 2.124,2.121C 9.222,13.464, 9.312,13.491, 9.39,13.554C 7.821,15.744, 6.753,18.291, 6.297,21.06 C 6.192,21.051, 6.105,21.00, 6.00,21.00L3.00,21.00 C 1.341,21.00,0.00,22.344,0.00,24.00s 1.341,3.00, 3.00,3.00l3.00,0.00 c 0.105,0.00, 0.192-0.048, 0.297-0.06 c 0.456,2.769, 1.527,5.316, 3.093,7.506c-0.075,0.063-0.168,0.087-0.237,0.159l-2.124,2.121c-1.17,1.173-1.17,3.072,0.00,4.242 c 1.173,1.173, 3.072,1.173, 4.245,0.00l 2.121-2.121c 0.069-0.069, 0.096-0.165, 0.159-0.24c 2.187,1.569, 4.737,2.637, 7.506,3.096 C 21.051,41.808, 21.00,41.895, 21.00,42.00l0.00,3.00 c0.00,1.659, 1.341,3.00, 3.00,3.00s 3.00-1.341, 3.00-3.00l0.00,-3.00 c0.00-0.105-0.051-0.192-0.06-0.297 c 2.769-0.459, 5.316-1.527, 7.506-3.096c 0.063,0.075, 0.087,0.171, 0.159,0.24l 2.121,2.121c 1.173,1.173, 3.072,1.173, 4.245,0.00 c 1.173-1.17, 1.173-3.069,0.00-4.242l-2.121-2.121c-0.072-0.069-0.165-0.093-0.24-0.159c 1.566-2.19, 2.637-4.737, 3.093-7.506 C 41.808,26.952, 41.895,27.00, 42.00,27.00l3.00,0.00 c 1.659,0.00, 3.00-1.344, 3.00-3.00S 46.659,21.00, 45.00,21.00z M 24.00,33.00c-4.971,0.00-9.00-4.032-9.00-9.00c0.00-4.971, 4.029-9.00, 9.00-9.00s 9.00,4.029, 9.00,9.00 C 33.00,28.968, 28.971,33.00, 24.00,33.00z" ></path></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
1
public/svgnest/img/spin.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><svg width='120px' height='120px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-spin"><rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><g transform="translate(50 50)"><g transform="rotate(0) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(45) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.12s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.12s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(90) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.25s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.25s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(135) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.37s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.37s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(180) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.5s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.5s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(225) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.62s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.62s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(270) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.75s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.75s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g><g transform="rotate(315) translate(34 0)"><circle cx="0" cy="0" r="8" fill="#3bb34a"><animate attributeName="opacity" from="1" to="0.1" begin="0.87s" dur="1s" repeatCount="indefinite"></animate><animateTransform attributeName="transform" type="scale" from="1.5" to="1" begin="0.87s" dur="1s" repeatCount="indefinite"></animateTransform></circle></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3 KiB |
1
public/svgnest/img/start.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a"> <path d="M 12.00,39.00c-0.549,0.00-1.095-0.15-1.578-0.447C 9.54,38.004, 9.00,37.041, 9.00,36.00L9.00,12.00 c0.00-1.041, 0.54-2.007, 1.422-2.553C 10.905,9.153, 11.451,9.00, 12.00,9.00c 0.456,0.00, 0.921,0.105, 1.341,0.315l 24.00,12.00C 38.358,21.825, 39.00,22.863, 39.00,24.00 s-0.642,2.178-1.659,2.685l-24.00,12.00C 12.921,38.895, 12.456,39.00, 12.00,39.00z" ></path></svg>
|
||||
|
After Width: | Height: | Size: 786 B |
1
public/svgnest/img/upload.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: IcoMoon.io --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a"> <path d="M 39.00,48.00l-6.00,0.00 l0.00,-6.00 l6.00,0.00 c 1.659,0.00, 3.00-1.341, 3.00-3.00L42.00,12.00 L6.00,12.00 l0.00,27.00 c0.00,1.659, 1.341,3.00, 3.00,3.00l6.00,0.00 l0.00,6.00 L9.00,48.00 c-4.971,0.00-9.00-4.032-9.00-9.00L0.00,9.00 c0.00-4.971, 4.029-9.00, 9.00-9.00l30.00,0.00 c 4.971,0.00, 9.00,4.029, 9.00,9.00l0.00,30.00 C 48.00,43.968, 43.971,48.00, 39.00,48.00z M 9.00,3.00C 7.341,3.00, 6.00,4.344, 6.00,6.00 s 1.341,3.00, 3.00,3.00s 3.00-1.344, 3.00-3.00S 10.659,3.00, 9.00,3.00z M 21.879,24.876C 22.464,24.291, 23.232,23.997, 24.00,23.997s 1.536,0.294, 2.121,0.879l 6.00,6.00 c 0.855,0.858, 1.113,2.148, 0.651,3.273C 32.31,35.268, 31.212,36.00, 30.00,36.00L27.00,36.00 l0.00,9.00 c0.00,1.659-1.341,3.00-3.00,3.00c-1.656,0.00-3.00-1.341-3.00-3.00l0.00,-9.00 L18.00,36.00 c-1.212,0.00-2.31-0.732-2.772-1.851c-0.462-1.122-0.207-2.415, 0.651-3.273L 21.879,24.876z" ></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
5
public/svgnest/img/zoomin.svg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48" height="48" viewBox="0 0 24 24" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a">
|
||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 591 B |
4
public/svgnest/img/zoomout.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="48" height="48" viewBox="0 0 24 24" enable-background="new 0 0 16 16" xml:space="preserve" fill="#3bb34a">
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 552 B |
912
public/svgnest/index.html
Normal file
|
|
@ -0,0 +1,912 @@
|
|||
<!doctype html>
|
||||
<html itemscope="" itemtype="http://schema.org/WebPage" lang="en">
|
||||
<head><base href="/svgnest/">
|
||||
<link rel="shortcut icon" href="/favicon32.gif" type="image/x-icon" sizes="32x32" />
|
||||
<link rel="shortcut icon" href="/favicon16.gif" type="image/x-icon" sizes="16x16" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>MAnest - MakeArmy hosted nesting app powered by SVGnest!</title>
|
||||
|
||||
<meta name="description" content="A completely free and open source application for automatic nesting. Comes with advanced features like part-in-part nesting and concave area detection." />
|
||||
|
||||
<link type="text/css" rel="stylesheet" media="all" href="font/latolatinfonts.css" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<script src="util/pathsegpolyfill.js"></script>
|
||||
<script src="util/matrix.js"></script>
|
||||
<script src="util/domparser.js"></script>
|
||||
<script src="util/clipper.js"></script>
|
||||
<script src="util/parallel.js"></script>
|
||||
<script src="util/geometryutil.js"></script>
|
||||
<script src="util/placementworker.js"></script>
|
||||
<script src="svgparser.js"></script>
|
||||
<script src="svgnest.js"></script>
|
||||
|
||||
<script src="util/filesaver.js"></script>
|
||||
|
||||
<script>
|
||||
// UI-specific stuff, button clicks go here
|
||||
function ready(fn){
|
||||
if (document.readyState != 'loading'){
|
||||
fn();
|
||||
}
|
||||
else {
|
||||
document.addEventListener('DOMContentLoaded', fn);
|
||||
}
|
||||
}
|
||||
|
||||
ready(function(){
|
||||
// FAQ toggle
|
||||
var faq = document.getElementById('faq');
|
||||
var faqbutton = document.getElementById('faqbutton');
|
||||
|
||||
var faqvisible = false;
|
||||
faqbutton.onclick = function(e){
|
||||
if(!faqvisible){
|
||||
faq.setAttribute('style','display: block');
|
||||
}
|
||||
else{
|
||||
faq.removeAttribute('style');
|
||||
}
|
||||
faqvisible = !faqvisible;
|
||||
};
|
||||
|
||||
function hideSplash(){
|
||||
var splash = document.getElementById('splash');
|
||||
var svgnest = document.getElementById('svgnest');
|
||||
if(splash){
|
||||
splash.remove();
|
||||
}
|
||||
svgnest.setAttribute('style','display: block');
|
||||
}
|
||||
|
||||
var demo = document.getElementById('demo');
|
||||
var upload = document.getElementById('upload');
|
||||
var display = document.getElementById('select');
|
||||
|
||||
demo.onclick = function(){
|
||||
try{
|
||||
var svg = window.SvgNest.parsesvg(display.innerHTML);
|
||||
display.innerHTML = '';
|
||||
display.appendChild(svg);
|
||||
}
|
||||
catch(e){
|
||||
message.innerHTML = e;
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
hideSplash();
|
||||
message.innerHTML = 'Click on the outline to use as the bin';
|
||||
message.className = 'active animated bounce';
|
||||
|
||||
attachSvgListeners(svg);
|
||||
};
|
||||
|
||||
var message = document.getElementById('message');
|
||||
|
||||
if(!document.createElementNS || !document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect){
|
||||
message.innerHTML = 'Your browser does not have SVG support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
if (!window.SvgNest) {
|
||||
message.innerHTML = "Couldn't initialize SVGnest";
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
if(!window.File || !window.FileReader){
|
||||
message.innerHTML = 'Your browser does not have file upload support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
if(!window.Worker){
|
||||
message.innerHTML = 'Your browser does not have web worker support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
// button clicks
|
||||
var upload = document.getElementById('upload');
|
||||
var start = document.getElementById('start');
|
||||
var download = document.getElementById('download');
|
||||
var startlabel = document.getElementById('startlabel');
|
||||
var fileinput = document.getElementById('fileinput');
|
||||
|
||||
var config = document.getElementById('config');
|
||||
var configbutton = document.getElementById('configbutton');
|
||||
var configsave = document.getElementById('configsave');
|
||||
|
||||
var zoomin = document.getElementById('zoominbutton');
|
||||
var zoomout = document.getElementById('zoomoutbutton');
|
||||
var exit = document.getElementById('exitbutton');
|
||||
|
||||
var isworking = false;
|
||||
|
||||
start.onclick = function(){
|
||||
if(this.className == 'button start disabled'){
|
||||
return false;
|
||||
}
|
||||
iterations = 0;
|
||||
if(isworking){
|
||||
stopnest();
|
||||
}
|
||||
else{
|
||||
startnest();
|
||||
}
|
||||
|
||||
display.className = 'disabled';
|
||||
document.getElementById('info_time').setAttribute('style','display: none');
|
||||
};
|
||||
|
||||
function startnest(){
|
||||
// Once started, don't allow this anymore
|
||||
document.removeEventListener('dragover', FileDragHover, false);
|
||||
document.removeEventListener('dragleave', FileDragHover, false);
|
||||
document.removeEventListener('drop', FileDrop, false);
|
||||
|
||||
SvgNest.start(progress, renderSvg);
|
||||
startlabel.innerHTML = 'Stop Nest';
|
||||
start.className = 'button spinner';
|
||||
configbutton.className = 'button config disabled';
|
||||
config.className = '';
|
||||
zoomin.className = 'button zoomin disabled';
|
||||
zoomout.className = 'button zoomout disabled';
|
||||
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.removeAttribute('style');
|
||||
}
|
||||
|
||||
isworking = true;
|
||||
}
|
||||
|
||||
function stopnest(){
|
||||
SvgNest.stop();
|
||||
startlabel.innerHTML = 'Start Nest';
|
||||
start.className = 'button start';
|
||||
configbutton.className = 'button config';
|
||||
|
||||
isworking = false;
|
||||
}
|
||||
|
||||
// config
|
||||
var configvisible = false;
|
||||
configbutton.onclick = function(){
|
||||
if(this.className == 'button config disabled'){
|
||||
return false;
|
||||
}
|
||||
if(!configvisible){
|
||||
config.className = 'active';
|
||||
configbutton.className = 'button close';
|
||||
}
|
||||
else{
|
||||
config.className = '';
|
||||
configbutton.className = 'button config';
|
||||
}
|
||||
configvisible = !configvisible;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
configsave.onclick = function(){
|
||||
var c = {};
|
||||
var inputs = document.querySelectorAll('#config input');
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
var key = inputs[i].getAttribute('data-config');
|
||||
if (inputs[i].getAttribute('type') === 'text') {
|
||||
c[key] = inputs[i].value;
|
||||
} else if (inputs[i].getAttribute('type') === 'checkbox') {
|
||||
c[key] = inputs[i].checked;
|
||||
}
|
||||
}
|
||||
|
||||
window.SvgNest.config(c);
|
||||
|
||||
if (isworking) stopnest(); // invalidate current nest
|
||||
configvisible = false;
|
||||
config.className = '';
|
||||
configbutton.className = 'button config'; // <— ensure the gear comes back
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
upload.onclick = function(){
|
||||
fileinput.click();
|
||||
}
|
||||
document.addEventListener('dragover', FileDragHover, false);
|
||||
document.addEventListener('dragleave', FileDragHover, false);
|
||||
document.addEventListener('drop', FileDrop, false);
|
||||
function FileDragHover(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
upload.style.backgroundColor = (e.type == "dragover" ? "#d7e9b7" : "");
|
||||
}
|
||||
function FileDrop(e){
|
||||
e.stopPropagation(); // Make sure not to replace website by file
|
||||
e.preventDefault();
|
||||
handleFile(e.dataTransfer.files[0]);
|
||||
}
|
||||
|
||||
|
||||
download.onclick = function(){
|
||||
if(download.className == 'button download disabled'){
|
||||
return false;
|
||||
}
|
||||
|
||||
var bins = document.getElementById('bins');
|
||||
|
||||
if(bins.children.length == 0){
|
||||
message.innerHTML = 'No SVG to export';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
var svg;
|
||||
svg = display.querySelector('svg');
|
||||
|
||||
if(!svg){
|
||||
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
||||
}
|
||||
|
||||
svg = svg.cloneNode(false);
|
||||
|
||||
// maintain stroke, fill etc of input
|
||||
if(SvgNest.style){
|
||||
svg.appendChild(SvgNest.style);
|
||||
}
|
||||
|
||||
var binHeight = parseInt(bins.children[0].getAttribute('height'));
|
||||
|
||||
for(var i=0; i<bins.children.length; i++){
|
||||
var b = bins.children[i];
|
||||
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
||||
group.setAttribute('transform', 'translate(0 '+binHeight*1.1*i+')');
|
||||
for(var j=0; j<b.children.length; j++){
|
||||
group.appendChild(b.children[j].cloneNode(true));
|
||||
}
|
||||
|
||||
svg.appendChild(group);
|
||||
}
|
||||
|
||||
var output;
|
||||
if(typeof XMLSerializer != 'undefined'){
|
||||
output = (new XMLSerializer()).serializeToString(svg);
|
||||
}
|
||||
else{
|
||||
output = svg.outerHTML;
|
||||
}
|
||||
|
||||
var blob = new Blob([output], {type: "image/svg+xml;charset=utf-8"});
|
||||
saveAs(blob, "SVGnest-output.svg");
|
||||
}
|
||||
|
||||
var zoomlevel = 1.0;
|
||||
|
||||
zoomin.onclick = function(){
|
||||
if(this.className == 'button zoomin disabled'){
|
||||
return false;
|
||||
}
|
||||
zoomlevel *= 1.2;
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.setAttribute('style', 'transform-origin: top left; transform:scale('+zoomlevel+'); -webkit-transform:scale('+zoomlevel+'); -moz-transform:scale('+zoomlevel+'); -ms-transform:scale('+zoomlevel+'); -o-transform:scale('+zoomlevel+');');
|
||||
}
|
||||
}
|
||||
|
||||
zoomout.onclick = function(){
|
||||
if(this.className == 'button zoomout disabled'){
|
||||
return false;
|
||||
}
|
||||
zoomlevel *= 0.8;
|
||||
if(zoomlevel < 0.02){
|
||||
zoomlevel = 0.02;
|
||||
}
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.setAttribute('style', 'transform-origin: top left; transform:scale('+zoomlevel+'); -webkit-transform:scale('+zoomlevel+'); -moz-transform:scale('+zoomlevel+'); -ms-transform:scale('+zoomlevel+'); -o-transform:scale('+zoomlevel+');');
|
||||
}
|
||||
}
|
||||
|
||||
exit.onclick = function(){
|
||||
location.reload();
|
||||
}
|
||||
|
||||
fileinput.onchange = function(e){
|
||||
handleFile(e.target.files[0]);
|
||||
}
|
||||
|
||||
|
||||
function handleFile(file){
|
||||
if(!file){
|
||||
return;
|
||||
}
|
||||
|
||||
if(!file.type || (file.type.search('svg') < 0 && file.type.search('xml') < 0 && file.type.search('text') < 0)){
|
||||
message.innerHTML = 'Only SVG files allowed';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
var reader = new FileReader();
|
||||
var input = this;
|
||||
reader.onload = function(e) {
|
||||
input.value = null;
|
||||
|
||||
if(reader.result){
|
||||
try{
|
||||
var svg = window.SvgNest.parsesvg(reader.result);
|
||||
{
|
||||
var wholeSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
// Copy relevant scaling info
|
||||
wholeSVG.setAttribute('width',svg.getAttribute('width'));
|
||||
wholeSVG.setAttribute('height',svg.getAttribute('height'));
|
||||
wholeSVG.setAttribute('viewBox',svg.getAttribute('viewBox'));
|
||||
var rect = document.createElementNS(wholeSVG.namespaceURI,'rect');
|
||||
rect.setAttribute('x', wholeSVG.viewBox.baseVal.x);
|
||||
rect.setAttribute('y', wholeSVG.viewBox.baseVal.x);
|
||||
rect.setAttribute('width', wholeSVG.viewBox.baseVal.width);
|
||||
rect.setAttribute('height', wholeSVG.viewBox.baseVal.height);
|
||||
rect.setAttribute('class', 'fullRect');
|
||||
wholeSVG.appendChild(rect);
|
||||
}
|
||||
display.innerHTML = '';
|
||||
display.appendChild(wholeSVG); // As a default bin in background
|
||||
display.appendChild(svg);
|
||||
}
|
||||
catch(e){
|
||||
message.innerHTML = e;
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
hideSplash();
|
||||
message.innerHTML = 'Click on the outline to use as the bin';
|
||||
message.className = 'active animated bounce';
|
||||
start.className = 'button start disabled';
|
||||
|
||||
attachSvgListeners(svg);
|
||||
attachSvgListeners(wholeSVG);
|
||||
}
|
||||
}
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
function attachSvgListeners(svg){
|
||||
// attach event listeners
|
||||
for(var i=0; i<svg.childNodes.length; i++){
|
||||
var node = svg.childNodes[i];
|
||||
if(node.nodeType == 1){
|
||||
node.onclick = function(){
|
||||
if(display.className == 'disabled'){
|
||||
return;
|
||||
}
|
||||
var currentbin = document.querySelector('#select .active');
|
||||
if(currentbin){
|
||||
var className = currentbin.getAttribute('class').replace('active', '').trim();
|
||||
if(!className)
|
||||
currentbin.removeAttribute('class');
|
||||
else
|
||||
currentbin.setAttribute('class', className);
|
||||
}
|
||||
|
||||
window.SvgNest.setbin(this);
|
||||
this.setAttribute('class',(this.getAttribute('class') ? this.getAttribute('class')+' ' : '') + 'active');
|
||||
|
||||
start.className = 'button start animated bounce';
|
||||
message.className = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var prevpercent = 0;
|
||||
var startTime = null;
|
||||
|
||||
function progress(percent){
|
||||
var transition = percent > prevpercent ? '; transition: width 0.1s' : '';
|
||||
document.getElementById('info_progress').setAttribute('style','width: '+Math.round(percent*100)+'% ' + transition);
|
||||
document.getElementById('info').setAttribute('style','display: block');
|
||||
|
||||
prevpercent = percent;
|
||||
|
||||
var now = new Date().getTime();
|
||||
if(startTime && now){
|
||||
var diff = now-startTime;
|
||||
// show a time estimate for long-running placements
|
||||
var estimate = (diff/percent)*(1-percent);
|
||||
document.getElementById('info_time').innerHTML = millisecondsToStr(estimate)+' remaining';
|
||||
|
||||
if(diff > 5000 && percent < 0.3 && percent > 0.02 && estimate > 10000){
|
||||
document.getElementById('info_time').setAttribute('style','display: block');
|
||||
}
|
||||
}
|
||||
|
||||
if(percent > 0.95 || percent < 0.02){
|
||||
document.getElementById('info_time').setAttribute('style','display: none');
|
||||
}
|
||||
if(percent < 0.02){
|
||||
startTime = new Date().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
var iterations = 0;
|
||||
|
||||
function renderSvg(svglist, efficiency, placed, total){
|
||||
iterations++;
|
||||
document.getElementById('info_iterations').innerHTML = iterations;
|
||||
|
||||
if(!svglist || svglist.length == 0){
|
||||
return;
|
||||
}
|
||||
var bins = document.getElementById('bins');
|
||||
bins.innerHTML = '';
|
||||
|
||||
for(var i=0; i<svglist.length; i++){
|
||||
if(svglist.length > 2){
|
||||
svglist[i].setAttribute('class','grid');
|
||||
}
|
||||
bins.appendChild(svglist[i]);
|
||||
}
|
||||
|
||||
if(efficiency || efficiency === 0){
|
||||
document.getElementById('info_efficiency').innerHTML = Math.round(efficiency*100);
|
||||
}
|
||||
|
||||
document.getElementById('info_placed').innerHTML = placed+'/'+total;
|
||||
|
||||
document.getElementById('info_placement').setAttribute('style','display: block');
|
||||
display.setAttribute('style','display: none');
|
||||
download.className = 'button download animated bounce';
|
||||
}
|
||||
|
||||
message.onclick = function(e){
|
||||
this.className='';
|
||||
}
|
||||
|
||||
function millisecondsToStr (milliseconds) {
|
||||
function numberEnding (number) {
|
||||
return (number > 1) ? 's' : '';
|
||||
}
|
||||
|
||||
var temp = Math.floor(milliseconds / 1000);
|
||||
var years = Math.floor(temp / 31536000);
|
||||
if (years) {
|
||||
return years + ' year' + numberEnding(years);
|
||||
}
|
||||
var days = Math.floor((temp %= 31536000) / 86400);
|
||||
if (days) {
|
||||
return days + ' day' + numberEnding(days);
|
||||
}
|
||||
var hours = Math.floor((temp %= 86400) / 3600);
|
||||
if (hours) {
|
||||
return hours + ' hour' + numberEnding(hours);
|
||||
}
|
||||
var minutes = Math.floor((temp %= 3600) / 60);
|
||||
if (minutes) {
|
||||
return minutes + ' minute' + numberEnding(minutes);
|
||||
}
|
||||
var seconds = temp % 60;
|
||||
if (seconds) {
|
||||
return seconds + ' second' + numberEnding(seconds);
|
||||
}
|
||||
return 'less than a second';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="splash">
|
||||
<!-- a small splash page that explains what this thing is -->
|
||||
<img src="img/logo.svg" alt="SVGnest" class="logo" style="display:block;margin:0 auto;max-width:220px;" />
|
||||
<h1 class="title">MAnest</h1>
|
||||
<em class="subscript">Fast Nesting for Makers</em>
|
||||
|
||||
|
||||
|
||||
|
||||
<ul class="nav" id="splash-nav">
|
||||
<li class="button start" id="demo">Example</li>
|
||||
<li class="button upload" id="upload">Upload SVG</li>
|
||||
<li class="button" id="faqbutton">FAQ</li>
|
||||
<li><a class="button back" id="back" href="https://makearmy.io" rel="noopener">Back to Main</a></li>
|
||||
</ul>
|
||||
|
||||
<p id="poweredby">
|
||||
Powered by SVGnest, a free open source project by Jack000 —
|
||||
visit the github <a href="https://github.com/Jack000/SVGnest" target="_blank" rel="noopener">here</a>.
|
||||
</p>
|
||||
<div id="faq">
|
||||
<h1>What exactly is "nesting"?</h1>
|
||||
<p>If you have some parts to cut out of a piece of metal/plastic/wood etc, you'd want to arrange the parts to use as little material as possible. This is a common problem if you use a laser cutter, plasma cutter, or CNC machine.</p>
|
||||
<p>In computer terms this is called the irregular bin-packing problem</p>
|
||||
|
||||
<h1>How much does it cost?</h1>
|
||||
<p>It's free and open source. The code and implementation details are on <a href="https://github.com/Jack000/SVGnest" target="_blank">Github</a></p>
|
||||
|
||||
<h1>Does it use inches? mm?</h1>
|
||||
<p>SVG has its internal units, the distance related fields in the settings use SVG units, ie. pixels. The conversion between a pixel and real units depend on the exporting software, but it's typically 72 pixels = 1 inch</p>
|
||||
|
||||
<h1>My SVG text/image doesn't show up?</h1>
|
||||
<p>Nesting only works for closed shapes, so SVG elements that don't represent closed shapes are removed. Convert text and any other elements to outlines first. Ensure that outlines do not intersect or overlap eachother. Outlines that are inside other outlines are considered holes.</p>
|
||||
|
||||
<h1>It doesn't ever stop?</h1>
|
||||
<p>The software will continuously look for better solutions until you press the stop button. You can stop at any time and download the SVG file.</p>
|
||||
|
||||
<h1>Some parts seem to slightly overlap?</h1>
|
||||
<p>Curved shapes are approximated with line segments. For a more accurate nest with curved parts, decrease the curve tolerance parameter in the configuration.</p>
|
||||
|
||||
<h1>I need help?</h1>
|
||||
<p>Add an issue on Github or contact me personally: <a href="http://jack.works">jack.works</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="svgnest">
|
||||
|
||||
<div id="controls">
|
||||
<ul class="nav">
|
||||
<li class="button start disabled" id="start"><span id="startlabel">Start Nest</span></li>
|
||||
<li class="button download disabled" id="download">Download SVG</li>
|
||||
<li class="button config" id="configbutton"></li>
|
||||
<li class="button zoomin" id="zoominbutton"></li>
|
||||
<li class="button zoomout" id="zoomoutbutton"></li>
|
||||
<li class="button exit" id="exitbutton"></li>
|
||||
</ul>
|
||||
|
||||
<div id="config">
|
||||
<div id="configwrapper">
|
||||
<input type="text" value="0" data-config="spacing" />
|
||||
<h3>Space between parts</h3><span class="tooltip" title="The space between parts in SVG units (conversion depends on exporting software but usually 1 SVG unit = 1px = 1/72 inches = 0.3527777~ mm)">?</span>
|
||||
|
||||
<input type="text" value="0.3" data-config="curveTolerance" />
|
||||
<h3>Curve tolerance</h3><span class="tooltip" title="The maximum error allowed when converting Beziers and arcs to line segments. In SVG units. Smaller tolerances will take longer to compute">?</span>
|
||||
|
||||
<input type="text" value="4" data-config="rotations" />
|
||||
<h3>Part rotations</h3><span class="tooltip" title="Number of rotations to consider when inserting a part. Larger rotations will take longer to compute, and may also take longer to converge to a good solution">?</span>
|
||||
|
||||
<input type="text" value="10" data-config="populationSize" />
|
||||
<h3>GA population</h3><span class="tooltip" title="The number of solutions in the Genetic Algorithm population. Larger populations will converge slower but may result in better solutions in the long run">?</span>
|
||||
|
||||
<input type="text" value="10" data-config="mutationRate" />
|
||||
<h3>GA mutation rate</h3><span class="tooltip" title="Mutation rate (in percent) at each generation of the Genetic Algorithm. A 100% mutation rate is equivalent to random sampling">?</span>
|
||||
|
||||
<input type="checkbox" class="checkbox" data-config="useHoles" />
|
||||
<h3>Part in Part</h3><span class="tooltip" title="Place parts in the holes of other parts. This will take much longer to compute ">?</span>
|
||||
|
||||
<input type="checkbox" class="checkbox" data-config="exploreConcave" />
|
||||
<h3>Explore concave areas</h3><span class="tooltip" title="Try to solve for enclosed concave areas (eg. a jigsaw puzzle piece) This will take much longer to compute ">?</span>
|
||||
|
||||
<a href="#" class="button" id="configsave">Save Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar">
|
||||
<div id="info">
|
||||
<h2 id="info_time"></h2>
|
||||
<div class="progress"><div class="progress_inner" id="info_progress"></div></div>
|
||||
<span class="subscript">Placement progress</span>
|
||||
|
||||
<div id="info_placement">
|
||||
<div class="column left">
|
||||
<h1 class="label"><span id="info_efficiency"></span><sup>%</sup></h1>
|
||||
<span class="subscript">Material Utilization</span>
|
||||
</div>
|
||||
|
||||
<div class="column right">
|
||||
<h1 class="label" id="info_iterations"></h1>
|
||||
<span class="subscript">Iterations</span>
|
||||
</div>
|
||||
|
||||
<div class="column left">
|
||||
<h1 class="label"><span id="info_placed"></span></h1>
|
||||
<span class="subscript">Parts placed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="select">
|
||||
<svg version="1.1" id="svg2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1147.592px" height="1397.27px" viewBox="0 0 1147.592 1397.27" enable-background="new 0 0 1147.592 1397.27" xml:space="preserve">
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="684.045,443.734 688.396,447.215
|
||||
666.488,450.935 666.488,432.651 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="697.067,404.901 697.067,415.601
|
||||
709.719,415.905 710.293,406.067 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="723.908,440.886 715.362,442.463
|
||||
709.719,435.85 712.627,427.66 721.17,426.079 726.81,432.692 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="617.292,458.369 618.742,465.049
|
||||
599.735,465.566 599.735,447.28 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="619.963,428.025 619.963,438.722
|
||||
633.189,438.467 633.189,429.192 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="646.805,464.01 638.259,465.587
|
||||
632.618,458.974 635.523,450.784 644.069,449.207 649.706,455.819 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="777.062,428.025 746.983,457.397
|
||||
760.468,481.256 782.898,488.173 788.995,478.145 814.669,479.959 818.817,438.722 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="666.589,476.434 664.255,503.557
|
||||
681.632,505.633 694.857,499.916 692.262,483.07 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="599.735,501.612 636.247,531.953
|
||||
680.981,531.953 680.981,554.904 599.735,554.904 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="759.315,529.301 775.721,500.886
|
||||
792.128,529.301 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="741.307,428.338 734.229,419.461
|
||||
736.757,408.396 746.983,403.469 757.206,408.396 759.735,419.461 752.654,428.338 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="647.399,599.509 651.749,602.988
|
||||
629.84,606.702 629.84,588.419 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="650.068,569.167 650.068,579.861
|
||||
662.723,580.171 663.294,570.334 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="758.061,626.35 800.104,626.854
|
||||
807.438,600.447 796.468,579.694 785.065,582.478 768.195,563.04 736.104,589.264 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="694.308,592.604 687.232,583.727
|
||||
689.758,572.661 699.984,567.735 710.211,572.661 712.736,583.727 705.658,592.604 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="854.273,544.551 858.625,548.03
|
||||
836.717,551.75 836.717,533.467 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="856.944,514.209 856.944,524.909
|
||||
869.597,525.213 870.171,515.376 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="883.785,550.194 875.24,551.771
|
||||
869.597,545.158 872.505,536.968 881.048,535.388 886.688,542.001 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="779.841,537.333 779.841,548.03
|
||||
793.067,547.775 793.067,538.5 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="901.184,537.646 894.106,528.769
|
||||
896.635,517.703 906.861,512.777 917.084,517.703 919.613,528.769 912.532,537.646 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.717,410.401 827.633,456.421
|
||||
894.106,463.102 910.101,434.273 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="676.909,605.146 668.363,606.727
|
||||
662.723,600.113 665.628,591.92 674.174,590.346 679.814,596.959 "/>
|
||||
<rect x="21.066" y="439.913" width="30.913" height="18.155" fill="none" stroke="#010101"/>
|
||||
<rect x="106.758" y="452.881" width="29.563" height="5.188" fill="none" stroke="#010101"/>
|
||||
<rect x="184.038" y="464.809" width="25.963" height="17.637" fill="none" stroke="#010101"/>
|
||||
<rect x="305.408" y="427.01" width="17.01" height="40.393" fill="none" stroke="#010101"/>
|
||||
<rect x="262.876" y="458.068" width="17.004" height="17.633" fill="none" stroke="#010101"/>
|
||||
<rect x="338.931" y="427.01" width="47.904" height="25.868" fill="none" stroke="#010101"/>
|
||||
<polygon fill="none" stroke="#010101" points="66.82,475.701 47.112,507.86 101.95,510.972 140.64,493.336 90.161,496.448 87.322,473.625 "/>
|
||||
<polygon fill="none" stroke="#010101" points="196.401,495.929 224.016,523.938 348.972,517.196 271.061,492.297 227.967,473.625 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1065.045,441.528 1069.396,445.009
|
||||
1047.488,448.729 1047.488,430.445 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1078.067,402.694 1078.067,413.395
|
||||
1090.719,413.699 1091.293,403.861 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1104.908,438.68 1096.362,440.257
|
||||
1090.719,433.644 1093.627,425.454 1102.17,423.873 1107.811,430.486 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="998.292,456.163 999.742,462.843
|
||||
980.735,463.359 980.735,445.074 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1000.963,425.818 1000.963,436.516
|
||||
1014.189,436.261 1014.189,426.985 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1027.805,461.804 1019.259,463.381
|
||||
1013.618,456.768 1016.523,448.578 1025.069,447.001 1030.706,453.613 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="601.531,174.639 571.451,204.011
|
||||
584.936,227.87 607.366,234.787 613.463,224.759 639.137,226.573 643.285,185.336 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1047.589,474.228 1045.255,501.351
|
||||
1062.632,503.427 1075.857,497.71 1073.262,480.864 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="980.735,499.406 1017.247,529.747
|
||||
1061.98,529.747 1061.98,552.698 980.735,552.698 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="583.783,275.915 600.188,247.5
|
||||
616.596,275.915 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="565.774,174.952 558.696,166.075
|
||||
561.225,155.01 571.451,150.083 581.674,155.01 584.203,166.075 577.122,174.952 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1028.399,597.303 1032.749,600.782
|
||||
1010.84,604.496 1010.84,586.213 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1031.068,566.961 1031.068,577.655
|
||||
1043.723,577.965 1044.294,568.128 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="582.528,372.964 624.57,373.468
|
||||
631.906,347.062 620.936,326.309 609.533,329.092 592.663,309.654 560.571,335.878 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1075.308,590.397 1068.232,581.521
|
||||
1070.758,570.455 1080.984,565.529 1091.211,570.455 1093.736,581.521 1086.658,590.397 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="678.741,291.165 683.093,294.645
|
||||
661.185,298.364 661.185,280.081 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="681.412,260.823 681.412,271.524
|
||||
694.064,271.827 694.639,261.99 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="708.253,296.809 699.708,298.386
|
||||
694.064,291.773 696.973,283.582 705.516,282.002 711.155,288.615 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="604.309,283.947 604.309,294.645
|
||||
617.535,294.389 617.535,285.114 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="725.651,284.26 718.574,275.383
|
||||
721.104,264.317 731.329,259.392 741.552,264.317 744.081,275.383 737,284.26 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="661.185,157.016 652.101,203.035
|
||||
718.574,209.716 734.568,180.887 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1057.909,602.939 1049.363,604.521
|
||||
1043.723,597.907 1046.628,589.714 1055.174,588.14 1060.814,594.753 "/>
|
||||
<rect x="402.066" y="437.707" width="30.912" height="18.155" fill="none" stroke="#010101" />
|
||||
<rect x="487.758" y="450.675" width="29.564" height="5.188" fill="none" stroke="#010101" />
|
||||
<rect x="565.949" y="691.507" width="25.963" height="17.636" fill="none" stroke="#010101" />
|
||||
<rect x="687.32" y="653.708" width="17.01" height="40.392" fill="none" stroke="#010101" />
|
||||
<rect x="644.789" y="684.767" width="17.004" height="17.634" fill="none" stroke="#010101" />
|
||||
<rect x="720.844" y="653.708" width="47.904" height="25.868" fill="none" stroke="#010101" />
|
||||
<polygon fill="none" stroke="#010101" points="447.82,473.495 428.112,505.654 482.95,508.766 521.641,491.13 471.161,494.242 468.322,471.419 "/>
|
||||
<polygon fill="none" stroke="#010101" points="578.312,722.627 605.928,750.635 730.885,743.895 652.973,718.995 609.879,700.323 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="903.513,195.164 907.864,198.645
|
||||
885.956,202.364 885.956,184.081 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="916.535,156.33 916.535,167.03
|
||||
929.188,167.335 929.761,157.497 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="943.376,192.316 934.83,193.893
|
||||
929.188,187.279 932.095,179.09 940.638,177.509 946.277,184.122 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.76,209.799 838.209,216.479
|
||||
819.203,216.995 819.203,198.71 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="839.432,179.454 839.432,190.151
|
||||
852.657,189.897 852.657,180.621 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="866.271,215.44 857.727,217.017
|
||||
852.086,210.403 854.991,202.214 863.537,200.637 869.174,207.249 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="996.531,179.454 966.451,208.826
|
||||
979.936,232.686 1002.366,239.603 1008.463,229.574 1034.137,231.389 1038.285,190.151 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="886.057,227.863 883.723,254.986
|
||||
901.1,257.063 914.325,251.346 911.729,234.5 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="819.203,253.042 855.715,283.383
|
||||
900.449,283.383 900.449,306.334 819.203,306.334 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="978.783,280.731 995.188,252.316
|
||||
1011.596,280.731 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="960.774,179.768 953.696,170.891
|
||||
956.225,159.825 966.451,154.899 976.674,159.825 979.203,170.891 972.122,179.768 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="866.867,350.939 871.217,354.418
|
||||
849.308,358.132 849.308,339.849 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="869.536,320.597 869.536,331.291
|
||||
882.19,331.601 882.762,321.764 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="977.528,377.779 1019.57,378.283
|
||||
1026.906,351.877 1015.936,331.124 1004.533,333.907 987.663,314.47 955.571,340.693 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="913.775,344.033 906.7,335.156
|
||||
909.226,324.091 919.452,319.165 929.679,324.091 932.204,335.156 925.126,344.033 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1073.741,295.981 1078.093,299.46
|
||||
1056.186,303.18 1056.186,284.897 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1076.412,265.639 1076.412,276.339
|
||||
1089.064,276.643 1089.639,266.806 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1103.253,301.624 1094.708,303.201
|
||||
1089.064,296.588 1091.973,288.398 1100.516,286.817 1106.155,293.431 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="999.309,288.763 999.309,299.46
|
||||
1012.535,299.204 1012.535,289.93 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1120.651,289.075 1113.574,280.198
|
||||
1116.104,269.133 1126.329,264.207 1136.552,269.133 1139.081,280.198 1132,289.075 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1056.186,161.831 1047.101,207.851
|
||||
1113.574,214.531 1129.568,185.702 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="896.377,356.575 887.831,358.156
|
||||
882.19,351.543 885.096,343.35 893.642,341.776 899.282,348.389 "/>
|
||||
<rect x="797.979" y="671.427" width="30.912" height="18.155" fill="none" stroke="#010101" />
|
||||
<rect x="883.67" y="684.395" width="29.564" height="5.188" fill="none" stroke="#010101" />
|
||||
<rect x="916.535" y="655.978" width="25.963" height="17.637" fill="none" stroke="#010101" />
|
||||
<rect x="1037.906" y="618.179" width="17.01" height="40.393" fill="none" stroke="#010101" />
|
||||
<rect x="995.375" y="649.237" width="17.004" height="17.633" fill="none" stroke="#010101" />
|
||||
<rect x="1071.43" y="618.179" width="47.904" height="25.868" fill="none" stroke="#010101" />
|
||||
<polygon fill="none" stroke="#010101" points="843.732,707.215 824.023,739.374 878.861,742.484 917.553,724.85 867.072,727.962 864.234,705.139 "/>
|
||||
<polygon fill="none" stroke="#010101" points="928.898,687.098 956.514,715.105 1081.471,708.365 1003.559,683.466 960.465,664.794 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="105.375,574.337 109.727,577.817
|
||||
87.819,581.537 87.819,563.254 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="118.398,535.503 118.398,546.203
|
||||
131.049,546.508 131.624,536.67 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="145.239,571.488 136.693,573.065
|
||||
131.049,566.452 133.958,558.263 142.5,556.682 148.14,563.295 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="38.623,588.972 40.072,595.651
|
||||
21.066,596.168 21.066,577.883 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="41.294,558.627 41.294,569.324
|
||||
54.52,569.069 54.52,559.794 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="68.135,594.612 59.589,596.189
|
||||
53.949,589.576 56.854,581.387 65.4,579.81 71.037,586.422 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="198.394,558.627 168.314,587.999
|
||||
181.798,611.858 204.229,618.775 210.326,608.747 236,610.562 240.148,569.324 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="87.919,607.036 85.585,634.159
|
||||
102.962,636.235 116.188,630.519 113.592,613.673 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="21.066,632.215 57.578,662.556
|
||||
102.312,662.556 102.312,685.507 21.066,685.507 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="180.646,659.903 197.051,631.488
|
||||
213.458,659.903 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="162.637,558.94 155.559,550.062
|
||||
158.087,538.998 168.314,534.071 178.537,538.998 181.066,550.062 173.985,558.94 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="68.73,730.111 73.08,733.591
|
||||
51.17,737.305 51.17,719.021 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="71.399,699.77 71.399,710.464
|
||||
84.053,710.773 84.625,700.938 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="115.638,723.206 108.563,714.329
|
||||
111.088,703.264 121.315,698.338 131.542,703.264 134.067,714.329 126.989,723.206 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="275.604,675.153 279.956,678.633
|
||||
258.047,682.354 258.047,664.069 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="278.275,644.812 278.275,655.512
|
||||
290.927,655.815 291.501,645.979 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="305.116,680.797 296.571,682.374
|
||||
290.927,675.761 293.835,667.57 302.378,665.99 308.018,672.604 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="201.171,667.936 201.171,678.633
|
||||
214.398,678.377 214.398,669.104 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="322.514,668.248 315.438,659.371
|
||||
317.965,648.306 328.192,643.38 338.415,648.306 340.944,659.371 333.863,668.248 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="258.047,541.004 248.963,587.023
|
||||
315.438,593.704 331.431,564.875 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="98.24,735.748 89.694,737.329
|
||||
84.053,730.716 86.958,722.521 95.504,720.948 101.145,727.562 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="504.59,600.795 508.941,604.275
|
||||
487.033,607.995 487.033,589.712 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="517.611,561.961 517.611,572.661
|
||||
530.264,572.966 530.838,563.128 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="545.365,716.138 536.818,717.715
|
||||
531.176,711.102 534.084,702.912 542.627,701.331 548.266,707.944 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="437.837,615.43 439.287,622.109
|
||||
420.28,622.626 420.28,604.341 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="440.508,585.085 440.508,595.782
|
||||
453.734,595.527 453.734,586.252 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="467.35,621.07 458.804,622.646
|
||||
453.163,616.034 456.068,607.845 464.614,606.268 470.251,612.88 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="598.52,813.989 568.439,843.361
|
||||
581.924,867.221 604.355,874.138 610.451,864.109 636.125,865.924 640.273,824.687 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="487.134,633.494 484.8,660.617
|
||||
502.177,662.693 515.402,656.977 512.807,640.131 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="420.28,658.673 456.792,689.014
|
||||
501.526,689.014 501.526,711.965 420.28,711.965 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="580.771,915.266 597.178,886.851
|
||||
613.584,915.266 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="562.764,814.303 555.686,805.426
|
||||
558.213,794.359 568.439,789.434 578.662,794.359 581.191,805.426 574.111,814.303 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="467.944,756.569 472.294,760.049
|
||||
450.385,763.763 450.385,745.479 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="470.613,726.229 470.613,736.922
|
||||
483.268,737.231 483.839,727.395 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="514.852,749.664 507.777,740.787
|
||||
510.303,729.722 520.529,724.796 530.756,729.722 533.281,740.787 526.203,749.664 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="675.73,930.516 680.082,933.995
|
||||
658.174,937.715 658.174,919.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="678.4,900.174 678.4,910.874
|
||||
691.053,911.178 691.627,901.341 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="705.242,936.159 696.697,937.736
|
||||
691.053,931.123 693.961,922.933 702.504,921.353 708.145,927.966 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="601.297,923.298 601.297,933.995
|
||||
614.523,933.739 614.523,924.465 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="563.383,919.432 559.621,926.865
|
||||
550.156,929.546 550.156,937.715 559.621,940.869 563.383,946.966 571.941,946.966 575.18,942.553 581.07,937.736 581.07,929.546
|
||||
575.18,926.087 570.123,919.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="722.641,923.609 715.562,914.734
|
||||
718.092,903.668 728.318,898.742 738.541,903.668 741.07,914.734 733.988,923.609 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="658.174,796.366 649.09,842.386
|
||||
715.562,849.066 731.557,820.237 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="497.454,762.206 488.908,763.787
|
||||
483.268,757.174 486.173,748.98 494.719,747.406 500.359,754.02 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="900.502,834.515 904.854,837.995
|
||||
882.945,841.715 882.945,823.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="913.523,795.681 913.523,806.381
|
||||
926.176,806.686 926.75,796.848 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="940.365,831.666 931.818,833.243
|
||||
926.176,826.63 929.084,818.441 937.627,816.859 943.266,823.473 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="833.748,849.15 835.197,855.829
|
||||
816.191,856.346 816.191,838.061 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.42,818.805 836.42,829.502
|
||||
849.646,829.247 849.646,819.972 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="863.262,854.79 854.715,856.367
|
||||
849.074,849.754 851.98,841.564 860.525,839.987 866.162,846.6 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="993.52,818.805 963.439,848.177
|
||||
976.924,872.036 999.355,878.953 1005.451,868.925 1031.125,870.739 1035.273,829.502 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="957.764,819.118 950.686,810.241
|
||||
953.213,799.176 963.439,794.249 973.662,799.176 976.191,810.241 969.111,819.118 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1053.174,801.182 1044.09,847.201
|
||||
1110.562,853.882 1126.557,825.053 "/>
|
||||
<rect width="511.822" height="339.235" fill="none" stroke="#010101" />
|
||||
|
||||
<path fill="none" stroke="#010101" d="M746.843,60.679c-2.465,1.232-7.395,2.465-13.711,2.465c-14.635,0-25.65-9.243-25.65-26.266
|
||||
c0-16.252,11.016-27.268,27.113-27.268c6.471,0,10.553,1.387,12.324,2.311l-1.617,5.469c-2.542-1.232-6.162-2.157-10.476-2.157
|
||||
c-12.17,0-20.258,7.78-20.258,21.414c0,12.709,7.317,20.874,19.95,20.874c4.082,0,8.241-0.848,10.938-2.157L746.843,60.679z"/>
|
||||
<path fill="none" stroke="#010101" d="M755.008,7.685h6.778v54.688h-6.778V7.685z"/>
|
||||
<path fill="none" stroke="#010101" d="M780.734,14.617c0.077,2.311-1.617,4.16-4.313,4.16c-2.388,0-4.082-1.849-4.082-4.16c0-2.388,1.771-4.236,4.236-4.236
|
||||
C779.117,10.38,780.734,12.229,780.734,14.617z M773.187,62.373V25.092h6.777v37.281H773.187z"/>
|
||||
<path fill="none" stroke="#010101" d="M817.784,60.986c-1.771,0.925-5.7,2.157-10.707,2.157c-11.246,0-18.563-7.626-18.563-19.026
|
||||
c0-11.477,7.856-19.795,20.027-19.795c4.005,0,7.548,1.001,9.397,1.925l-1.541,5.238c-1.617-0.924-4.159-1.771-7.856-1.771
|
||||
c-8.55,0-13.172,6.316-13.172,14.096c0,8.627,5.546,13.942,12.94,13.942c3.852,0,6.394-1.001,8.318-1.849L817.784,60.986z"/>
|
||||
<path fill="none" stroke="#010101" d="M832.42,42.192h0.154c0.924-1.31,2.233-2.927,3.312-4.237l10.938-12.863h8.164L840.585,40.42l16.406,21.953h-8.241
|
||||
l-12.864-17.87l-3.466,3.852v14.019h-6.701V7.685h6.701V42.192z"/>
|
||||
<path fill="none" stroke="#010101" d="M885.107,16.157h-15.79v-5.7h38.437v5.7h-15.867v46.216h-6.779V16.157z"/>
|
||||
<path fill="none" stroke="#010101" d="M912.762,7.685h6.778v23.262h0.154c1.078-1.926,2.772-3.62,4.853-4.775c2.002-1.156,4.391-1.926,6.932-1.926
|
||||
c5.007,0,13.018,3.081,13.018,15.944v22.184h-6.778V40.96c0-6.008-2.233-11.092-8.627-11.092c-4.39,0-7.856,3.081-9.089,6.778
|
||||
c-0.385,0.924-0.462,1.925-0.462,3.235v22.492h-6.778V7.685z"/>
|
||||
<path fill="none" stroke="#010101" d="M963.062,14.617c0.077,2.311-1.618,4.16-4.313,4.16c-2.389,0-4.083-1.849-4.083-4.16c0-2.388,1.771-4.236,4.236-4.236
|
||||
C961.443,10.38,963.062,12.229,963.062,14.617z M955.513,62.373V25.092h6.778v37.281H955.513z"/>
|
||||
<path fill="none" stroke="#010101" d="M972.611,55.44c2.003,1.31,5.546,2.696,8.936,2.696c4.93,0,7.24-2.465,7.24-5.546c0-3.235-1.926-5.007-6.933-6.855
|
||||
c-6.701-2.388-9.859-6.085-9.859-10.553c0-6.008,4.853-10.938,12.864-10.938c3.773,0,7.086,1.078,9.166,2.311l-1.695,4.93
|
||||
c-1.463-0.924-4.159-2.157-7.625-2.157c-4.006,0-6.239,2.311-6.239,5.084c0,3.081,2.233,4.467,7.086,6.316
|
||||
c6.471,2.465,9.782,5.7,9.782,11.246c0,6.547-5.083,11.169-13.941,11.169c-4.082,0-7.856-1.001-10.476-2.542L972.611,55.44z"/>
|
||||
<polygon fill="none" stroke="#010101" points="676.149,23 616.756,23 616.756,1 558.443,34.667 616.756,68.333 616.756,46.333 676.149,46.333 "/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<div id="bins"></div>
|
||||
|
||||
<input id="fileinput" type="file" style="visibility:hidden" />
|
||||
</div>
|
||||
|
||||
<div id="messagewrapper">
|
||||
<div id="message"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
914
public/svgnest/index.html.bak
Normal file
|
|
@ -0,0 +1,914 @@
|
|||
<!doctype html>
|
||||
<html itemscope="" itemtype="http://schema.org/WebPage" lang="en">
|
||||
<head><base href="/svgnest/">
|
||||
<link rel="shortcut icon" href="/favicon32.gif" type="image/x-icon" sizes="32x32" />
|
||||
<link rel="shortcut icon" href="/favicon16.gif" type="image/x-icon" sizes="16x16" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>MAnest - MakeArmy hosted nesting app powered by SVGnest!</title>
|
||||
|
||||
<meta name="description" content="A completely free and open source application for automatic nesting. Comes with advanced features like part-in-part nesting and concave area detection." />
|
||||
|
||||
<link type="text/css" rel="stylesheet" media="all" href="font/latolatinfonts.css" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<script src="util/pathsegpolyfill.js"></script>
|
||||
<script src="util/matrix.js"></script>
|
||||
<script src="util/domparser.js"></script>
|
||||
<script src="util/clipper.js"></script>
|
||||
<script src="util/parallel.js"></script>
|
||||
<script src="util/geometryutil.js"></script>
|
||||
<script src="util/placementworker.js"></script>
|
||||
<script src="svgparser.js"></script>
|
||||
<script src="svgnest.js"></script>
|
||||
|
||||
<script src="util/filesaver.js"></script>
|
||||
|
||||
<script>
|
||||
// UI-specific stuff, button clicks go here
|
||||
function ready(fn){
|
||||
if (document.readyState != 'loading'){
|
||||
fn();
|
||||
}
|
||||
else {
|
||||
document.addEventListener('DOMContentLoaded', fn);
|
||||
}
|
||||
}
|
||||
|
||||
ready(function(){
|
||||
// FAQ toggle
|
||||
var faq = document.getElementById('faq');
|
||||
var faqbutton = document.getElementById('faqbutton');
|
||||
|
||||
var faqvisible = false;
|
||||
faqbutton.onclick = function(e){
|
||||
if(!faqvisible){
|
||||
faq.setAttribute('style','display: block');
|
||||
}
|
||||
else{
|
||||
faq.removeAttribute('style');
|
||||
}
|
||||
faqvisible = !faqvisible;
|
||||
};
|
||||
|
||||
function hideSplash(){
|
||||
var splash = document.getElementById('splash');
|
||||
var svgnest = document.getElementById('svgnest');
|
||||
if(splash){
|
||||
splash.remove();
|
||||
}
|
||||
svgnest.setAttribute('style','display: block');
|
||||
}
|
||||
|
||||
var demo = document.getElementById('demo');
|
||||
var upload = document.getElementById('upload');
|
||||
var display = document.getElementById('select');
|
||||
|
||||
demo.onclick = function(){
|
||||
try{
|
||||
var svg = window.SvgNest.parsesvg(display.innerHTML);
|
||||
display.innerHTML = '';
|
||||
display.appendChild(svg);
|
||||
}
|
||||
catch(e){
|
||||
message.innerHTML = e;
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
hideSplash();
|
||||
message.innerHTML = 'Click on the outline to use as the bin';
|
||||
message.className = 'active animated bounce';
|
||||
|
||||
attachSvgListeners(svg);
|
||||
};
|
||||
|
||||
var message = document.getElementById('message');
|
||||
|
||||
if(!document.createElementNS || !document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect){
|
||||
message.innerHTML = 'Your browser does not have SVG support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
if (!window.SvgNest) {
|
||||
message.innerHTML = "Couldn't initialize SVGnest";
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
if(!window.File || !window.FileReader){
|
||||
message.innerHTML = 'Your browser does not have file upload support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
if(!window.Worker){
|
||||
message.innerHTML = 'Your browser does not have web worker support';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
// button clicks
|
||||
var upload = document.getElementById('upload');
|
||||
var start = document.getElementById('start');
|
||||
var download = document.getElementById('download');
|
||||
var startlabel = document.getElementById('startlabel');
|
||||
var fileinput = document.getElementById('fileinput');
|
||||
|
||||
var config = document.getElementById('config');
|
||||
var configbutton = document.getElementById('configbutton');
|
||||
var configsave = document.getElementById('configsave');
|
||||
|
||||
var zoomin = document.getElementById('zoominbutton');
|
||||
var zoomout = document.getElementById('zoomoutbutton');
|
||||
var exit = document.getElementById('exitbutton');
|
||||
|
||||
var isworking = false;
|
||||
|
||||
start.onclick = function(){
|
||||
if(this.className == 'button start disabled'){
|
||||
return false;
|
||||
}
|
||||
iterations = 0;
|
||||
if(isworking){
|
||||
stopnest();
|
||||
}
|
||||
else{
|
||||
startnest();
|
||||
}
|
||||
|
||||
display.className = 'disabled';
|
||||
document.getElementById('info_time').setAttribute('style','display: none');
|
||||
};
|
||||
|
||||
function startnest(){
|
||||
// Once started, don't allow this anymore
|
||||
document.removeEventListener('dragover', FileDragHover, false);
|
||||
document.removeEventListener('dragleave', FileDragHover, false);
|
||||
document.removeEventListener('drop', FileDrop, false);
|
||||
|
||||
SvgNest.start(progress, renderSvg);
|
||||
startlabel.innerHTML = 'Stop Nest';
|
||||
start.className = 'button spinner';
|
||||
configbutton.className = 'button config disabled';
|
||||
config.className = '';
|
||||
zoomin.className = 'button zoomin disabled';
|
||||
zoomout.className = 'button zoomout disabled';
|
||||
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.removeAttribute('style');
|
||||
}
|
||||
|
||||
isworking = true;
|
||||
}
|
||||
|
||||
function stopnest(){
|
||||
SvgNest.stop();
|
||||
startlabel.innerHTML = 'Start Nest';
|
||||
start.className = 'button start';
|
||||
configbutton.className = 'button config';
|
||||
|
||||
isworking = false;
|
||||
}
|
||||
|
||||
// config
|
||||
var configvisible = false;
|
||||
configbutton.onclick = function(){
|
||||
if(this.className == 'button config disabled'){
|
||||
return false;
|
||||
}
|
||||
if(!configvisible){
|
||||
config.className = 'active';
|
||||
configbutton.className = 'button close';
|
||||
}
|
||||
else{
|
||||
config.className = '';
|
||||
configbutton.className = 'button config';
|
||||
}
|
||||
configvisible = !configvisible;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
configsave.onclick = function(){
|
||||
var c = {};
|
||||
var inputs = document.querySelectorAll('#config input');
|
||||
for(var i=0; i<inputs.length; i++){
|
||||
var key = inputs[i].getAttribute('data-config');
|
||||
if(inputs[i].getAttribute('type') == 'text'){
|
||||
c[key] = inputs[i].value;
|
||||
}
|
||||
else if(inputs[i].getAttribute('type') == 'checkbox'){
|
||||
c[key] = inputs[i].checked;
|
||||
}
|
||||
}
|
||||
|
||||
window.SvgNest.config(c);
|
||||
|
||||
// new configs will invalidate current nest
|
||||
if(isworking){
|
||||
stopnest();
|
||||
}
|
||||
configvisible = false;
|
||||
config.className = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
upload.onclick = function(){
|
||||
fileinput.click();
|
||||
}
|
||||
document.addEventListener('dragover', FileDragHover, false);
|
||||
document.addEventListener('dragleave', FileDragHover, false);
|
||||
document.addEventListener('drop', FileDrop, false);
|
||||
function FileDragHover(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
upload.style.backgroundColor = (e.type == "dragover" ? "#d7e9b7" : "");
|
||||
}
|
||||
function FileDrop(e){
|
||||
e.stopPropagation(); // Make sure not to replace website by file
|
||||
e.preventDefault();
|
||||
handleFile(e.dataTransfer.files[0]);
|
||||
}
|
||||
|
||||
|
||||
download.onclick = function(){
|
||||
if(download.className == 'button download disabled'){
|
||||
return false;
|
||||
}
|
||||
|
||||
var bins = document.getElementById('bins');
|
||||
|
||||
if(bins.children.length == 0){
|
||||
message.innerHTML = 'No SVG to export';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
var svg;
|
||||
svg = display.querySelector('svg');
|
||||
|
||||
if(!svg){
|
||||
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
||||
}
|
||||
|
||||
svg = svg.cloneNode(false);
|
||||
|
||||
// maintain stroke, fill etc of input
|
||||
if(SvgNest.style){
|
||||
svg.appendChild(SvgNest.style);
|
||||
}
|
||||
|
||||
var binHeight = parseInt(bins.children[0].getAttribute('height'));
|
||||
|
||||
for(var i=0; i<bins.children.length; i++){
|
||||
var b = bins.children[i];
|
||||
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
||||
group.setAttribute('transform', 'translate(0 '+binHeight*1.1*i+')');
|
||||
for(var j=0; j<b.children.length; j++){
|
||||
group.appendChild(b.children[j].cloneNode(true));
|
||||
}
|
||||
|
||||
svg.appendChild(group);
|
||||
}
|
||||
|
||||
var output;
|
||||
if(typeof XMLSerializer != 'undefined'){
|
||||
output = (new XMLSerializer()).serializeToString(svg);
|
||||
}
|
||||
else{
|
||||
output = svg.outerHTML;
|
||||
}
|
||||
|
||||
var blob = new Blob([output], {type: "image/svg+xml;charset=utf-8"});
|
||||
saveAs(blob, "SVGnest-output.svg");
|
||||
}
|
||||
|
||||
var zoomlevel = 1.0;
|
||||
|
||||
zoomin.onclick = function(){
|
||||
if(this.className == 'button zoomin disabled'){
|
||||
return false;
|
||||
}
|
||||
zoomlevel *= 1.2;
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.setAttribute('style', 'transform-origin: top left; transform:scale('+zoomlevel+'); -webkit-transform:scale('+zoomlevel+'); -moz-transform:scale('+zoomlevel+'); -ms-transform:scale('+zoomlevel+'); -o-transform:scale('+zoomlevel+');');
|
||||
}
|
||||
}
|
||||
|
||||
zoomout.onclick = function(){
|
||||
if(this.className == 'button zoomout disabled'){
|
||||
return false;
|
||||
}
|
||||
zoomlevel *= 0.8;
|
||||
if(zoomlevel < 0.02){
|
||||
zoomlevel = 0.02;
|
||||
}
|
||||
var svg = document.querySelector('#select svg');
|
||||
if(svg){
|
||||
svg.setAttribute('style', 'transform-origin: top left; transform:scale('+zoomlevel+'); -webkit-transform:scale('+zoomlevel+'); -moz-transform:scale('+zoomlevel+'); -ms-transform:scale('+zoomlevel+'); -o-transform:scale('+zoomlevel+');');
|
||||
}
|
||||
}
|
||||
|
||||
exit.onclick = function(){
|
||||
location.reload();
|
||||
}
|
||||
|
||||
fileinput.onchange = function(e){
|
||||
handleFile(e.target.files[0]);
|
||||
}
|
||||
|
||||
|
||||
function handleFile(file){
|
||||
if(!file){
|
||||
return;
|
||||
}
|
||||
|
||||
if(!file.type || (file.type.search('svg') < 0 && file.type.search('xml') < 0 && file.type.search('text') < 0)){
|
||||
message.innerHTML = 'Only SVG files allowed';
|
||||
message.className = 'error animated bounce';
|
||||
return
|
||||
}
|
||||
|
||||
var reader = new FileReader();
|
||||
var input = this;
|
||||
reader.onload = function(e) {
|
||||
input.value = null;
|
||||
|
||||
if(reader.result){
|
||||
try{
|
||||
var svg = window.SvgNest.parsesvg(reader.result);
|
||||
{
|
||||
var wholeSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
// Copy relevant scaling info
|
||||
wholeSVG.setAttribute('width',svg.getAttribute('width'));
|
||||
wholeSVG.setAttribute('height',svg.getAttribute('height'));
|
||||
wholeSVG.setAttribute('viewBox',svg.getAttribute('viewBox'));
|
||||
var rect = document.createElementNS(wholeSVG.namespaceURI,'rect');
|
||||
rect.setAttribute('x', wholeSVG.viewBox.baseVal.x);
|
||||
rect.setAttribute('y', wholeSVG.viewBox.baseVal.x);
|
||||
rect.setAttribute('width', wholeSVG.viewBox.baseVal.width);
|
||||
rect.setAttribute('height', wholeSVG.viewBox.baseVal.height);
|
||||
rect.setAttribute('class', 'fullRect');
|
||||
wholeSVG.appendChild(rect);
|
||||
}
|
||||
display.innerHTML = '';
|
||||
display.appendChild(wholeSVG); // As a default bin in background
|
||||
display.appendChild(svg);
|
||||
}
|
||||
catch(e){
|
||||
message.innerHTML = e;
|
||||
message.className = 'error animated bounce';
|
||||
return;
|
||||
}
|
||||
|
||||
hideSplash();
|
||||
message.innerHTML = 'Click on the outline to use as the bin';
|
||||
message.className = 'active animated bounce';
|
||||
start.className = 'button start disabled';
|
||||
|
||||
attachSvgListeners(svg);
|
||||
attachSvgListeners(wholeSVG);
|
||||
}
|
||||
}
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
function attachSvgListeners(svg){
|
||||
// attach event listeners
|
||||
for(var i=0; i<svg.childNodes.length; i++){
|
||||
var node = svg.childNodes[i];
|
||||
if(node.nodeType == 1){
|
||||
node.onclick = function(){
|
||||
if(display.className == 'disabled'){
|
||||
return;
|
||||
}
|
||||
var currentbin = document.querySelector('#select .active');
|
||||
if(currentbin){
|
||||
var className = currentbin.getAttribute('class').replace('active', '').trim();
|
||||
if(!className)
|
||||
currentbin.removeAttribute('class');
|
||||
else
|
||||
currentbin.setAttribute('class', className);
|
||||
}
|
||||
|
||||
window.SvgNest.setbin(this);
|
||||
this.setAttribute('class',(this.getAttribute('class') ? this.getAttribute('class')+' ' : '') + 'active');
|
||||
|
||||
start.className = 'button start animated bounce';
|
||||
message.className = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var prevpercent = 0;
|
||||
var startTime = null;
|
||||
|
||||
function progress(percent){
|
||||
var transition = percent > prevpercent ? '; transition: width 0.1s' : '';
|
||||
document.getElementById('info_progress').setAttribute('style','width: '+Math.round(percent*100)+'% ' + transition);
|
||||
document.getElementById('info').setAttribute('style','display: block');
|
||||
|
||||
prevpercent = percent;
|
||||
|
||||
var now = new Date().getTime();
|
||||
if(startTime && now){
|
||||
var diff = now-startTime;
|
||||
// show a time estimate for long-running placements
|
||||
var estimate = (diff/percent)*(1-percent);
|
||||
document.getElementById('info_time').innerHTML = millisecondsToStr(estimate)+' remaining';
|
||||
|
||||
if(diff > 5000 && percent < 0.3 && percent > 0.02 && estimate > 10000){
|
||||
document.getElementById('info_time').setAttribute('style','display: block');
|
||||
}
|
||||
}
|
||||
|
||||
if(percent > 0.95 || percent < 0.02){
|
||||
document.getElementById('info_time').setAttribute('style','display: none');
|
||||
}
|
||||
if(percent < 0.02){
|
||||
startTime = new Date().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
var iterations = 0;
|
||||
|
||||
function renderSvg(svglist, efficiency, placed, total){
|
||||
iterations++;
|
||||
document.getElementById('info_iterations').innerHTML = iterations;
|
||||
|
||||
if(!svglist || svglist.length == 0){
|
||||
return;
|
||||
}
|
||||
var bins = document.getElementById('bins');
|
||||
bins.innerHTML = '';
|
||||
|
||||
for(var i=0; i<svglist.length; i++){
|
||||
if(svglist.length > 2){
|
||||
svglist[i].setAttribute('class','grid');
|
||||
}
|
||||
bins.appendChild(svglist[i]);
|
||||
}
|
||||
|
||||
if(efficiency || efficiency === 0){
|
||||
document.getElementById('info_efficiency').innerHTML = Math.round(efficiency*100);
|
||||
}
|
||||
|
||||
document.getElementById('info_placed').innerHTML = placed+'/'+total;
|
||||
|
||||
document.getElementById('info_placement').setAttribute('style','display: block');
|
||||
display.setAttribute('style','display: none');
|
||||
download.className = 'button download animated bounce';
|
||||
}
|
||||
|
||||
message.onclick = function(e){
|
||||
this.className='';
|
||||
}
|
||||
|
||||
function millisecondsToStr (milliseconds) {
|
||||
function numberEnding (number) {
|
||||
return (number > 1) ? 's' : '';
|
||||
}
|
||||
|
||||
var temp = Math.floor(milliseconds / 1000);
|
||||
var years = Math.floor(temp / 31536000);
|
||||
if (years) {
|
||||
return years + ' year' + numberEnding(years);
|
||||
}
|
||||
var days = Math.floor((temp %= 31536000) / 86400);
|
||||
if (days) {
|
||||
return days + ' day' + numberEnding(days);
|
||||
}
|
||||
var hours = Math.floor((temp %= 86400) / 3600);
|
||||
if (hours) {
|
||||
return hours + ' hour' + numberEnding(hours);
|
||||
}
|
||||
var minutes = Math.floor((temp %= 3600) / 60);
|
||||
if (minutes) {
|
||||
return minutes + ' minute' + numberEnding(minutes);
|
||||
}
|
||||
var seconds = temp % 60;
|
||||
if (seconds) {
|
||||
return seconds + ' second' + numberEnding(seconds);
|
||||
}
|
||||
return 'less than a second';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="splash">
|
||||
<!-- a small splash page that explains what this thing is -->
|
||||
<img src="img/logo.svg" alt="SVGnest" class="logo" style="display:block;margin:0 auto;max-width:220px;" />
|
||||
<h1 class="title">MAnest</h1>
|
||||
<em class="subscript">Fast Nesting for Makers</em>
|
||||
|
||||
|
||||
|
||||
|
||||
<ul class="nav" id="splash-nav">
|
||||
<li class="button start" id="demo">Demo</li>
|
||||
<li class="button upload" id="upload">Upload SVG</li>
|
||||
<li class="button" id="faqbutton">FAQ</li>
|
||||
<li><a class="button back" id="back" href="https://makearmy.io" rel="noopener">Back to Main</a></li>
|
||||
</ul>
|
||||
|
||||
<p id="poweredby">
|
||||
Powered by SVGnest, a free open source project by Jack000 —
|
||||
visit the github <a href="https://github.com/Jack000/SVGnest" target="_blank" rel="noopener">here</a>.
|
||||
</p>
|
||||
<div id="faq">
|
||||
<h1>What exactly is "nesting"?</h1>
|
||||
<p>If you have some parts to cut out of a piece of metal/plastic/wood etc, you'd want to arrange the parts to use as little material as possible. This is a common problem if you use a laser cutter, plasma cutter, or CNC machine.</p>
|
||||
<p>In computer terms this is called the irregular bin-packing problem</p>
|
||||
|
||||
<h1>How much does it cost?</h1>
|
||||
<p>It's free and open source. The code and implementation details are on <a href="https://github.com/Jack000/SVGnest" target="_blank">Github</a></p>
|
||||
|
||||
<h1>Does it use inches? mm?</h1>
|
||||
<p>SVG has its internal units, the distance related fields in the settings use SVG units, ie. pixels. The conversion between a pixel and real units depend on the exporting software, but it's typically 72 pixels = 1 inch</p>
|
||||
|
||||
<h1>My SVG text/image doesn't show up?</h1>
|
||||
<p>Nesting only works for closed shapes, so SVG elements that don't represent closed shapes are removed. Convert text and any other elements to outlines first. Ensure that outlines do not intersect or overlap eachother. Outlines that are inside other outlines are considered holes.</p>
|
||||
|
||||
<h1>It doesn't ever stop?</h1>
|
||||
<p>The software will continuously look for better solutions until you press the stop button. You can stop at any time and download the SVG file.</p>
|
||||
|
||||
<h1>Some parts seem to slightly overlap?</h1>
|
||||
<p>Curved shapes are approximated with line segments. For a more accurate nest with curved parts, decrease the curve tolerance parameter in the configuration.</p>
|
||||
|
||||
<h1>I need help?</h1>
|
||||
<p>Add an issue on Github or contact me personally: <a href="http://jack.works">jack.works</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="svgnest">
|
||||
|
||||
<div id="controls">
|
||||
<ul class="nav">
|
||||
<li class="button start disabled" id="start"><span id="startlabel">Start Nest</span></li>
|
||||
<li class="button download disabled" id="download">Download SVG</li>
|
||||
<li class="button config" id="configbutton"></li>
|
||||
<li class="button zoomin" id="zoominbutton"></li>
|
||||
<li class="button zoomout" id="zoomoutbutton"></li>
|
||||
<li class="button exit" id="exitbutton"></li>
|
||||
</ul>
|
||||
|
||||
<div id="config">
|
||||
<div id="configwrapper">
|
||||
<input type="text" value="0" data-config="spacing" />
|
||||
<h3>Space between parts</h3><span class="tooltip" title="The space between parts in SVG units (conversion depends on exporting software but usually 1 SVG unit = 1px = 1/72 inches = 0.3527777~ mm)">?</span>
|
||||
|
||||
<input type="text" value="0.3" data-config="curveTolerance" />
|
||||
<h3>Curve tolerance</h3><span class="tooltip" title="The maximum error allowed when converting Beziers and arcs to line segments. In SVG units. Smaller tolerances will take longer to compute">?</span>
|
||||
|
||||
<input type="text" value="4" data-config="rotations" />
|
||||
<h3>Part rotations</h3><span class="tooltip" title="Number of rotations to consider when inserting a part. Larger rotations will take longer to compute, and may also take longer to converge to a good solution">?</span>
|
||||
|
||||
<input type="text" value="10" data-config="populationSize" />
|
||||
<h3>GA population</h3><span class="tooltip" title="The number of solutions in the Genetic Algorithm population. Larger populations will converge slower but may result in better solutions in the long run">?</span>
|
||||
|
||||
<input type="text" value="10" data-config="mutationRate" />
|
||||
<h3>GA mutation rate</h3><span class="tooltip" title="Mutation rate (in percent) at each generation of the Genetic Algorithm. A 100% mutation rate is equivalent to random sampling">?</span>
|
||||
|
||||
<input type="checkbox" class="checkbox" data-config="useHoles" />
|
||||
<h3>Part in Part</h3><span class="tooltip" title="Place parts in the holes of other parts. This will take much longer to compute ">?</span>
|
||||
|
||||
<input type="checkbox" class="checkbox" data-config="exploreConcave" />
|
||||
<h3>Explore concave areas</h3><span class="tooltip" title="Try to solve for enclosed concave areas (eg. a jigsaw puzzle piece) This will take much longer to compute ">?</span>
|
||||
|
||||
<a href="#" class="button" id="configsave">Save Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar">
|
||||
<div id="info">
|
||||
<h2 id="info_time"></h2>
|
||||
<div class="progress"><div class="progress_inner" id="info_progress"></div></div>
|
||||
<span class="subscript">Placement progress</span>
|
||||
|
||||
<div id="info_placement">
|
||||
<div class="column left">
|
||||
<h1 class="label"><span id="info_efficiency"></span><sup>%</sup></h1>
|
||||
<span class="subscript">Material Utilization</span>
|
||||
</div>
|
||||
|
||||
<div class="column right">
|
||||
<h1 class="label" id="info_iterations"></h1>
|
||||
<span class="subscript">Iterations</span>
|
||||
</div>
|
||||
|
||||
<div class="column left">
|
||||
<h1 class="label"><span id="info_placed"></span></h1>
|
||||
<span class="subscript">Parts placed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="select">
|
||||
<svg version="1.1" id="svg2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1147.592px" height="1397.27px" viewBox="0 0 1147.592 1397.27" enable-background="new 0 0 1147.592 1397.27" xml:space="preserve">
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="684.045,443.734 688.396,447.215
|
||||
666.488,450.935 666.488,432.651 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="697.067,404.901 697.067,415.601
|
||||
709.719,415.905 710.293,406.067 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="723.908,440.886 715.362,442.463
|
||||
709.719,435.85 712.627,427.66 721.17,426.079 726.81,432.692 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="617.292,458.369 618.742,465.049
|
||||
599.735,465.566 599.735,447.28 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="619.963,428.025 619.963,438.722
|
||||
633.189,438.467 633.189,429.192 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="646.805,464.01 638.259,465.587
|
||||
632.618,458.974 635.523,450.784 644.069,449.207 649.706,455.819 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="777.062,428.025 746.983,457.397
|
||||
760.468,481.256 782.898,488.173 788.995,478.145 814.669,479.959 818.817,438.722 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="666.589,476.434 664.255,503.557
|
||||
681.632,505.633 694.857,499.916 692.262,483.07 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="599.735,501.612 636.247,531.953
|
||||
680.981,531.953 680.981,554.904 599.735,554.904 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="759.315,529.301 775.721,500.886
|
||||
792.128,529.301 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="741.307,428.338 734.229,419.461
|
||||
736.757,408.396 746.983,403.469 757.206,408.396 759.735,419.461 752.654,428.338 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="647.399,599.509 651.749,602.988
|
||||
629.84,606.702 629.84,588.419 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="650.068,569.167 650.068,579.861
|
||||
662.723,580.171 663.294,570.334 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="758.061,626.35 800.104,626.854
|
||||
807.438,600.447 796.468,579.694 785.065,582.478 768.195,563.04 736.104,589.264 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="694.308,592.604 687.232,583.727
|
||||
689.758,572.661 699.984,567.735 710.211,572.661 712.736,583.727 705.658,592.604 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="854.273,544.551 858.625,548.03
|
||||
836.717,551.75 836.717,533.467 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="856.944,514.209 856.944,524.909
|
||||
869.597,525.213 870.171,515.376 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="883.785,550.194 875.24,551.771
|
||||
869.597,545.158 872.505,536.968 881.048,535.388 886.688,542.001 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="779.841,537.333 779.841,548.03
|
||||
793.067,547.775 793.067,538.5 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="901.184,537.646 894.106,528.769
|
||||
896.635,517.703 906.861,512.777 917.084,517.703 919.613,528.769 912.532,537.646 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.717,410.401 827.633,456.421
|
||||
894.106,463.102 910.101,434.273 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="676.909,605.146 668.363,606.727
|
||||
662.723,600.113 665.628,591.92 674.174,590.346 679.814,596.959 "/>
|
||||
<rect x="21.066" y="439.913" width="30.913" height="18.155" fill="none" stroke="#010101"/>
|
||||
<rect x="106.758" y="452.881" width="29.563" height="5.188" fill="none" stroke="#010101"/>
|
||||
<rect x="184.038" y="464.809" width="25.963" height="17.637" fill="none" stroke="#010101"/>
|
||||
<rect x="305.408" y="427.01" width="17.01" height="40.393" fill="none" stroke="#010101"/>
|
||||
<rect x="262.876" y="458.068" width="17.004" height="17.633" fill="none" stroke="#010101"/>
|
||||
<rect x="338.931" y="427.01" width="47.904" height="25.868" fill="none" stroke="#010101"/>
|
||||
<polygon fill="none" stroke="#010101" points="66.82,475.701 47.112,507.86 101.95,510.972 140.64,493.336 90.161,496.448 87.322,473.625 "/>
|
||||
<polygon fill="none" stroke="#010101" points="196.401,495.929 224.016,523.938 348.972,517.196 271.061,492.297 227.967,473.625 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1065.045,441.528 1069.396,445.009
|
||||
1047.488,448.729 1047.488,430.445 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1078.067,402.694 1078.067,413.395
|
||||
1090.719,413.699 1091.293,403.861 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1104.908,438.68 1096.362,440.257
|
||||
1090.719,433.644 1093.627,425.454 1102.17,423.873 1107.811,430.486 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="998.292,456.163 999.742,462.843
|
||||
980.735,463.359 980.735,445.074 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1000.963,425.818 1000.963,436.516
|
||||
1014.189,436.261 1014.189,426.985 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1027.805,461.804 1019.259,463.381
|
||||
1013.618,456.768 1016.523,448.578 1025.069,447.001 1030.706,453.613 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="601.531,174.639 571.451,204.011
|
||||
584.936,227.87 607.366,234.787 613.463,224.759 639.137,226.573 643.285,185.336 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1047.589,474.228 1045.255,501.351
|
||||
1062.632,503.427 1075.857,497.71 1073.262,480.864 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="980.735,499.406 1017.247,529.747
|
||||
1061.98,529.747 1061.98,552.698 980.735,552.698 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="583.783,275.915 600.188,247.5
|
||||
616.596,275.915 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="565.774,174.952 558.696,166.075
|
||||
561.225,155.01 571.451,150.083 581.674,155.01 584.203,166.075 577.122,174.952 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1028.399,597.303 1032.749,600.782
|
||||
1010.84,604.496 1010.84,586.213 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1031.068,566.961 1031.068,577.655
|
||||
1043.723,577.965 1044.294,568.128 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="582.528,372.964 624.57,373.468
|
||||
631.906,347.062 620.936,326.309 609.533,329.092 592.663,309.654 560.571,335.878 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1075.308,590.397 1068.232,581.521
|
||||
1070.758,570.455 1080.984,565.529 1091.211,570.455 1093.736,581.521 1086.658,590.397 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="678.741,291.165 683.093,294.645
|
||||
661.185,298.364 661.185,280.081 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="681.412,260.823 681.412,271.524
|
||||
694.064,271.827 694.639,261.99 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="708.253,296.809 699.708,298.386
|
||||
694.064,291.773 696.973,283.582 705.516,282.002 711.155,288.615 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="604.309,283.947 604.309,294.645
|
||||
617.535,294.389 617.535,285.114 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="725.651,284.26 718.574,275.383
|
||||
721.104,264.317 731.329,259.392 741.552,264.317 744.081,275.383 737,284.26 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="661.185,157.016 652.101,203.035
|
||||
718.574,209.716 734.568,180.887 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1057.909,602.939 1049.363,604.521
|
||||
1043.723,597.907 1046.628,589.714 1055.174,588.14 1060.814,594.753 "/>
|
||||
<rect x="402.066" y="437.707" width="30.912" height="18.155" fill="none" stroke="#010101" />
|
||||
<rect x="487.758" y="450.675" width="29.564" height="5.188" fill="none" stroke="#010101" />
|
||||
<rect x="565.949" y="691.507" width="25.963" height="17.636" fill="none" stroke="#010101" />
|
||||
<rect x="687.32" y="653.708" width="17.01" height="40.392" fill="none" stroke="#010101" />
|
||||
<rect x="644.789" y="684.767" width="17.004" height="17.634" fill="none" stroke="#010101" />
|
||||
<rect x="720.844" y="653.708" width="47.904" height="25.868" fill="none" stroke="#010101" />
|
||||
<polygon fill="none" stroke="#010101" points="447.82,473.495 428.112,505.654 482.95,508.766 521.641,491.13 471.161,494.242 468.322,471.419 "/>
|
||||
<polygon fill="none" stroke="#010101" points="578.312,722.627 605.928,750.635 730.885,743.895 652.973,718.995 609.879,700.323 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="903.513,195.164 907.864,198.645
|
||||
885.956,202.364 885.956,184.081 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="916.535,156.33 916.535,167.03
|
||||
929.188,167.335 929.761,157.497 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="943.376,192.316 934.83,193.893
|
||||
929.188,187.279 932.095,179.09 940.638,177.509 946.277,184.122 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.76,209.799 838.209,216.479
|
||||
819.203,216.995 819.203,198.71 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="839.432,179.454 839.432,190.151
|
||||
852.657,189.897 852.657,180.621 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="866.271,215.44 857.727,217.017
|
||||
852.086,210.403 854.991,202.214 863.537,200.637 869.174,207.249 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="996.531,179.454 966.451,208.826
|
||||
979.936,232.686 1002.366,239.603 1008.463,229.574 1034.137,231.389 1038.285,190.151 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="886.057,227.863 883.723,254.986
|
||||
901.1,257.063 914.325,251.346 911.729,234.5 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="819.203,253.042 855.715,283.383
|
||||
900.449,283.383 900.449,306.334 819.203,306.334 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="978.783,280.731 995.188,252.316
|
||||
1011.596,280.731 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="960.774,179.768 953.696,170.891
|
||||
956.225,159.825 966.451,154.899 976.674,159.825 979.203,170.891 972.122,179.768 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="866.867,350.939 871.217,354.418
|
||||
849.308,358.132 849.308,339.849 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="869.536,320.597 869.536,331.291
|
||||
882.19,331.601 882.762,321.764 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="977.528,377.779 1019.57,378.283
|
||||
1026.906,351.877 1015.936,331.124 1004.533,333.907 987.663,314.47 955.571,340.693 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="913.775,344.033 906.7,335.156
|
||||
909.226,324.091 919.452,319.165 929.679,324.091 932.204,335.156 925.126,344.033 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1073.741,295.981 1078.093,299.46
|
||||
1056.186,303.18 1056.186,284.897 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1076.412,265.639 1076.412,276.339
|
||||
1089.064,276.643 1089.639,266.806 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1103.253,301.624 1094.708,303.201
|
||||
1089.064,296.588 1091.973,288.398 1100.516,286.817 1106.155,293.431 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="999.309,288.763 999.309,299.46
|
||||
1012.535,299.204 1012.535,289.93 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1120.651,289.075 1113.574,280.198
|
||||
1116.104,269.133 1126.329,264.207 1136.552,269.133 1139.081,280.198 1132,289.075 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1056.186,161.831 1047.101,207.851
|
||||
1113.574,214.531 1129.568,185.702 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="896.377,356.575 887.831,358.156
|
||||
882.19,351.543 885.096,343.35 893.642,341.776 899.282,348.389 "/>
|
||||
<rect x="797.979" y="671.427" width="30.912" height="18.155" fill="none" stroke="#010101" />
|
||||
<rect x="883.67" y="684.395" width="29.564" height="5.188" fill="none" stroke="#010101" />
|
||||
<rect x="916.535" y="655.978" width="25.963" height="17.637" fill="none" stroke="#010101" />
|
||||
<rect x="1037.906" y="618.179" width="17.01" height="40.393" fill="none" stroke="#010101" />
|
||||
<rect x="995.375" y="649.237" width="17.004" height="17.633" fill="none" stroke="#010101" />
|
||||
<rect x="1071.43" y="618.179" width="47.904" height="25.868" fill="none" stroke="#010101" />
|
||||
<polygon fill="none" stroke="#010101" points="843.732,707.215 824.023,739.374 878.861,742.484 917.553,724.85 867.072,727.962 864.234,705.139 "/>
|
||||
<polygon fill="none" stroke="#010101" points="928.898,687.098 956.514,715.105 1081.471,708.365 1003.559,683.466 960.465,664.794 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="105.375,574.337 109.727,577.817
|
||||
87.819,581.537 87.819,563.254 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="118.398,535.503 118.398,546.203
|
||||
131.049,546.508 131.624,536.67 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="145.239,571.488 136.693,573.065
|
||||
131.049,566.452 133.958,558.263 142.5,556.682 148.14,563.295 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="38.623,588.972 40.072,595.651
|
||||
21.066,596.168 21.066,577.883 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="41.294,558.627 41.294,569.324
|
||||
54.52,569.069 54.52,559.794 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="68.135,594.612 59.589,596.189
|
||||
53.949,589.576 56.854,581.387 65.4,579.81 71.037,586.422 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="198.394,558.627 168.314,587.999
|
||||
181.798,611.858 204.229,618.775 210.326,608.747 236,610.562 240.148,569.324 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="87.919,607.036 85.585,634.159
|
||||
102.962,636.235 116.188,630.519 113.592,613.673 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="21.066,632.215 57.578,662.556
|
||||
102.312,662.556 102.312,685.507 21.066,685.507 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="180.646,659.903 197.051,631.488
|
||||
213.458,659.903 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="162.637,558.94 155.559,550.062
|
||||
158.087,538.998 168.314,534.071 178.537,538.998 181.066,550.062 173.985,558.94 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="68.73,730.111 73.08,733.591
|
||||
51.17,737.305 51.17,719.021 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="71.399,699.77 71.399,710.464
|
||||
84.053,710.773 84.625,700.938 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="115.638,723.206 108.563,714.329
|
||||
111.088,703.264 121.315,698.338 131.542,703.264 134.067,714.329 126.989,723.206 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="275.604,675.153 279.956,678.633
|
||||
258.047,682.354 258.047,664.069 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="278.275,644.812 278.275,655.512
|
||||
290.927,655.815 291.501,645.979 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="305.116,680.797 296.571,682.374
|
||||
290.927,675.761 293.835,667.57 302.378,665.99 308.018,672.604 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="201.171,667.936 201.171,678.633
|
||||
214.398,678.377 214.398,669.104 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="322.514,668.248 315.438,659.371
|
||||
317.965,648.306 328.192,643.38 338.415,648.306 340.944,659.371 333.863,668.248 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="258.047,541.004 248.963,587.023
|
||||
315.438,593.704 331.431,564.875 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="98.24,735.748 89.694,737.329
|
||||
84.053,730.716 86.958,722.521 95.504,720.948 101.145,727.562 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="504.59,600.795 508.941,604.275
|
||||
487.033,607.995 487.033,589.712 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="517.611,561.961 517.611,572.661
|
||||
530.264,572.966 530.838,563.128 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="545.365,716.138 536.818,717.715
|
||||
531.176,711.102 534.084,702.912 542.627,701.331 548.266,707.944 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="437.837,615.43 439.287,622.109
|
||||
420.28,622.626 420.28,604.341 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="440.508,585.085 440.508,595.782
|
||||
453.734,595.527 453.734,586.252 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="467.35,621.07 458.804,622.646
|
||||
453.163,616.034 456.068,607.845 464.614,606.268 470.251,612.88 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="598.52,813.989 568.439,843.361
|
||||
581.924,867.221 604.355,874.138 610.451,864.109 636.125,865.924 640.273,824.687 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="487.134,633.494 484.8,660.617
|
||||
502.177,662.693 515.402,656.977 512.807,640.131 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="420.28,658.673 456.792,689.014
|
||||
501.526,689.014 501.526,711.965 420.28,711.965 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="580.771,915.266 597.178,886.851
|
||||
613.584,915.266 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="562.764,814.303 555.686,805.426
|
||||
558.213,794.359 568.439,789.434 578.662,794.359 581.191,805.426 574.111,814.303 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="467.944,756.569 472.294,760.049
|
||||
450.385,763.763 450.385,745.479 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="470.613,726.229 470.613,736.922
|
||||
483.268,737.231 483.839,727.395 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="514.852,749.664 507.777,740.787
|
||||
510.303,729.722 520.529,724.796 530.756,729.722 533.281,740.787 526.203,749.664 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="675.73,930.516 680.082,933.995
|
||||
658.174,937.715 658.174,919.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="678.4,900.174 678.4,910.874
|
||||
691.053,911.178 691.627,901.341 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="705.242,936.159 696.697,937.736
|
||||
691.053,931.123 693.961,922.933 702.504,921.353 708.145,927.966 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="601.297,923.298 601.297,933.995
|
||||
614.523,933.739 614.523,924.465 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="563.383,919.432 559.621,926.865
|
||||
550.156,929.546 550.156,937.715 559.621,940.869 563.383,946.966 571.941,946.966 575.18,942.553 581.07,937.736 581.07,929.546
|
||||
575.18,926.087 570.123,919.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="722.641,923.609 715.562,914.734
|
||||
718.092,903.668 728.318,898.742 738.541,903.668 741.07,914.734 733.988,923.609 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="658.174,796.366 649.09,842.386
|
||||
715.562,849.066 731.557,820.237 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="497.454,762.206 488.908,763.787
|
||||
483.268,757.174 486.173,748.98 494.719,747.406 500.359,754.02 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="900.502,834.515 904.854,837.995
|
||||
882.945,841.715 882.945,823.432 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="913.523,795.681 913.523,806.381
|
||||
926.176,806.686 926.75,796.848 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="940.365,831.666 931.818,833.243
|
||||
926.176,826.63 929.084,818.441 937.627,816.859 943.266,823.473 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="833.748,849.15 835.197,855.829
|
||||
816.191,856.346 816.191,838.061 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="836.42,818.805 836.42,829.502
|
||||
849.646,829.247 849.646,819.972 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="863.262,854.79 854.715,856.367
|
||||
849.074,849.754 851.98,841.564 860.525,839.987 866.162,846.6 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="993.52,818.805 963.439,848.177
|
||||
976.924,872.036 999.355,878.953 1005.451,868.925 1031.125,870.739 1035.273,829.502 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="957.764,819.118 950.686,810.241
|
||||
953.213,799.176 963.439,794.249 973.662,799.176 976.191,810.241 969.111,819.118 "/>
|
||||
<polygon fill="none" stroke="#010101" stroke-miterlimit="10" points="1053.174,801.182 1044.09,847.201
|
||||
1110.562,853.882 1126.557,825.053 "/>
|
||||
<rect width="511.822" height="339.235" fill="none" stroke="#010101" />
|
||||
|
||||
<path fill="none" stroke="#010101" d="M746.843,60.679c-2.465,1.232-7.395,2.465-13.711,2.465c-14.635,0-25.65-9.243-25.65-26.266
|
||||
c0-16.252,11.016-27.268,27.113-27.268c6.471,0,10.553,1.387,12.324,2.311l-1.617,5.469c-2.542-1.232-6.162-2.157-10.476-2.157
|
||||
c-12.17,0-20.258,7.78-20.258,21.414c0,12.709,7.317,20.874,19.95,20.874c4.082,0,8.241-0.848,10.938-2.157L746.843,60.679z"/>
|
||||
<path fill="none" stroke="#010101" d="M755.008,7.685h6.778v54.688h-6.778V7.685z"/>
|
||||
<path fill="none" stroke="#010101" d="M780.734,14.617c0.077,2.311-1.617,4.16-4.313,4.16c-2.388,0-4.082-1.849-4.082-4.16c0-2.388,1.771-4.236,4.236-4.236
|
||||
C779.117,10.38,780.734,12.229,780.734,14.617z M773.187,62.373V25.092h6.777v37.281H773.187z"/>
|
||||
<path fill="none" stroke="#010101" d="M817.784,60.986c-1.771,0.925-5.7,2.157-10.707,2.157c-11.246,0-18.563-7.626-18.563-19.026
|
||||
c0-11.477,7.856-19.795,20.027-19.795c4.005,0,7.548,1.001,9.397,1.925l-1.541,5.238c-1.617-0.924-4.159-1.771-7.856-1.771
|
||||
c-8.55,0-13.172,6.316-13.172,14.096c0,8.627,5.546,13.942,12.94,13.942c3.852,0,6.394-1.001,8.318-1.849L817.784,60.986z"/>
|
||||
<path fill="none" stroke="#010101" d="M832.42,42.192h0.154c0.924-1.31,2.233-2.927,3.312-4.237l10.938-12.863h8.164L840.585,40.42l16.406,21.953h-8.241
|
||||
l-12.864-17.87l-3.466,3.852v14.019h-6.701V7.685h6.701V42.192z"/>
|
||||
<path fill="none" stroke="#010101" d="M885.107,16.157h-15.79v-5.7h38.437v5.7h-15.867v46.216h-6.779V16.157z"/>
|
||||
<path fill="none" stroke="#010101" d="M912.762,7.685h6.778v23.262h0.154c1.078-1.926,2.772-3.62,4.853-4.775c2.002-1.156,4.391-1.926,6.932-1.926
|
||||
c5.007,0,13.018,3.081,13.018,15.944v22.184h-6.778V40.96c0-6.008-2.233-11.092-8.627-11.092c-4.39,0-7.856,3.081-9.089,6.778
|
||||
c-0.385,0.924-0.462,1.925-0.462,3.235v22.492h-6.778V7.685z"/>
|
||||
<path fill="none" stroke="#010101" d="M963.062,14.617c0.077,2.311-1.618,4.16-4.313,4.16c-2.389,0-4.083-1.849-4.083-4.16c0-2.388,1.771-4.236,4.236-4.236
|
||||
C961.443,10.38,963.062,12.229,963.062,14.617z M955.513,62.373V25.092h6.778v37.281H955.513z"/>
|
||||
<path fill="none" stroke="#010101" d="M972.611,55.44c2.003,1.31,5.546,2.696,8.936,2.696c4.93,0,7.24-2.465,7.24-5.546c0-3.235-1.926-5.007-6.933-6.855
|
||||
c-6.701-2.388-9.859-6.085-9.859-10.553c0-6.008,4.853-10.938,12.864-10.938c3.773,0,7.086,1.078,9.166,2.311l-1.695,4.93
|
||||
c-1.463-0.924-4.159-2.157-7.625-2.157c-4.006,0-6.239,2.311-6.239,5.084c0,3.081,2.233,4.467,7.086,6.316
|
||||
c6.471,2.465,9.782,5.7,9.782,11.246c0,6.547-5.083,11.169-13.941,11.169c-4.082,0-7.856-1.001-10.476-2.542L972.611,55.44z"/>
|
||||
<polygon fill="none" stroke="#010101" points="676.149,23 616.756,23 616.756,1 558.443,34.667 616.756,68.333 616.756,46.333 676.149,46.333 "/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<div id="bins"></div>
|
||||
|
||||
<input id="fileinput" type="file" style="visibility:hidden" />
|
||||
</div>
|
||||
|
||||
<div id="messagewrapper">
|
||||
<div id="message"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
114
public/svgnest/readme.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# 
|
||||
|
||||
**SVGNest**: A browser-based vector nesting tool.
|
||||
|
||||
**Demo:** http://svgnest.com
|
||||
|
||||
(requires SVG and webworker support). Mobile warning: running the demo is CPU intensive.
|
||||
|
||||
references (PDF):
|
||||
- [López-Camacho *et al.* 2013](http://www.cs.stir.ac.uk/~goc/papers/EffectiveHueristic2DAOR2013.pdf)
|
||||
- [Kendall 2000](http://www.graham-kendall.com/papers/k2001.pdf)
|
||||
- [E.K. Burke *et al.* 2006](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.440.379&rep=rep1&type=pdf)
|
||||
|
||||
## What is "nesting"?
|
||||
|
||||
Given a square piece of material and some letters to be laser-cut:
|
||||
|
||||

|
||||
|
||||
We want to pack all the letters into the square, using as little material as possible. If a single square is not enough, we also want to minimize the number of squares used.
|
||||
|
||||
In the CNC world this is called "[nesting](http://sigmanest.com/)", and [software](http://www.mynesting.com/) that [does this](http://www.autodesk.com/products/trunest/overview) is typically targeted at [industrial customers](http://www.hypertherm.com/en/Products/Automated_cutting/Nesting_software/) and [very expensive](http://www.nestfab.com/pricing/).
|
||||
|
||||
SVGnest is a free and open-source alternative that solves this problem with the orbital approach outlined in [E.K. Burke *et al.* 2006], using a genetic algorithm for global optimization. It works for arbitrary containers and concave edge cases, and performs on-par with existing commercial software.
|
||||
|
||||

|
||||
|
||||
It also features part-in-part support, for placing parts in the holes of other parts.
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
Make sure all parts have been converted to outlines, and that no outlines overlap. Upload the SVG file and select one of the outlines to be used as the bin.
|
||||
|
||||
All other outlines are automatically processed as parts for nesting.
|
||||
|
||||
## Outline of algorithm
|
||||
|
||||
While [good heuristics](http://cgi.csc.liv.ac.uk/~epa/surveyhtml.html) exist for the rectangular bin packing problem, in the real world we are concerned with irregular shapes.
|
||||
|
||||
The strategy is made of two parts:
|
||||
|
||||
- the placement strategy (ie. how do I insert each part into a bin?)
|
||||
- and the optimization strategy (ie. what's the best order of insertions?)
|
||||
|
||||
### Placing the part
|
||||
|
||||
The key concept here is the "No Fit Polygon".
|
||||
|
||||
Given polygons A and B, we want to "orbit" B around A such that they always touch but do not intersect.
|
||||
|
||||

|
||||
|
||||
The resulting orbit is the NFP. The NFP contains all possible placements of B that touches the previously placed parts. We can then choose a point on the NFP as the placement position using some heuristics.
|
||||
|
||||
Similarly we can construct an "Inner Fit Polygon" for the part and the bin. This is the same as the NFP, except the orbiting polygon is inside the stationary one.
|
||||
|
||||
When two or more parts have already been placed, we can take the union of the NFPs of the previously placed parts.
|
||||
|
||||

|
||||
|
||||
This means that we need to compute O(nlogn) NFPs to complete the first packing. While there are ways to mitigate this, we take the brute-force approach which has good properties for the optimization algo.
|
||||
|
||||
### Optimization
|
||||
|
||||
Now that we can place the parts, we need to optimize the insertion order. Here's an example of a bad insertion order:
|
||||
|
||||

|
||||
|
||||
If the large "C" is placed last, the concave space inside it won't be utilized because all the parts that could have filled it have already been placed.
|
||||
|
||||
To solve this, we use the "first-fit-decreasing" heuristic. Larger parts are placed first, and smaller parts last. This is quite intuitive, as the smaller parts tend to act as "sand" to fill the gaps left by the larger parts.
|
||||
|
||||

|
||||
|
||||
While this strategy gives us a good start, we want to explore more of the solution space. We could simply randomize the insertion order, but we can probably do better with a genetic algorithm. (If you don't know what a GA is, [this article](http://www.ai-junkie.com/ga/intro/gat1.html) is a very approachable read)
|
||||
|
||||
## Evaluating fitness
|
||||
|
||||
In our GA the insertion order and the rotation of the parts form the gene. The fitness function follows these rules:
|
||||
|
||||
1. Minimize the number of unplaceable parts (parts that cannot fit any bin due to its rotation)
|
||||
2. Minimize the number of bins used
|
||||
3. Minimize the *width* of all placed parts
|
||||
|
||||
The third one is rather arbitrary, as we can also optimize for rectangular bounds or a minimal concave hull. In real-world use the material to be cut tends to be rectangular, and those options tend to result in long slivers of un-used material.
|
||||
|
||||
Because small mutations in the gene cause potentially large changes in overall fitness, the individuals of the population can be very similar. By caching NFPs new individuals can be evaluated very quickly.
|
||||
|
||||
## Performance
|
||||
|
||||

|
||||
|
||||
Performs similarly to commercial software, after both have run for about 5 minutes.
|
||||
|
||||
## Configuration parameters
|
||||
|
||||
- **Space between parts:** Minimum space between parts (eg. for laser kerf, CNC offset etc.)
|
||||
- **Curve tolerance:** The maximum error allowed for linear approximations of Bezier paths and arcs, in SVG units or "pixels". Decrease this value if curved parts appear to slightly overlap.
|
||||
- **Part rotations:** The *possible* number of rotations to evaluate for each part. eg. 4 for only the cardinal directions. Larger values may improve results, but will be slower to converge.
|
||||
- **GA population:** The population size for the Genetic Algorithm
|
||||
- **GA mutation rate:** The probability of mutation for each gene or part placement. Values from 1-50
|
||||
- **Part in part:** When enabled, places parts in the holes of other parts. This is off by default as it can be resource intensive
|
||||
- **Explore concave areas:** When enabled, solves the concave edge case at a cost of some performance and placement robustness:
|
||||
|
||||

|
||||
|
||||
## To-do
|
||||
|
||||
- ~~Recursive placement (putting parts in holes of other parts)~~
|
||||
- Customize fitness function (gravity direction, etc)
|
||||
- kill worker threads when stop button is clicked
|
||||
- fix certain edge cases in NFP generation
|
||||
628
public/svgnest/style.css
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
/* =========================================================
|
||||
SVGNest — MakeArmy True-Gray Theme (final teal version)
|
||||
- Neutral gray UI with Teal accents (#20C5B5)
|
||||
- Fixed #svgnest top spacing (removed giant gap)
|
||||
- Restores !important on SVG stroke/fill so uploaded parts display correctly
|
||||
- Accent is consistent across links, buttons, tooltips, selection, progress
|
||||
========================================================= */
|
||||
|
||||
:root{
|
||||
/* Neutral grayscale foundation */
|
||||
--bg: #0e0e0e; /* page background (near-black) */
|
||||
--bg-2: #1a1a1a; /* panels / cards / buttons */
|
||||
--bg-3: #121212; /* bins / work areas */
|
||||
--text: #e0e0e0; /* primary text */
|
||||
--muted: #a0a0a0; /* secondary text */
|
||||
--border: #2a2a2a; /* subtle borders */
|
||||
--shadow: rgba(0,0,0,0.40);
|
||||
|
||||
/* Teal accent */
|
||||
--accent: #20C5B5; /* primary accent */
|
||||
--accent-2: #1aa397; /* darker hover/active */
|
||||
|
||||
/* True-grays (replace any previous blues) */
|
||||
--gray-1: #f0f0f0; /* headings, light text */
|
||||
--gray-2: #cccccc; /* subheadings */
|
||||
--gray-3: #888888; /* lines / subtle emphasis */
|
||||
--gray-4: #555555; /* secondary fills */
|
||||
}
|
||||
|
||||
/* ===== Base ===== */
|
||||
html, body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font: normal 22px/1.4 'LatoLatinWeb', helvetica, arial, verdana, sans-serif;
|
||||
background-color: var(--bg);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
a{
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
transition: color .15s ease;
|
||||
}
|
||||
a:hover{
|
||||
color: var(--accent-2);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1{
|
||||
font-size: 1.5em;
|
||||
font-family: 'LatoLatinWebLight', helvetica, arial, verdana, sans-serif;
|
||||
font-weight: normal;
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
color: var(--gray-1);
|
||||
}
|
||||
h2{
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0.5em 0;
|
||||
color: var(--gray-2);
|
||||
}
|
||||
h3{
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
margin: 1em 0 0.2em 0;
|
||||
color: var(--gray-2);
|
||||
}
|
||||
|
||||
/* ===== Splash ===== */
|
||||
#splash{
|
||||
width: 28em;
|
||||
margin: 8% auto 0 auto;
|
||||
}
|
||||
#splash .logo{
|
||||
width: 50%;
|
||||
margin: 0 0 0 25%;
|
||||
height: auto;
|
||||
}
|
||||
#splash h1{ color: var(--accent); }
|
||||
#splash h1.title{
|
||||
font-size: 3.5em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.subscript{ font-size: 0.75em; }
|
||||
#splash .subscript{
|
||||
display: block;
|
||||
color: var(--accent);
|
||||
font-size: 1.45em;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* ===== Nav + Buttons ===== */
|
||||
.nav{ margin: 0; padding: 0; }
|
||||
li{ list-style: none; float: left; margin: 0; padding: 0; }
|
||||
|
||||
.button{
|
||||
display: block;
|
||||
margin: 0 0.5em;
|
||||
padding: 0.6em 2.4em;
|
||||
background-color: var(--bg-2);
|
||||
border-radius: 5em;
|
||||
border: 1px solid var(--border);
|
||||
cursor: pointer;
|
||||
color: var(--accent);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.25);
|
||||
transition: color .15s ease, box-shadow .15s ease, border-color .15s ease, background-color .15s ease;
|
||||
}
|
||||
.button a:hover{ text-decoration: none; }
|
||||
|
||||
.button.start{
|
||||
background: var(--bg-2) url(img/start.svg) no-repeat 1.8em 50% / 1.4em 1.4em;
|
||||
padding-left: 3.7em;
|
||||
}
|
||||
.button.spinner{
|
||||
background: var(--bg-2) url(img/spin.svg) no-repeat 1.8em 50% / 1.4em 1.4em;
|
||||
padding-left: 3.7em;
|
||||
}
|
||||
.button.upload{
|
||||
background: var(--bg-2) url(img/upload.svg) no-repeat 2.2em 50% / 1em 1em;
|
||||
padding-left: 4em;
|
||||
}
|
||||
.button.download{
|
||||
background: var(--bg-2) url(img/download.svg) no-repeat 2.2em 50% / 1em 1em;
|
||||
padding-left: 4em;
|
||||
}
|
||||
.button.code{
|
||||
background: var(--bg-2) url(img/code.svg) no-repeat 2em 50% / 1.2em 1.2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.config{
|
||||
background: var(--bg-2) url(img/settings.svg) no-repeat 2em 50% / 1.2em 1.2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.close{
|
||||
background: var(--bg-2) url(img/close.svg) no-repeat 1.8em 50% / 2em 2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.zoomin{ background: var(--bg-2) url(img/zoomin.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
.button.zoomout{ background: var(--bg-2) url(img/zoomout.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
.button.exit{ background: var(--bg-2) url(img/close.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
|
||||
.button:hover{
|
||||
color: var(--accent-2);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
||||
text-decoration: none;
|
||||
}
|
||||
.button:active{
|
||||
background-color: #1f1f1f;
|
||||
border-color: var(--accent-2);
|
||||
box-shadow: inset 0 2px 2px rgba(0,0,0,0.35);
|
||||
}
|
||||
.button.disabled{
|
||||
cursor: default; opacity: 0.5; color: #999;
|
||||
-webkit-filter: saturate(0); filter: saturate(0);
|
||||
}
|
||||
.button.disabled:hover{ box-shadow: none; border-color: var(--border); }
|
||||
.button.disabled:active{ background-color: var(--bg-2); box-shadow: none; }
|
||||
|
||||
#splash .nav{ float: left; width: 150%; margin: 4em 0 0 -20%; }
|
||||
#faq{ display: none; float: left; margin-top: 2em; padding-bottom: 5em; }
|
||||
|
||||
/* ===== SVGNest layout ===== */
|
||||
#svgnest, #messagewrapper{ width: 72em; }
|
||||
|
||||
/* FIXED: smaller, responsive top spacing (replaces 9em) */
|
||||
#svgnest{
|
||||
display: none;
|
||||
margin: clamp(1rem, 3vh, 2.5rem) auto 0 auto;
|
||||
}
|
||||
|
||||
#svgnest .logo, #svgnest .sidebar{ float: left; width: 22%; margin-right: 8%; }
|
||||
#svgnest .sidebar h1{ font-size: 3em; color: var(--text); }
|
||||
#svgnest .sidebar{ clear: both; width: 100%; margin-top: 3em; }
|
||||
|
||||
#svgnest .nav{ float: left; margin: 0 0 0 -0.5em; padding: 0; }
|
||||
#controls{ margin-top: 0.5em; float: left; position: relative; }
|
||||
|
||||
/* ===== Info sidebar ===== */
|
||||
#info, #info_placement{ display: none; }
|
||||
h1.label{
|
||||
font-size: 4em; margin: 0.2em 0 0 0; padding: 0;
|
||||
line-height: 1; font-weight: normal; color: var(--text);
|
||||
}
|
||||
h1.label sup{ font-size: 0.5em; }
|
||||
.column{ margin: 0.5em 4em 2em 0; float: left; }
|
||||
|
||||
/* ===== Progress ===== */
|
||||
.progress{
|
||||
width: 51%;
|
||||
clear: both;
|
||||
height: 1.2em;
|
||||
background-color: var(--bg-2);
|
||||
border: 1px solid var(--accent); /* accent border */
|
||||
border-radius: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
.progress_inner{
|
||||
height: 100%;
|
||||
background-color: var(--accent); /* accent fill */
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
/* ===== Config panel ===== */
|
||||
#config{
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
width: 20em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 24.5em;
|
||||
background-color: var(--bg-2);
|
||||
border-radius: 0.5em;
|
||||
transition: max-height 0.5s;
|
||||
box-shadow: 0 2px 8px var(--shadow);
|
||||
}
|
||||
#configwrapper{ float: left; padding: 3em 0 1em 2em; }
|
||||
#config.active{ display: block; max-height: 50em; }
|
||||
#configbutton{ position: relative; z-index: 2; width: 3em; padding: 0; height: 2.5em; background-position: 50%; }
|
||||
#zoominbutton, #zoomoutbutton, #exitbutton{ width: 3em; padding: 0; height: 2.5em; background-position: 50%; }
|
||||
#configbutton.close:hover{ box-shadow: none; }
|
||||
#configsave{ margin-left: 7%; }
|
||||
|
||||
#config input, #config h3, #config .tooltip{ margin: 1em 0 0 0; height: 2em; padding: 0; }
|
||||
#config input{
|
||||
float: left; width: 13%; font-size: 1em;
|
||||
border: 1px solid var(--accent);
|
||||
color: var(--text);
|
||||
background: #141414;
|
||||
text-align: center; clear: left; border-radius: 0.4em;
|
||||
transition: border-color .15s ease, background-color .15s ease;
|
||||
}
|
||||
#config input:hover{ background-color: #181818; border-color: var(--accent-2); }
|
||||
#config input.checkbox{ width: 7%; margin-left: 4%; margin-right: 4%; border: 1px solid var(--border); }
|
||||
#config h3{ float: left; width: 65%; margin-left: 5%; padding: 0; font-size: 0.8em; line-height: 3em; color: var(--muted); }
|
||||
#config .tooltip{
|
||||
float: left; max-width: 15%; width: 1.5em; height: 1.5em;
|
||||
font-size: 0.8em; font-weight: bold; background-color: var(--accent);
|
||||
color: #fff; text-align: center; line-height: 1.5; margin-top: 1.8em;
|
||||
cursor: default; border-radius: 3em;
|
||||
}
|
||||
#config .button{ float: left; clear: both; margin-top: 2em; }
|
||||
|
||||
/* ===== SVG areas ===== */
|
||||
#select{ margin-top: 2em; }
|
||||
#select, #bins{ float: left; width: 69%; position: relative; }
|
||||
|
||||
#select svg, #bins svg{
|
||||
width: 100%; height: auto; position: absolute; top: 0;
|
||||
margin: 0; display: block; overflow: visible; pointer-events: none;
|
||||
}
|
||||
|
||||
/* Selection strokes (use accent; override uploaded inline styles) */
|
||||
#select svg *{
|
||||
fill: #fff !important;
|
||||
fill-opacity: 0 !important;
|
||||
stroke: var(--accent) !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
pointer-events: fill !important;
|
||||
}
|
||||
#select svg *.fullRect{
|
||||
fill: #1b1b1b !important;
|
||||
fill-opacity: 1 !important;
|
||||
stroke: #1b1b1b !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
}
|
||||
#select svg *:hover{ stroke: var(--accent-2) !important; cursor: pointer !important; }
|
||||
#select svg *.active{ stroke: var(--accent-2) !important; stroke-width: 3px !important; }
|
||||
#select.disabled svg *, #select.disabled svg *:hover, #select.disabled svg *.active{
|
||||
stroke: #6b6b6b !important; stroke-width: 2px !important; cursor: default !important;
|
||||
}
|
||||
|
||||
/* Bins (neutral grays) */
|
||||
#bins svg{ margin-bottom: 2em; }
|
||||
#bins svg.grid{ float: left; width: 45%; margin-right: 5%; min-width: 20em; }
|
||||
#bins svg *{
|
||||
fill: var(--gray-4) !important;
|
||||
stroke: var(--gray-3) !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
}
|
||||
#bins svg .bin{ fill: var(--bg-3) !important; stroke: var(--gray-4) !important; }
|
||||
#bins svg .hole{ fill: var(--bg) !important; stroke: var(--gray-3) !important; }
|
||||
|
||||
/* ===== Messages ===== */
|
||||
#messagewrapper{
|
||||
width: 50em; overflow: hidden;
|
||||
background: var(--gray-4) url(img/close.svg) no-repeat 99% 0.5em / 3em 3em;
|
||||
line-height: 4em;
|
||||
position: fixed; left: 50%; margin-left: -25em; bottom: 1em;
|
||||
text-align: center; border-radius: 0.5em; color: #fff;
|
||||
box-shadow: 0 6px 24px var(--shadow);
|
||||
border-left: 4px solid var(--accent); /* subtle accent marker */
|
||||
}
|
||||
#messagewrapper:hover{ background-color: #666; border-left-color: var(--accent-2); }
|
||||
#message{ overflow: hidden; height: 0; }
|
||||
#message.active, #message.error{ height: 4em; cursor: pointer; }
|
||||
#message.error{ color: #ff314e; font-weight: bold; }
|
||||
|
||||
/* ===== Animations (kept intact) ===== */
|
||||
.animated{
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
@-webkit-keyframes bounce{
|
||||
from,20%,53%,80%,to{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
40%,43%{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-30px,0);
|
||||
transform: translate3d(0,-30px,0);
|
||||
}
|
||||
70%{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-15px,0);
|
||||
transform: translate3d(0,-15px,0);
|
||||
}
|
||||
90%{
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
@keyframes bounce{
|
||||
from,20%,53%,80%,to{
|
||||
animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
40%,43%{
|
||||
animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-30px,0);
|
||||
transform: translate3d(0,-30px,0);
|
||||
}
|
||||
70%{
|
||||
animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-15px,0);
|
||||
transform: translate3d(0,-15px,0);
|
||||
}
|
||||
90%{
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
.bounce{
|
||||
-webkit-animation-name: bounce;
|
||||
animation-name: bounce;
|
||||
-webkit-transform-origin: center bottom;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
@-webkit-keyframes slideInUp{
|
||||
from{
|
||||
-webkit-transform: translate3d(0,100%,0);
|
||||
transform: translate3d(0,100%,0);
|
||||
visibility: visible;
|
||||
}
|
||||
to{
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
@keyframes slideInUp{
|
||||
from{
|
||||
-webkit-transform: translate3d(0,100%,0);
|
||||
transform: translate3d(0,100%,0);
|
||||
visibility: visible;
|
||||
}
|
||||
to{
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
.slideInUp{
|
||||
-webkit-animation-name: slideInUp;
|
||||
animation-name: slideInUp;
|
||||
}
|
||||
|
||||
/* ===== Responsive ===== */
|
||||
@media only screen and (max-width: 1800px){
|
||||
body { font-size: 20px; }
|
||||
#svgnest, #messagewrapper{ width: 60em; }
|
||||
.progress{ width: 61%; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1500px){
|
||||
body { font-size: 16px; }
|
||||
|
||||
#svgnest, #messagewrapper{ width: 50em; }
|
||||
/* replaces old 5em top margin */
|
||||
#svgnest{ margin-top: clamp(0.75rem, 2vh, 1.5rem); }
|
||||
|
||||
#svgnest .logo{ width: 25%; }
|
||||
#controls{ margin-top: 0.75em; }
|
||||
|
||||
#splash .logo{ width: 60%; margin: 0 20%; }
|
||||
#splash h1.title{ margin: 0; font-size: 2em; }
|
||||
#splash .subscript{ font-size: 1em; }
|
||||
|
||||
h1.label{ font-size: 3em; }
|
||||
.progress{ width: 75%; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1300px){
|
||||
body { font-size: 14px; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 790px){
|
||||
#splash{ width: 100%; }
|
||||
#splash .logo{ width: 40%; margin-left: 30%; float: left; }
|
||||
#splash h1.title{ margin: 0; font-size: 2em; }
|
||||
#splash .subscript{ font-size: 1em; }
|
||||
body { font-size: 18px; }
|
||||
|
||||
#splash .nav{ width: 60%; margin-left: 20%; margin-top: 2em; }
|
||||
#splash .nav li{ float: none; display: block; margin-top: 1em; }
|
||||
|
||||
#faq{ padding: 3em; }
|
||||
}
|
||||
|
||||
/* ===== MakeArmy splash nav & buttons — one-row, mono font, less rounded ===== */
|
||||
|
||||
/* use Hack sitewide */
|
||||
html, body {
|
||||
font-family: "Hack", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
/* kill the old float hack and center as a single flex row */
|
||||
#splash .nav {
|
||||
/* override old: float:left; width:150%; margin: 4em 0 0 -20%; */
|
||||
float: none;
|
||||
width: auto;
|
||||
margin: 3rem auto 0 auto;
|
||||
padding: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
/* keep them on one line on wide screens */
|
||||
flex-wrap: nowrap;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
/* list items no longer float */
|
||||
#splash .nav li {
|
||||
list-style: none;
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* button shape: slimmer, less rounded, mono font keeps line-height crisp */
|
||||
#splash .nav .button {
|
||||
border-radius: 12px; /* was pill; now closer to your other UI */
|
||||
padding: 0.55em 1.2em; /* a bit tighter so all fit in one row */
|
||||
font-size: 0.95em;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap; /* prevent label wrapping */
|
||||
}
|
||||
|
||||
/* keep left padding for icon-capable buttons (no icon on Back is fine) */
|
||||
#splash .nav .button.start { padding-left: 3.7em; }
|
||||
#splash .nav .button.spinner { padding-left: 3.7em; }
|
||||
#splash .nav .button.upload { padding-left: 4em; }
|
||||
#splash .nav .button.download { padding-left: 4em; }
|
||||
#splash .nav .button.code { padding-left: 3.9em; }
|
||||
#splash .nav .button.config { padding-left: 3.9em; }
|
||||
#splash .nav .button.close { padding-left: 3.9em; }
|
||||
|
||||
/* ensure the standalone Back button visually matches height/shape */
|
||||
#splash .nav .button.back {
|
||||
/* no extra left padding (no icon), but same height/roundedness */
|
||||
}
|
||||
|
||||
/* responsive fallback: allow wrapping only on truly narrow screens */
|
||||
@media (max-width: 860px) {
|
||||
#splash .nav {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ===== Splash buttons: sharp corners, no icons, one row ===== */
|
||||
|
||||
/* one-line row stays the same */
|
||||
#splash .nav{
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
flex-wrap:nowrap; gap:14px; /* you can nudge this if you need space */
|
||||
margin:3rem auto 0; padding:0; width:auto; float:none;
|
||||
}
|
||||
|
||||
/* kill legacy floats */
|
||||
#splash .nav li{ list-style:none; float:none; }
|
||||
|
||||
/* sharper buttons + uniform padding */
|
||||
#splash .nav .button{
|
||||
border-radius:6px; /* sharper (not quite square) */
|
||||
padding:0.55em 1.2em; /* same for all buttons */
|
||||
font-size:0.95em;
|
||||
line-height:1.2;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
/* nuke all icon pseudo-elements from the splash row */
|
||||
#splash .nav .button::before{ display:none !important; }
|
||||
|
||||
/* remove the old “extra left padding for icons” */
|
||||
#splash .nav .button.start,
|
||||
#splash .nav .button.spinner,
|
||||
#splash .nav .button.upload,
|
||||
#splash .nav .button.download,
|
||||
#splash .nav .button.code,
|
||||
#splash .nav .button.config,
|
||||
#splash .nav .button.close{
|
||||
padding:0.55em 1.2em;
|
||||
}
|
||||
|
||||
/* responsive: only wrap on narrow screens */
|
||||
@media (max-width: 860px){
|
||||
#splash .nav{ flex-wrap:wrap; row-gap:12px; }
|
||||
}
|
||||
|
||||
/* ===== Powered-by footer on splash ===== */
|
||||
#poweredby{
|
||||
margin: 1.25rem auto 0;
|
||||
text-align: center;
|
||||
font-size: 0.95rem;
|
||||
color: var(--muted);
|
||||
max-width: 72ch;
|
||||
}
|
||||
#poweredby a{
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
#poweredby a:hover{ color: var(--accent-2); }
|
||||
|
||||
|
||||
|
||||
/* Restore icon backgrounds for app controls (non-splash) */
|
||||
.button.start{ background: #1a1a1a url(img/start.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; }
|
||||
.button.spinner{ background: #1a1a1a url(img/spin.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; }
|
||||
.button.upload{ background: #1a1a1a url(img/upload.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; }
|
||||
.button.download{ background: #1a1a1a url(img/download.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; }
|
||||
.button.code{ background: #1a1a1a url(img/code.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; }
|
||||
.button.config{ background: #1a1a1a url(img/settings.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; }
|
||||
.button.close{ background: #1a1a1a url(img/close.svg) no-repeat 1.8em 50%; background-size: 2em 2em; padding-left: 3.9em; }
|
||||
.button.zoomin{ background: #1a1a1a url(img/zoomin.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
.button.zoomout{ background: #1a1a1a url(img/zoomout.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
.button.exit{ background: #1a1a1a url(img/close.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
|
||||
|
||||
|
||||
/* Keep splash narrow; stretch only its nav/footer for centering */
|
||||
#splash{ width:28em; margin:8% auto 0 auto; }
|
||||
#splash .logo{ max-width: 220px; width: 50%; margin: 0 0 0 25%; height:auto; display:block; }
|
||||
#splash .nav, #poweredby{ width:100%; text-align:center; }
|
||||
|
||||
|
||||
|
||||
/* --- Splash page buttons override: text-only, no icons --- */
|
||||
#splash .nav .button {
|
||||
border-radius: 6px;
|
||||
padding: 0.55em 1.2em;
|
||||
font-size: 0.95em;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
|
||||
background-image: none !important;
|
||||
padding-left: 1.2em !important; /* uniform spacing */
|
||||
}
|
||||
|
||||
/* --- FINAL stacking: toolbar above panel; both above SVGs --- */
|
||||
#svgnest { position: relative; }
|
||||
|
||||
/* SVG layers lowest */
|
||||
#select, #bins { position: relative; z-index: 0; }
|
||||
#select svg, #bins svg { position: absolute; z-index: 0; }
|
||||
|
||||
/* Toolbar must beat the panel so the gear/X is clickable */
|
||||
#controls { position: relative; z-index: 1000 !important; }
|
||||
|
||||
/* Panel above drawings but below toolbar */
|
||||
#config { position: absolute; z-index: 900 !important; pointer-events: auto; }
|
||||
|
||||
/* Toast always on top */
|
||||
#messagewrapper { position: fixed; z-index: 99999 !important; }
|
||||
|
||||
|
||||
/* === FINAL STACKING ORDER (toolbar above panel; both above SVGs) === */
|
||||
#svgnest { position: relative; }
|
||||
|
||||
/* SVG canvases lowest */
|
||||
#select, #bins { position: relative; z-index: 0; }
|
||||
#select svg, #bins svg { position: absolute; z-index: 0; }
|
||||
|
||||
/* Toolbar wins over panel so the gear/X can always be clicked */
|
||||
#controls { position: relative; z-index: 1000 !important; }
|
||||
|
||||
/* Panel overlays drawings but stays below toolbar */
|
||||
#config { position: absolute; z-index: 900 !important; pointer-events: auto; }
|
||||
|
||||
/* Toast message on top of everything */
|
||||
#messagewrapper { position: fixed; z-index: 99999 !important; }
|
||||
|
||||
/* Panel should NOT intercept clicks when closed */
|
||||
#config:not(.active) {
|
||||
pointer-events: none; /* let clicks pass through */
|
||||
}
|
||||
|
||||
/* Keep toolbar reliably above the panel when open */
|
||||
#controls { position: relative; z-index: 1000 !important; }
|
||||
#controls .button { position: relative; z-index: 1001; }
|
||||
|
||||
/* Panel above drawings but below toolbar */
|
||||
#config { position: absolute; z-index: 900 !important; }
|
||||
584
public/svgnest/style.css.bak
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
/* =========================================================
|
||||
SVGNest — MakeArmy True-Gray Theme (final teal version)
|
||||
- Neutral gray UI with Teal accents (#20C5B5)
|
||||
- Fixed #svgnest top spacing (removed giant gap)
|
||||
- Restores !important on SVG stroke/fill so uploaded parts display correctly
|
||||
- Accent is consistent across links, buttons, tooltips, selection, progress
|
||||
========================================================= */
|
||||
|
||||
:root{
|
||||
/* Neutral grayscale foundation */
|
||||
--bg: #0e0e0e; /* page background (near-black) */
|
||||
--bg-2: #1a1a1a; /* panels / cards / buttons */
|
||||
--bg-3: #121212; /* bins / work areas */
|
||||
--text: #e0e0e0; /* primary text */
|
||||
--muted: #a0a0a0; /* secondary text */
|
||||
--border: #2a2a2a; /* subtle borders */
|
||||
--shadow: rgba(0,0,0,0.40);
|
||||
|
||||
/* Teal accent */
|
||||
--accent: #20C5B5; /* primary accent */
|
||||
--accent-2: #1aa397; /* darker hover/active */
|
||||
|
||||
/* True-grays (replace any previous blues) */
|
||||
--gray-1: #f0f0f0; /* headings, light text */
|
||||
--gray-2: #cccccc; /* subheadings */
|
||||
--gray-3: #888888; /* lines / subtle emphasis */
|
||||
--gray-4: #555555; /* secondary fills */
|
||||
}
|
||||
|
||||
/* ===== Base ===== */
|
||||
html, body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font: normal 22px/1.4 'LatoLatinWeb', helvetica, arial, verdana, sans-serif;
|
||||
background-color: var(--bg);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
a{
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
transition: color .15s ease;
|
||||
}
|
||||
a:hover{
|
||||
color: var(--accent-2);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1{
|
||||
font-size: 1.5em;
|
||||
font-family: 'LatoLatinWebLight', helvetica, arial, verdana, sans-serif;
|
||||
font-weight: normal;
|
||||
margin: 1.5em 0 0.5em 0;
|
||||
color: var(--gray-1);
|
||||
}
|
||||
h2{
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin: 0 0 0.5em 0;
|
||||
color: var(--gray-2);
|
||||
}
|
||||
h3{
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
margin: 1em 0 0.2em 0;
|
||||
color: var(--gray-2);
|
||||
}
|
||||
|
||||
/* ===== Splash ===== */
|
||||
#splash{
|
||||
width: 28em;
|
||||
margin: 8% auto 0 auto;
|
||||
}
|
||||
#splash .logo{
|
||||
width: 50%;
|
||||
margin: 0 0 0 25%;
|
||||
height: auto;
|
||||
}
|
||||
#splash h1{ color: var(--accent); }
|
||||
#splash h1.title{
|
||||
font-size: 3.5em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.subscript{ font-size: 0.75em; }
|
||||
#splash .subscript{
|
||||
display: block;
|
||||
color: var(--accent);
|
||||
font-size: 1.45em;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* ===== Nav + Buttons ===== */
|
||||
.nav{ margin: 0; padding: 0; }
|
||||
li{ list-style: none; float: left; margin: 0; padding: 0; }
|
||||
|
||||
.button{
|
||||
display: block;
|
||||
margin: 0 0.5em;
|
||||
padding: 0.6em 2.4em;
|
||||
background-color: var(--bg-2);
|
||||
border-radius: 5em;
|
||||
border: 1px solid var(--border);
|
||||
cursor: pointer;
|
||||
color: var(--accent);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.25);
|
||||
transition: color .15s ease, box-shadow .15s ease, border-color .15s ease, background-color .15s ease;
|
||||
}
|
||||
.button a:hover{ text-decoration: none; }
|
||||
|
||||
.button.start{
|
||||
background: var(--bg-2) url(img/start.svg) no-repeat 1.8em 50% / 1.4em 1.4em;
|
||||
padding-left: 3.7em;
|
||||
}
|
||||
.button.spinner{
|
||||
background: var(--bg-2) url(img/spin.svg) no-repeat 1.8em 50% / 1.4em 1.4em;
|
||||
padding-left: 3.7em;
|
||||
}
|
||||
.button.upload{
|
||||
background: var(--bg-2) url(img/upload.svg) no-repeat 2.2em 50% / 1em 1em;
|
||||
padding-left: 4em;
|
||||
}
|
||||
.button.download{
|
||||
background: var(--bg-2) url(img/download.svg) no-repeat 2.2em 50% / 1em 1em;
|
||||
padding-left: 4em;
|
||||
}
|
||||
.button.code{
|
||||
background: var(--bg-2) url(img/code.svg) no-repeat 2em 50% / 1.2em 1.2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.config{
|
||||
background: var(--bg-2) url(img/settings.svg) no-repeat 2em 50% / 1.2em 1.2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.close{
|
||||
background: var(--bg-2) url(img/close.svg) no-repeat 1.8em 50% / 2em 2em;
|
||||
padding-left: 3.9em;
|
||||
}
|
||||
.button.zoomin{ background: var(--bg-2) url(img/zoomin.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
.button.zoomout{ background: var(--bg-2) url(img/zoomout.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
.button.exit{ background: var(--bg-2) url(img/close.svg) no-repeat 50% 50% / 1.5em 1.5em; }
|
||||
|
||||
.button:hover{
|
||||
color: var(--accent-2);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.25);
|
||||
text-decoration: none;
|
||||
}
|
||||
.button:active{
|
||||
background-color: #1f1f1f;
|
||||
border-color: var(--accent-2);
|
||||
box-shadow: inset 0 2px 2px rgba(0,0,0,0.35);
|
||||
}
|
||||
.button.disabled{
|
||||
cursor: default; opacity: 0.5; color: #999;
|
||||
-webkit-filter: saturate(0); filter: saturate(0);
|
||||
}
|
||||
.button.disabled:hover{ box-shadow: none; border-color: var(--border); }
|
||||
.button.disabled:active{ background-color: var(--bg-2); box-shadow: none; }
|
||||
|
||||
#splash .nav{ float: left; width: 150%; margin: 4em 0 0 -20%; }
|
||||
#faq{ display: none; float: left; margin-top: 2em; padding-bottom: 5em; }
|
||||
|
||||
/* ===== SVGNest layout ===== */
|
||||
#svgnest, #messagewrapper{ width: 72em; }
|
||||
|
||||
/* FIXED: smaller, responsive top spacing (replaces 9em) */
|
||||
#svgnest{
|
||||
display: none;
|
||||
margin: clamp(1rem, 3vh, 2.5rem) auto 0 auto;
|
||||
}
|
||||
|
||||
#svgnest .logo, #svgnest .sidebar{ float: left; width: 22%; margin-right: 8%; }
|
||||
#svgnest .sidebar h1{ font-size: 3em; color: var(--text); }
|
||||
#svgnest .sidebar{ clear: both; width: 100%; margin-top: 3em; }
|
||||
|
||||
#svgnest .nav{ float: left; margin: 0 0 0 -0.5em; padding: 0; }
|
||||
#controls{ margin-top: 0.5em; float: left; position: relative; }
|
||||
|
||||
/* ===== Info sidebar ===== */
|
||||
#info, #info_placement{ display: none; }
|
||||
h1.label{
|
||||
font-size: 4em; margin: 0.2em 0 0 0; padding: 0;
|
||||
line-height: 1; font-weight: normal; color: var(--text);
|
||||
}
|
||||
h1.label sup{ font-size: 0.5em; }
|
||||
.column{ margin: 0.5em 4em 2em 0; float: left; }
|
||||
|
||||
/* ===== Progress ===== */
|
||||
.progress{
|
||||
width: 51%;
|
||||
clear: both;
|
||||
height: 1.2em;
|
||||
background-color: var(--bg-2);
|
||||
border: 1px solid var(--accent); /* accent border */
|
||||
border-radius: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
.progress_inner{
|
||||
height: 100%;
|
||||
background-color: var(--accent); /* accent fill */
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
/* ===== Config panel ===== */
|
||||
#config{
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
width: 20em;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 24.5em;
|
||||
background-color: var(--bg-2);
|
||||
border-radius: 0.5em;
|
||||
transition: max-height 0.5s;
|
||||
box-shadow: 0 2px 8px var(--shadow);
|
||||
}
|
||||
#configwrapper{ float: left; padding: 3em 0 1em 2em; }
|
||||
#config.active{ display: block; max-height: 50em; }
|
||||
#configbutton{ position: relative; z-index: 2; width: 3em; padding: 0; height: 2.5em; background-position: 50%; }
|
||||
#zoominbutton, #zoomoutbutton, #exitbutton{ width: 3em; padding: 0; height: 2.5em; background-position: 50%; }
|
||||
#configbutton.close:hover{ box-shadow: none; }
|
||||
#configsave{ margin-left: 7%; }
|
||||
|
||||
#config input, #config h3, #config .tooltip{ margin: 1em 0 0 0; height: 2em; padding: 0; }
|
||||
#config input{
|
||||
float: left; width: 13%; font-size: 1em;
|
||||
border: 1px solid var(--accent);
|
||||
color: var(--text);
|
||||
background: #141414;
|
||||
text-align: center; clear: left; border-radius: 0.4em;
|
||||
transition: border-color .15s ease, background-color .15s ease;
|
||||
}
|
||||
#config input:hover{ background-color: #181818; border-color: var(--accent-2); }
|
||||
#config input.checkbox{ width: 7%; margin-left: 4%; margin-right: 4%; border: 1px solid var(--border); }
|
||||
#config h3{ float: left; width: 65%; margin-left: 5%; padding: 0; font-size: 0.8em; line-height: 3em; color: var(--muted); }
|
||||
#config .tooltip{
|
||||
float: left; max-width: 15%; width: 1.5em; height: 1.5em;
|
||||
font-size: 0.8em; font-weight: bold; background-color: var(--accent);
|
||||
color: #fff; text-align: center; line-height: 1.5; margin-top: 1.8em;
|
||||
cursor: default; border-radius: 3em;
|
||||
}
|
||||
#config .button{ float: left; clear: both; margin-top: 2em; }
|
||||
|
||||
/* ===== SVG areas ===== */
|
||||
#select{ margin-top: 2em; }
|
||||
#select, #bins{ float: left; width: 69%; position: relative; }
|
||||
|
||||
#select svg, #bins svg{
|
||||
width: 100%; height: auto; position: absolute; top: 0;
|
||||
margin: 0; display: block; overflow: visible; pointer-events: none;
|
||||
}
|
||||
|
||||
/* Selection strokes (use accent; override uploaded inline styles) */
|
||||
#select svg *{
|
||||
fill: #fff !important;
|
||||
fill-opacity: 0 !important;
|
||||
stroke: var(--accent) !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
pointer-events: fill !important;
|
||||
}
|
||||
#select svg *.fullRect{
|
||||
fill: #1b1b1b !important;
|
||||
fill-opacity: 1 !important;
|
||||
stroke: #1b1b1b !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
}
|
||||
#select svg *:hover{ stroke: var(--accent-2) !important; cursor: pointer !important; }
|
||||
#select svg *.active{ stroke: var(--accent-2) !important; stroke-width: 3px !important; }
|
||||
#select.disabled svg *, #select.disabled svg *:hover, #select.disabled svg *.active{
|
||||
stroke: #6b6b6b !important; stroke-width: 2px !important; cursor: default !important;
|
||||
}
|
||||
|
||||
/* Bins (neutral grays) */
|
||||
#bins svg{ margin-bottom: 2em; }
|
||||
#bins svg.grid{ float: left; width: 45%; margin-right: 5%; min-width: 20em; }
|
||||
#bins svg *{
|
||||
fill: var(--gray-4) !important;
|
||||
stroke: var(--gray-3) !important;
|
||||
stroke-width: 2px !important;
|
||||
vector-effect: non-scaling-stroke !important;
|
||||
stroke-linejoin: round !important;
|
||||
}
|
||||
#bins svg .bin{ fill: var(--bg-3) !important; stroke: var(--gray-4) !important; }
|
||||
#bins svg .hole{ fill: var(--bg) !important; stroke: var(--gray-3) !important; }
|
||||
|
||||
/* ===== Messages ===== */
|
||||
#messagewrapper{
|
||||
width: 50em; overflow: hidden;
|
||||
background: var(--gray-4) url(img/close.svg) no-repeat 99% 0.5em / 3em 3em;
|
||||
line-height: 4em;
|
||||
position: fixed; left: 50%; margin-left: -25em; bottom: 1em;
|
||||
text-align: center; border-radius: 0.5em; color: #fff;
|
||||
box-shadow: 0 6px 24px var(--shadow);
|
||||
border-left: 4px solid var(--accent); /* subtle accent marker */
|
||||
}
|
||||
#messagewrapper:hover{ background-color: #666; border-left-color: var(--accent-2); }
|
||||
#message{ overflow: hidden; height: 0; }
|
||||
#message.active, #message.error{ height: 4em; cursor: pointer; }
|
||||
#message.error{ color: #ff314e; font-weight: bold; }
|
||||
|
||||
/* ===== Animations (kept intact) ===== */
|
||||
.animated{
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
@-webkit-keyframes bounce{
|
||||
from,20%,53%,80%,to{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
40%,43%{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-30px,0);
|
||||
transform: translate3d(0,-30px,0);
|
||||
}
|
||||
70%{
|
||||
-webkit-animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-15px,0);
|
||||
transform: translate3d(0,-15px,0);
|
||||
}
|
||||
90%{
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
@keyframes bounce{
|
||||
from,20%,53%,80%,to{
|
||||
animation-timing-function: cubic-bezier(0.215,0.610,0.355,1.000);
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
40%,43%{
|
||||
animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-30px,0);
|
||||
transform: translate3d(0,-30px,0);
|
||||
}
|
||||
70%{
|
||||
animation-timing-function: cubic-bezier(0.755,0.050,0.855,0.060);
|
||||
-webkit-transform: translate3d(0,-15px,0);
|
||||
transform: translate3d(0,-15px,0);
|
||||
}
|
||||
90%{
|
||||
-webkit-transform: translate3d(0,-4px,0);
|
||||
transform: translate3d(0,-4px,0);
|
||||
}
|
||||
}
|
||||
.bounce{
|
||||
-webkit-animation-name: bounce;
|
||||
animation-name: bounce;
|
||||
-webkit-transform-origin: center bottom;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
@-webkit-keyframes slideInUp{
|
||||
from{
|
||||
-webkit-transform: translate3d(0,100%,0);
|
||||
transform: translate3d(0,100%,0);
|
||||
visibility: visible;
|
||||
}
|
||||
to{
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
@keyframes slideInUp{
|
||||
from{
|
||||
-webkit-transform: translate3d(0,100%,0);
|
||||
transform: translate3d(0,100%,0);
|
||||
visibility: visible;
|
||||
}
|
||||
to{
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
.slideInUp{
|
||||
-webkit-animation-name: slideInUp;
|
||||
animation-name: slideInUp;
|
||||
}
|
||||
|
||||
/* ===== Responsive ===== */
|
||||
@media only screen and (max-width: 1800px){
|
||||
body { font-size: 20px; }
|
||||
#svgnest, #messagewrapper{ width: 60em; }
|
||||
.progress{ width: 61%; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1500px){
|
||||
body { font-size: 16px; }
|
||||
|
||||
#svgnest, #messagewrapper{ width: 50em; }
|
||||
/* replaces old 5em top margin */
|
||||
#svgnest{ margin-top: clamp(0.75rem, 2vh, 1.5rem); }
|
||||
|
||||
#svgnest .logo{ width: 25%; }
|
||||
#controls{ margin-top: 0.75em; }
|
||||
|
||||
#splash .logo{ width: 60%; margin: 0 20%; }
|
||||
#splash h1.title{ margin: 0; font-size: 2em; }
|
||||
#splash .subscript{ font-size: 1em; }
|
||||
|
||||
h1.label{ font-size: 3em; }
|
||||
.progress{ width: 75%; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1300px){
|
||||
body { font-size: 14px; }
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 790px){
|
||||
#splash{ width: 100%; }
|
||||
#splash .logo{ width: 40%; margin-left: 30%; float: left; }
|
||||
#splash h1.title{ margin: 0; font-size: 2em; }
|
||||
#splash .subscript{ font-size: 1em; }
|
||||
body { font-size: 18px; }
|
||||
|
||||
#splash .nav{ width: 60%; margin-left: 20%; margin-top: 2em; }
|
||||
#splash .nav li{ float: none; display: block; margin-top: 1em; }
|
||||
|
||||
#faq{ padding: 3em; }
|
||||
}
|
||||
|
||||
/* ===== MakeArmy splash nav & buttons — one-row, mono font, less rounded ===== */
|
||||
|
||||
/* use Hack sitewide */
|
||||
html, body {
|
||||
font-family: "Hack", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
|
||||
/* kill the old float hack and center as a single flex row */
|
||||
#splash .nav {
|
||||
/* override old: float:left; width:150%; margin: 4em 0 0 -20%; */
|
||||
float: none;
|
||||
width: auto;
|
||||
margin: 3rem auto 0 auto;
|
||||
padding: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
/* keep them on one line on wide screens */
|
||||
flex-wrap: nowrap;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
/* list items no longer float */
|
||||
#splash .nav li {
|
||||
list-style: none;
|
||||
float: none;
|
||||
}
|
||||
|
||||
/* button shape: slimmer, less rounded, mono font keeps line-height crisp */
|
||||
#splash .nav .button {
|
||||
border-radius: 12px; /* was pill; now closer to your other UI */
|
||||
padding: 0.55em 1.2em; /* a bit tighter so all fit in one row */
|
||||
font-size: 0.95em;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap; /* prevent label wrapping */
|
||||
}
|
||||
|
||||
/* keep left padding for icon-capable buttons (no icon on Back is fine) */
|
||||
#splash .nav .button.start { padding-left: 3.7em; }
|
||||
#splash .nav .button.spinner { padding-left: 3.7em; }
|
||||
#splash .nav .button.upload { padding-left: 4em; }
|
||||
#splash .nav .button.download { padding-left: 4em; }
|
||||
#splash .nav .button.code { padding-left: 3.9em; }
|
||||
#splash .nav .button.config { padding-left: 3.9em; }
|
||||
#splash .nav .button.close { padding-left: 3.9em; }
|
||||
|
||||
/* ensure the standalone Back button visually matches height/shape */
|
||||
#splash .nav .button.back {
|
||||
/* no extra left padding (no icon), but same height/roundedness */
|
||||
}
|
||||
|
||||
/* responsive fallback: allow wrapping only on truly narrow screens */
|
||||
@media (max-width: 860px) {
|
||||
#splash .nav {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ===== Splash buttons: sharp corners, no icons, one row ===== */
|
||||
|
||||
/* one-line row stays the same */
|
||||
#splash .nav{
|
||||
display:flex; align-items:center; justify-content:center;
|
||||
flex-wrap:nowrap; gap:14px; /* you can nudge this if you need space */
|
||||
margin:3rem auto 0; padding:0; width:auto; float:none;
|
||||
}
|
||||
|
||||
/* kill legacy floats */
|
||||
#splash .nav li{ list-style:none; float:none; }
|
||||
|
||||
/* sharper buttons + uniform padding */
|
||||
#splash .nav .button{
|
||||
border-radius:6px; /* sharper (not quite square) */
|
||||
padding:0.55em 1.2em; /* same for all buttons */
|
||||
font-size:0.95em;
|
||||
line-height:1.2;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
/* nuke all icon pseudo-elements from the splash row */
|
||||
#splash .nav .button::before{ display:none !important; }
|
||||
|
||||
/* remove the old “extra left padding for icons” */
|
||||
#splash .nav .button.start,
|
||||
#splash .nav .button.spinner,
|
||||
#splash .nav .button.upload,
|
||||
#splash .nav .button.download,
|
||||
#splash .nav .button.code,
|
||||
#splash .nav .button.config,
|
||||
#splash .nav .button.close{
|
||||
padding:0.55em 1.2em;
|
||||
}
|
||||
|
||||
/* responsive: only wrap on narrow screens */
|
||||
@media (max-width: 860px){
|
||||
#splash .nav{ flex-wrap:wrap; row-gap:12px; }
|
||||
}
|
||||
|
||||
/* ===== Powered-by footer on splash ===== */
|
||||
#poweredby{
|
||||
margin: 1.25rem auto 0;
|
||||
text-align: center;
|
||||
font-size: 0.95rem;
|
||||
color: var(--muted);
|
||||
max-width: 72ch;
|
||||
}
|
||||
#poweredby a{
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
#poweredby a:hover{ color: var(--accent-2); }
|
||||
|
||||
|
||||
|
||||
/* Restore icon backgrounds for app controls (non-splash) */
|
||||
.button.start{ background: #1a1a1a url(img/start.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; }
|
||||
.button.spinner{ background: #1a1a1a url(img/spin.svg) no-repeat 1.8em 50%; background-size: 1.4em 1.4em; padding-left: 3.7em; }
|
||||
.button.upload{ background: #1a1a1a url(img/upload.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; }
|
||||
.button.download{ background: #1a1a1a url(img/download.svg) no-repeat 2.2em 50%; background-size: 1em 1em; padding-left: 4em; }
|
||||
.button.code{ background: #1a1a1a url(img/code.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; }
|
||||
.button.config{ background: #1a1a1a url(img/settings.svg) no-repeat 2em 50%; background-size: 1.2em 1.2em; padding-left: 3.9em; }
|
||||
.button.close{ background: #1a1a1a url(img/close.svg) no-repeat 1.8em 50%; background-size: 2em 2em; padding-left: 3.9em; }
|
||||
.button.zoomin{ background: #1a1a1a url(img/zoomin.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
.button.zoomout{ background: #1a1a1a url(img/zoomout.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
.button.exit{ background: #1a1a1a url(img/close.svg) no-repeat 50% 50%; background-size: 1.5em 1.5em; }
|
||||
|
||||
|
||||
|
||||
/* Keep splash narrow; stretch only its nav/footer for centering */
|
||||
#splash{ width:28em; margin:8% auto 0 auto; }
|
||||
#splash .logo{ max-width: 220px; width: 50%; margin: 0 0 0 25%; height:auto; display:block; }
|
||||
#splash .nav, #poweredby{ width:100%; text-align:center; }
|
||||
|
||||
|
||||
|
||||
/* --- Splash page buttons override: text-only, no icons --- */
|
||||
#splash .nav .button {
|
||||
border-radius: 6px;
|
||||
padding: 0.55em 1.2em;
|
||||
font-size: 0.95em;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
|
||||
background-image: none !important;
|
||||
padding-left: 1.2em !important; /* uniform spacing */
|
||||
}
|
||||
|
||||
988
public/svgnest/svgnest.js
Normal file
|
|
@ -0,0 +1,988 @@
|
|||
/*!
|
||||
* SvgNest
|
||||
* Licensed under the MIT license
|
||||
*/
|
||||
|
||||
(function(root){
|
||||
'use strict';
|
||||
|
||||
root.SvgNest = new SvgNest();
|
||||
|
||||
function SvgNest(){
|
||||
var self = this;
|
||||
|
||||
var svg = null;
|
||||
|
||||
// keep a reference to any style nodes, to maintain color/fill info
|
||||
this.style = null;
|
||||
|
||||
var parts = null;
|
||||
|
||||
var tree = null;
|
||||
|
||||
|
||||
var bin = null;
|
||||
var binPolygon = null;
|
||||
var binBounds = null;
|
||||
var nfpCache = {};
|
||||
var config = {
|
||||
clipperScale: 10000000,
|
||||
curveTolerance: 0.3,
|
||||
spacing: 0,
|
||||
rotations: 4,
|
||||
populationSize: 10,
|
||||
mutationRate: 10,
|
||||
useHoles: false,
|
||||
exploreConcave: false
|
||||
};
|
||||
|
||||
this.working = false;
|
||||
|
||||
var GA = null;
|
||||
var best = null;
|
||||
var workerTimer = null;
|
||||
var progress = 0;
|
||||
|
||||
this.parsesvg = function(svgstring){
|
||||
// reset if in progress
|
||||
this.stop();
|
||||
|
||||
bin = null;
|
||||
binPolygon = null;
|
||||
tree = null;
|
||||
|
||||
// parse svg
|
||||
svg = SvgParser.load(svgstring);
|
||||
|
||||
this.style = SvgParser.getStyle();
|
||||
|
||||
svg = SvgParser.clean();
|
||||
|
||||
tree = this.getParts(svg.childNodes);
|
||||
|
||||
//re-order elements such that deeper elements are on top, so they can be moused over
|
||||
function zorder(paths){
|
||||
// depth-first
|
||||
var length = paths.length;
|
||||
for(var i=0; i<length; i++){
|
||||
if(paths[i].children && paths[i].children.length > 0){
|
||||
zorder(paths[i].children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
this.setbin = function(element){
|
||||
if(!svg){
|
||||
return;
|
||||
}
|
||||
bin = element;
|
||||
}
|
||||
|
||||
this.config = function(c){
|
||||
// clean up inputs
|
||||
|
||||
if(!c){
|
||||
return config;
|
||||
}
|
||||
|
||||
if(c.curveTolerance && !GeometryUtil.almostEqual(parseFloat(c.curveTolerance), 0)){
|
||||
config.curveTolerance = parseFloat(c.curveTolerance);
|
||||
}
|
||||
|
||||
if('spacing' in c){
|
||||
config.spacing = parseFloat(c.spacing);
|
||||
}
|
||||
|
||||
if(c.rotations && parseInt(c.rotations) > 0){
|
||||
config.rotations = parseInt(c.rotations);
|
||||
}
|
||||
|
||||
if(c.populationSize && parseInt(c.populationSize) > 2){
|
||||
config.populationSize = parseInt(c.populationSize);
|
||||
}
|
||||
|
||||
if(c.mutationRate && parseInt(c.mutationRate) > 0){
|
||||
config.mutationRate = parseInt(c.mutationRate);
|
||||
}
|
||||
|
||||
if('useHoles' in c){
|
||||
config.useHoles = !!c.useHoles;
|
||||
}
|
||||
|
||||
if('exploreConcave' in c){
|
||||
config.exploreConcave = !!c.exploreConcave;
|
||||
}
|
||||
|
||||
SvgParser.config({ tolerance: config.curveTolerance});
|
||||
|
||||
best = null;
|
||||
nfpCache = {};
|
||||
binPolygon = null;
|
||||
GA = null;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// progressCallback is called when progress is made
|
||||
// displayCallback is called when a new placement has been made
|
||||
this.start = function(progressCallback, displayCallback){
|
||||
if(!svg || !bin){
|
||||
return false;
|
||||
}
|
||||
|
||||
parts = Array.prototype.slice.call(svg.childNodes);
|
||||
var binindex = parts.indexOf(bin);
|
||||
|
||||
if(binindex >= 0){
|
||||
// don't process bin as a part of the tree
|
||||
parts.splice(binindex, 1);
|
||||
}
|
||||
|
||||
// build tree without bin
|
||||
tree = this.getParts(parts.slice(0));
|
||||
|
||||
offsetTree(tree, 0.5*config.spacing, this.polygonOffset.bind(this));
|
||||
|
||||
// offset tree recursively
|
||||
function offsetTree(t, offset, offsetFunction){
|
||||
for(var i=0; i<t.length; i++){
|
||||
var offsetpaths = offsetFunction(t[i], offset);
|
||||
if(offsetpaths.length == 1){
|
||||
// replace array items in place
|
||||
Array.prototype.splice.apply(t[i], [0, t[i].length].concat(offsetpaths[0]));
|
||||
}
|
||||
|
||||
if(t[i].childNodes && t[i].childNodes.length > 0){
|
||||
offsetTree(t[i].childNodes, -offset, offsetFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binPolygon = SvgParser.polygonify(bin);
|
||||
binPolygon = this.cleanPolygon(binPolygon);
|
||||
|
||||
if(!binPolygon || binPolygon.length < 3){
|
||||
return false;
|
||||
}
|
||||
|
||||
binBounds = GeometryUtil.getPolygonBounds(binPolygon);
|
||||
|
||||
if(config.spacing > 0){
|
||||
var offsetBin = this.polygonOffset(binPolygon, -0.5*config.spacing);
|
||||
if(offsetBin.length == 1){
|
||||
// if the offset contains 0 or more than 1 path, something went wrong.
|
||||
binPolygon = offsetBin.pop();
|
||||
}
|
||||
}
|
||||
|
||||
binPolygon.id = -1;
|
||||
|
||||
// put bin on origin
|
||||
var xbinmax = binPolygon[0].x;
|
||||
var xbinmin = binPolygon[0].x;
|
||||
var ybinmax = binPolygon[0].y;
|
||||
var ybinmin = binPolygon[0].y;
|
||||
|
||||
for(var i=1; i<binPolygon.length; i++){
|
||||
if(binPolygon[i].x > xbinmax){
|
||||
xbinmax = binPolygon[i].x;
|
||||
}
|
||||
else if(binPolygon[i].x < xbinmin){
|
||||
xbinmin = binPolygon[i].x;
|
||||
}
|
||||
if(binPolygon[i].y > ybinmax){
|
||||
ybinmax = binPolygon[i].y;
|
||||
}
|
||||
else if(binPolygon[i].y < ybinmin){
|
||||
ybinmin = binPolygon[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<binPolygon.length; i++){
|
||||
binPolygon[i].x -= xbinmin;
|
||||
binPolygon[i].y -= ybinmin;
|
||||
}
|
||||
|
||||
binPolygon.width = xbinmax-xbinmin;
|
||||
binPolygon.height = ybinmax-ybinmin;
|
||||
|
||||
// all paths need to have the same winding direction
|
||||
if(GeometryUtil.polygonArea(binPolygon) > 0){
|
||||
binPolygon.reverse();
|
||||
}
|
||||
|
||||
// remove duplicate endpoints, ensure counterclockwise winding direction
|
||||
for(i=0; i<tree.length; i++){
|
||||
var start = tree[i][0];
|
||||
var end = tree[i][tree[i].length-1];
|
||||
if(start == end || (GeometryUtil.almostEqual(start.x,end.x) && GeometryUtil.almostEqual(start.y,end.y))){
|
||||
tree[i].pop();
|
||||
}
|
||||
|
||||
if(GeometryUtil.polygonArea(tree[i]) > 0){
|
||||
tree[i].reverse();
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.working = false;
|
||||
|
||||
workerTimer = setInterval(function(){
|
||||
if(!self.working){
|
||||
self.launchWorkers.call(self, tree, binPolygon, config, progressCallback, displayCallback);
|
||||
self.working = true;
|
||||
}
|
||||
|
||||
progressCallback(progress);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
this.launchWorkers = function(tree, binPolygon, config, progressCallback, displayCallback){
|
||||
function shuffle(array) {
|
||||
var currentIndex = array.length, temporaryValue, randomIndex ;
|
||||
|
||||
// While there remain elements to shuffle...
|
||||
while (0 !== currentIndex) {
|
||||
|
||||
// Pick a remaining element...
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex -= 1;
|
||||
|
||||
// And swap it with the current element.
|
||||
temporaryValue = array[currentIndex];
|
||||
array[currentIndex] = array[randomIndex];
|
||||
array[randomIndex] = temporaryValue;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
var i,j;
|
||||
|
||||
if(GA === null){
|
||||
// initiate new GA
|
||||
var adam = tree.slice(0);
|
||||
|
||||
// seed with decreasing area
|
||||
adam.sort(function(a, b){
|
||||
return Math.abs(GeometryUtil.polygonArea(b)) - Math.abs(GeometryUtil.polygonArea(a));
|
||||
});
|
||||
|
||||
GA = new GeneticAlgorithm(adam, binPolygon, config);
|
||||
}
|
||||
|
||||
var individual = null;
|
||||
|
||||
// evaluate all members of the population
|
||||
for(i=0; i<GA.population.length; i++){
|
||||
if(!GA.population[i].fitness){
|
||||
individual = GA.population[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(individual === null){
|
||||
// all individuals have been evaluated, start next generation
|
||||
GA.generation();
|
||||
individual = GA.population[1];
|
||||
}
|
||||
|
||||
var placelist = individual.placement;
|
||||
var rotations = individual.rotation;
|
||||
|
||||
var ids = [];
|
||||
for(i=0; i<placelist.length; i++){
|
||||
ids.push(placelist[i].id);
|
||||
placelist[i].rotation = rotations[i];
|
||||
}
|
||||
|
||||
var nfpPairs = [];
|
||||
var key;
|
||||
var newCache = {};
|
||||
|
||||
for(i=0; i<placelist.length; i++){
|
||||
var part = placelist[i];
|
||||
key = {A: binPolygon.id, B: part.id, inside: true, Arotation: 0, Brotation: rotations[i]};
|
||||
if(!nfpCache[JSON.stringify(key)]){
|
||||
nfpPairs.push({A: binPolygon, B: part, key: key});
|
||||
}
|
||||
else{
|
||||
newCache[JSON.stringify(key)] = nfpCache[JSON.stringify(key)]
|
||||
}
|
||||
for(j=0; j<i; j++){
|
||||
var placed = placelist[j];
|
||||
key = {A: placed.id, B: part.id, inside: false, Arotation: rotations[j], Brotation: rotations[i]};
|
||||
if(!nfpCache[JSON.stringify(key)]){
|
||||
nfpPairs.push({A: placed, B: part, key: key});
|
||||
}
|
||||
else{
|
||||
newCache[JSON.stringify(key)] = nfpCache[JSON.stringify(key)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only keep cache for one cycle
|
||||
nfpCache = newCache;
|
||||
|
||||
var worker = new PlacementWorker(binPolygon, placelist.slice(0), ids, rotations, config, nfpCache);
|
||||
|
||||
var p = new Parallel(nfpPairs, {
|
||||
env: {
|
||||
binPolygon: binPolygon,
|
||||
searchEdges: config.exploreConcave,
|
||||
useHoles: config.useHoles
|
||||
},
|
||||
evalPath: 'util/eval.js'
|
||||
});
|
||||
|
||||
p.require('matrix.js');
|
||||
p.require('geometryutil.js');
|
||||
p.require('placementworker.js');
|
||||
p.require('clipper.js');
|
||||
|
||||
var self = this;
|
||||
var spawncount = 0;
|
||||
p._spawnMapWorker = function (i, cb, done, env, wrk){
|
||||
// hijack the worker call to check progress
|
||||
progress = spawncount++/nfpPairs.length;
|
||||
return Parallel.prototype._spawnMapWorker.call(p, i, cb, done, env, wrk);
|
||||
}
|
||||
|
||||
p.map(function(pair){
|
||||
if(!pair || pair.length == 0){
|
||||
return null;
|
||||
}
|
||||
var searchEdges = global.env.searchEdges;
|
||||
var useHoles = global.env.useHoles;
|
||||
|
||||
var A = rotatePolygon(pair.A, pair.key.Arotation);
|
||||
var B = rotatePolygon(pair.B, pair.key.Brotation);
|
||||
|
||||
var nfp;
|
||||
|
||||
if(pair.key.inside){
|
||||
if(GeometryUtil.isRectangle(A, 0.001)){
|
||||
nfp = GeometryUtil.noFitPolygonRectangle(A,B);
|
||||
}
|
||||
else{
|
||||
nfp = GeometryUtil.noFitPolygon(A,B,true,searchEdges);
|
||||
}
|
||||
|
||||
// ensure all interior NFPs have the same winding direction
|
||||
if(nfp && nfp.length > 0){
|
||||
for(var i=0; i<nfp.length; i++){
|
||||
if(GeometryUtil.polygonArea(nfp[i]) > 0){
|
||||
nfp[i].reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
// warning on null inner NFP
|
||||
// this is not an error, as the part may simply be larger than the bin or otherwise unplaceable due to geometry
|
||||
log('NFP Warning: ', pair.key);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(searchEdges){
|
||||
nfp = GeometryUtil.noFitPolygon(A,B,false,searchEdges);
|
||||
}
|
||||
else{
|
||||
nfp = minkowskiDifference(A,B);
|
||||
}
|
||||
// sanity check
|
||||
if(!nfp || nfp.length == 0){
|
||||
log('NFP Error: ', pair.key);
|
||||
log('A: ',JSON.stringify(A));
|
||||
log('B: ',JSON.stringify(B));
|
||||
return null;
|
||||
}
|
||||
|
||||
for(var i=0; i<nfp.length; i++){
|
||||
if(!searchEdges || i==0){ // if searchedges is active, only the first NFP is guaranteed to pass sanity check
|
||||
if(Math.abs(GeometryUtil.polygonArea(nfp[i])) < Math.abs(GeometryUtil.polygonArea(A))){
|
||||
log('NFP Area Error: ', Math.abs(GeometryUtil.polygonArea(nfp[i])), pair.key);
|
||||
log('NFP:', JSON.stringify(nfp[i]));
|
||||
log('A: ',JSON.stringify(A));
|
||||
log('B: ',JSON.stringify(B));
|
||||
nfp.splice(i,1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nfp.length == 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
// for outer NFPs, the first is guaranteed to be the largest. Any subsequent NFPs that lie inside the first are holes
|
||||
for(var i=0; i<nfp.length; i++){
|
||||
if(GeometryUtil.polygonArea(nfp[i]) > 0){
|
||||
nfp[i].reverse();
|
||||
}
|
||||
|
||||
if(i > 0){
|
||||
if(GeometryUtil.pointInPolygon(nfp[i][0], nfp[0])){
|
||||
if(GeometryUtil.polygonArea(nfp[i]) < 0){
|
||||
nfp[i].reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate nfps for children (holes of parts) if any exist
|
||||
if(useHoles && A.childNodes && A.childNodes.length > 0){
|
||||
var Bbounds = GeometryUtil.getPolygonBounds(B);
|
||||
|
||||
for(var i=0; i<A.childNodes.length; i++){
|
||||
var Abounds = GeometryUtil.getPolygonBounds(A.childNodes[i]);
|
||||
|
||||
// no need to find nfp if B's bounding box is too big
|
||||
if(Abounds.width > Bbounds.width && Abounds.height > Bbounds.height){
|
||||
|
||||
var cnfp = GeometryUtil.noFitPolygon(A.childNodes[i],B,true,searchEdges);
|
||||
// ensure all interior NFPs have the same winding direction
|
||||
if(cnfp && cnfp.length > 0){
|
||||
for(var j=0; j<cnfp.length; j++){
|
||||
if(GeometryUtil.polygonArea(cnfp[j]) < 0){
|
||||
cnfp[j].reverse();
|
||||
}
|
||||
nfp.push(cnfp[j]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function log(){
|
||||
if(typeof console !== "undefined") {
|
||||
console.log.apply(console,arguments);
|
||||
}
|
||||
}
|
||||
|
||||
function toClipperCoordinates(polygon){
|
||||
var clone = [];
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
clone.push({
|
||||
X: polygon[i].x,
|
||||
Y: polygon[i].y
|
||||
});
|
||||
}
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
function toNestCoordinates(polygon, scale){
|
||||
var clone = [];
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
clone.push({
|
||||
x: polygon[i].X/scale,
|
||||
y: polygon[i].Y/scale
|
||||
});
|
||||
}
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
function minkowskiDifference(A, B){
|
||||
var Ac = toClipperCoordinates(A);
|
||||
ClipperLib.JS.ScaleUpPath(Ac, 10000000);
|
||||
var Bc = toClipperCoordinates(B);
|
||||
ClipperLib.JS.ScaleUpPath(Bc, 10000000);
|
||||
for(var i=0; i<Bc.length; i++){
|
||||
Bc[i].X *= -1;
|
||||
Bc[i].Y *= -1;
|
||||
}
|
||||
var solution = ClipperLib.Clipper.MinkowskiSum(Ac, Bc, true);
|
||||
var clipperNfp;
|
||||
|
||||
var largestArea = null;
|
||||
for(i=0; i<solution.length; i++){
|
||||
var n = toNestCoordinates(solution[i], 10000000);
|
||||
var sarea = GeometryUtil.polygonArea(n);
|
||||
if(largestArea === null || largestArea > sarea){
|
||||
clipperNfp = n;
|
||||
largestArea = sarea;
|
||||
}
|
||||
}
|
||||
|
||||
for(var i=0; i<clipperNfp.length; i++){
|
||||
clipperNfp[i].x += B[0].x;
|
||||
clipperNfp[i].y += B[0].y;
|
||||
}
|
||||
|
||||
return [clipperNfp];
|
||||
}
|
||||
|
||||
return {key: pair.key, value: nfp};
|
||||
}).then(function(generatedNfp){
|
||||
if(generatedNfp){
|
||||
for(var i=0; i<generatedNfp.length; i++){
|
||||
var Nfp = generatedNfp[i];
|
||||
|
||||
if(Nfp){
|
||||
// a null nfp means the nfp could not be generated, either because the parts simply don't fit or an error in the nfp algo
|
||||
var key = JSON.stringify(Nfp.key);
|
||||
nfpCache[key] = Nfp.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.nfpCache = nfpCache;
|
||||
|
||||
// can't use .spawn because our data is an array
|
||||
var p2 = new Parallel([placelist.slice(0)], {
|
||||
env: {
|
||||
self: worker
|
||||
},
|
||||
evalPath: 'util/eval.js'
|
||||
});
|
||||
|
||||
p2.require('json.js');
|
||||
p2.require('clipper.js');
|
||||
p2.require('matrix.js');
|
||||
p2.require('geometryutil.js');
|
||||
p2.require('placementworker.js');
|
||||
|
||||
p2.map(worker.placePaths).then(function(placements){
|
||||
if(!placements || placements.length == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
individual.fitness = placements[0].fitness;
|
||||
var bestresult = placements[0];
|
||||
|
||||
for(var i=1; i<placements.length; i++){
|
||||
if(placements[i].fitness < bestresult.fitness){
|
||||
bestresult = placements[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(!best || bestresult.fitness < best.fitness){
|
||||
best = bestresult;
|
||||
|
||||
var placedArea = 0;
|
||||
var totalArea = 0;
|
||||
var numParts = placelist.length;
|
||||
var numPlacedParts = 0;
|
||||
|
||||
for(i=0; i<best.placements.length; i++){
|
||||
totalArea += Math.abs(GeometryUtil.polygonArea(binPolygon));
|
||||
for(var j=0; j<best.placements[i].length; j++){
|
||||
placedArea += Math.abs(GeometryUtil.polygonArea(tree[best.placements[i][j].id]));
|
||||
numPlacedParts++;
|
||||
}
|
||||
}
|
||||
displayCallback(self.applyPlacement(best.placements), placedArea/totalArea, numPlacedParts, numParts);
|
||||
}
|
||||
else{
|
||||
displayCallback();
|
||||
}
|
||||
self.working = false;
|
||||
}, function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
}, function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
// assuming no intersections, return a tree where odd leaves are parts and even ones are holes
|
||||
// might be easier to use the DOM, but paths can't have paths as children. So we'll just make our own tree.
|
||||
this.getParts = function(paths){
|
||||
|
||||
var i, j;
|
||||
var polygons = [];
|
||||
|
||||
var numChildren = paths.length;
|
||||
for(i=0; i<numChildren; i++){
|
||||
var poly = SvgParser.polygonify(paths[i]);
|
||||
poly = this.cleanPolygon(poly);
|
||||
|
||||
// todo: warn user if poly could not be processed and is excluded from the nest
|
||||
if(poly && poly.length > 2 && Math.abs(GeometryUtil.polygonArea(poly)) > config.curveTolerance*config.curveTolerance){
|
||||
poly.source = i;
|
||||
polygons.push(poly);
|
||||
}
|
||||
}
|
||||
|
||||
// turn the list into a tree
|
||||
toTree(polygons);
|
||||
|
||||
function toTree(list, idstart){
|
||||
var parents = [];
|
||||
var i,j;
|
||||
|
||||
// assign a unique id to each leaf
|
||||
var id = idstart || 0;
|
||||
|
||||
for(i=0; i<list.length; i++){
|
||||
var p = list[i];
|
||||
|
||||
var ischild = false;
|
||||
for(j=0; j<list.length; j++){
|
||||
if(j==i){
|
||||
continue;
|
||||
}
|
||||
if(GeometryUtil.pointInPolygon(p[0], list[j]) === true){
|
||||
if(!list[j].children){
|
||||
list[j].children = [];
|
||||
}
|
||||
list[j].children.push(p);
|
||||
p.parent = list[j];
|
||||
ischild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!ischild){
|
||||
parents.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<list.length; i++){
|
||||
if(parents.indexOf(list[i]) < 0){
|
||||
list.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<parents.length; i++){
|
||||
parents[i].id = id;
|
||||
id++;
|
||||
}
|
||||
|
||||
for(i=0; i<parents.length; i++){
|
||||
if(parents[i].children){
|
||||
id = toTree(parents[i].children, id);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
};
|
||||
|
||||
return polygons;
|
||||
};
|
||||
|
||||
// use the clipper library to return an offset to the given polygon. Positive offset expands the polygon, negative contracts
|
||||
// note that this returns an array of polygons
|
||||
this.polygonOffset = function(polygon, offset){
|
||||
if(!offset || offset == 0 || GeometryUtil.almostEqual(offset, 0)){
|
||||
return polygon;
|
||||
}
|
||||
|
||||
var p = this.svgToClipper(polygon);
|
||||
|
||||
var miterLimit = 2;
|
||||
var co = new ClipperLib.ClipperOffset(miterLimit, config.curveTolerance*config.clipperScale);
|
||||
co.AddPath(p, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
|
||||
|
||||
var newpaths = new ClipperLib.Paths();
|
||||
co.Execute(newpaths, offset*config.clipperScale);
|
||||
|
||||
var result = [];
|
||||
for(var i=0; i<newpaths.length; i++){
|
||||
result.push(this.clipperToSvg(newpaths[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// returns a less complex polygon that satisfies the curve tolerance
|
||||
this.cleanPolygon = function(polygon){
|
||||
var p = this.svgToClipper(polygon);
|
||||
// remove self-intersections and find the biggest polygon that's left
|
||||
var simple = ClipperLib.Clipper.SimplifyPolygon(p, ClipperLib.PolyFillType.pftNonZero);
|
||||
|
||||
if(!simple || simple.length == 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
var biggest = simple[0];
|
||||
var biggestarea = Math.abs(ClipperLib.Clipper.Area(biggest));
|
||||
for(var i=1; i<simple.length; i++){
|
||||
var area = Math.abs(ClipperLib.Clipper.Area(simple[i]));
|
||||
if(area > biggestarea){
|
||||
biggest = simple[i];
|
||||
biggestarea = area;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up singularities, coincident points and edges
|
||||
var clean = ClipperLib.Clipper.CleanPolygon(biggest, config.curveTolerance*config.clipperScale);
|
||||
|
||||
if(!clean || clean.length == 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.clipperToSvg(clean);
|
||||
}
|
||||
|
||||
// converts a polygon from normal float coordinates to integer coordinates used by clipper, as well as x/y -> X/Y
|
||||
this.svgToClipper = function(polygon){
|
||||
var clip = [];
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
clip.push({X: polygon[i].x, Y: polygon[i].y});
|
||||
}
|
||||
|
||||
ClipperLib.JS.ScaleUpPath(clip, config.clipperScale);
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
this.clipperToSvg = function(polygon){
|
||||
var normal = [];
|
||||
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
normal.push({x: polygon[i].X/config.clipperScale, y: polygon[i].Y/config.clipperScale});
|
||||
}
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
// returns an array of SVG elements that represent the placement, for export or rendering
|
||||
this.applyPlacement = function(placement){
|
||||
var i, j, k;
|
||||
var clone = [];
|
||||
for(i=0; i<parts.length; i++){
|
||||
clone.push(parts[i].cloneNode(false));
|
||||
}
|
||||
|
||||
var svglist = [];
|
||||
|
||||
for(i=0; i<placement.length; i++){
|
||||
var newsvg = svg.cloneNode(false);
|
||||
newsvg.setAttribute('viewBox', '0 0 '+binBounds.width+' '+binBounds.height);
|
||||
newsvg.setAttribute('width',binBounds.width + 'px');
|
||||
newsvg.setAttribute('height',binBounds.height + 'px');
|
||||
var binclone = bin.cloneNode(false);
|
||||
|
||||
binclone.setAttribute('class','bin');
|
||||
binclone.setAttribute('transform','translate('+(-binBounds.x)+' '+(-binBounds.y)+')');
|
||||
newsvg.appendChild(binclone);
|
||||
|
||||
for(j=0; j<placement[i].length; j++){
|
||||
var p = placement[i][j];
|
||||
var part = tree[p.id];
|
||||
|
||||
// the original path could have transforms and stuff on it, so apply our transforms on a group
|
||||
var partgroup = document.createElementNS(svg.namespaceURI, 'g');
|
||||
partgroup.setAttribute('transform','translate('+p.x+' '+p.y+') rotate('+p.rotation+')');
|
||||
partgroup.appendChild(clone[part.source]);
|
||||
|
||||
if(part.children && part.children.length > 0){
|
||||
var flattened = _flattenTree(part.children, true);
|
||||
for(k=0; k<flattened.length; k++){
|
||||
|
||||
var c = clone[flattened[k].source];
|
||||
// add class to indicate hole
|
||||
if(flattened[k].hole && (!c.getAttribute('class') || c.getAttribute('class').indexOf('hole') < 0)){
|
||||
c.setAttribute('class',c.getAttribute('class')+' hole');
|
||||
}
|
||||
partgroup.appendChild(c);
|
||||
}
|
||||
}
|
||||
|
||||
newsvg.appendChild(partgroup);
|
||||
}
|
||||
|
||||
svglist.push(newsvg);
|
||||
}
|
||||
|
||||
// flatten the given tree into a list
|
||||
function _flattenTree(t, hole){
|
||||
var flat = [];
|
||||
for(var i=0; i<t.length; i++){
|
||||
flat.push(t[i]);
|
||||
t[i].hole = hole;
|
||||
if(t[i].children && t[i].children.length > 0){
|
||||
flat = flat.concat(_flattenTree(t[i].children, !hole));
|
||||
}
|
||||
}
|
||||
|
||||
return flat;
|
||||
}
|
||||
|
||||
return svglist;
|
||||
}
|
||||
|
||||
this.stop = function(){
|
||||
this.working = false;
|
||||
if(workerTimer){
|
||||
clearInterval(workerTimer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function GeneticAlgorithm(adam, bin, config){
|
||||
|
||||
this.config = config || { populationSize: 10, mutationRate: 10, rotations: 4 };
|
||||
this.binBounds = GeometryUtil.getPolygonBounds(bin);
|
||||
|
||||
// population is an array of individuals. Each individual is a object representing the order of insertion and the angle each part is rotated
|
||||
var angles = [];
|
||||
for(var i=0; i<adam.length; i++){
|
||||
angles.push(this.randomAngle(adam[i]));
|
||||
}
|
||||
|
||||
this.population = [{placement: adam, rotation: angles}];
|
||||
|
||||
while(this.population.length < config.populationSize){
|
||||
var mutant = this.mutate(this.population[0]);
|
||||
this.population.push(mutant);
|
||||
}
|
||||
}
|
||||
|
||||
// returns a random angle of insertion
|
||||
GeneticAlgorithm.prototype.randomAngle = function(part){
|
||||
|
||||
var angleList = [];
|
||||
for(var i=0; i<Math.max(this.config.rotations,1); i++){
|
||||
angleList.push(i*(360/this.config.rotations));
|
||||
}
|
||||
|
||||
function shuffleArray(array) {
|
||||
for (var i = array.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
angleList = shuffleArray(angleList);
|
||||
|
||||
for(i=0; i<angleList.length; i++){
|
||||
var rotatedPart = GeometryUtil.rotatePolygon(part, angleList[i]);
|
||||
|
||||
// don't use obviously bad angles where the part doesn't fit in the bin
|
||||
if(rotatedPart.width < this.binBounds.width && rotatedPart.height < this.binBounds.height){
|
||||
return angleList[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns a mutated individual with the given mutation rate
|
||||
GeneticAlgorithm.prototype.mutate = function(individual){
|
||||
var clone = {placement: individual.placement.slice(0), rotation: individual.rotation.slice(0)};
|
||||
for(var i=0; i<clone.placement.length; i++){
|
||||
var rand = Math.random();
|
||||
if(rand < 0.01*this.config.mutationRate){
|
||||
// swap current part with next part
|
||||
var j = i+1;
|
||||
|
||||
if(j < clone.placement.length){
|
||||
var temp = clone.placement[i];
|
||||
clone.placement[i] = clone.placement[j];
|
||||
clone.placement[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
rand = Math.random();
|
||||
if(rand < 0.01*this.config.mutationRate){
|
||||
clone.rotation[i] = this.randomAngle(clone.placement[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
// single point crossover
|
||||
GeneticAlgorithm.prototype.mate = function(male, female){
|
||||
var cutpoint = Math.round(Math.min(Math.max(Math.random(), 0.1), 0.9)*(male.placement.length-1));
|
||||
|
||||
var gene1 = male.placement.slice(0,cutpoint);
|
||||
var rot1 = male.rotation.slice(0,cutpoint);
|
||||
|
||||
var gene2 = female.placement.slice(0,cutpoint);
|
||||
var rot2 = female.rotation.slice(0,cutpoint);
|
||||
|
||||
var i;
|
||||
|
||||
for(i=0; i<female.placement.length; i++){
|
||||
if(!contains(gene1, female.placement[i].id)){
|
||||
gene1.push(female.placement[i]);
|
||||
rot1.push(female.rotation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<male.placement.length; i++){
|
||||
if(!contains(gene2, male.placement[i].id)){
|
||||
gene2.push(male.placement[i]);
|
||||
rot2.push(male.rotation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function contains(gene, id){
|
||||
for(var i=0; i<gene.length; i++){
|
||||
if(gene[i].id == id){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return [{placement: gene1, rotation: rot1},{placement: gene2, rotation: rot2}];
|
||||
}
|
||||
|
||||
GeneticAlgorithm.prototype.generation = function(){
|
||||
|
||||
// Individuals with higher fitness are more likely to be selected for mating
|
||||
this.population.sort(function(a, b){
|
||||
return a.fitness - b.fitness;
|
||||
});
|
||||
|
||||
// fittest individual is preserved in the new generation (elitism)
|
||||
var newpopulation = [this.population[0]];
|
||||
|
||||
while(newpopulation.length < this.population.length){
|
||||
var male = this.randomWeightedIndividual();
|
||||
var female = this.randomWeightedIndividual(male);
|
||||
|
||||
// each mating produces two children
|
||||
var children = this.mate(male, female);
|
||||
|
||||
// slightly mutate children
|
||||
newpopulation.push(this.mutate(children[0]));
|
||||
|
||||
if(newpopulation.length < this.population.length){
|
||||
newpopulation.push(this.mutate(children[1]));
|
||||
}
|
||||
}
|
||||
|
||||
this.population = newpopulation;
|
||||
}
|
||||
|
||||
// returns a random individual from the population, weighted to the front of the list (lower fitness value is more likely to be selected)
|
||||
GeneticAlgorithm.prototype.randomWeightedIndividual = function(exclude){
|
||||
var pop = this.population.slice(0);
|
||||
|
||||
if(exclude && pop.indexOf(exclude) >= 0){
|
||||
pop.splice(pop.indexOf(exclude),1);
|
||||
}
|
||||
|
||||
var rand = Math.random();
|
||||
|
||||
var lower = 0;
|
||||
var weight = 1/pop.length;
|
||||
var upper = weight;
|
||||
|
||||
for(var i=0; i<pop.length; i++){
|
||||
// if the random number falls between lower and upper bounds, select this individual
|
||||
if(rand > lower && rand < upper){
|
||||
return pop[i];
|
||||
}
|
||||
lower = upper;
|
||||
upper += 2*weight * ((pop.length-i)/pop.length);
|
||||
}
|
||||
|
||||
return pop[0];
|
||||
}
|
||||
|
||||
})(window);
|
||||
793
public/svgnest/svgparser.js
Normal file
|
|
@ -0,0 +1,793 @@
|
|||
/*!
|
||||
* SvgParser
|
||||
* A library to convert an SVG string to parse-able segments for CAD/CAM use
|
||||
* Licensed under the MIT license
|
||||
*/
|
||||
|
||||
(function(root){
|
||||
'use strict';
|
||||
|
||||
function SvgParser(){
|
||||
// the SVG document
|
||||
this.svg;
|
||||
|
||||
// the top level SVG element of the SVG document
|
||||
this.svgRoot;
|
||||
|
||||
this.allowedElements = ['svg','circle','ellipse','path','polygon','polyline','rect', 'line'];
|
||||
|
||||
this.conf = {
|
||||
tolerance: 2, // max bound for bezier->line segment conversion, in native SVG units
|
||||
toleranceSvg: 0.005 // fudge factor for browser inaccuracy in SVG unit handling
|
||||
};
|
||||
}
|
||||
|
||||
SvgParser.prototype.config = function(config){
|
||||
this.conf.tolerance = config.tolerance;
|
||||
}
|
||||
|
||||
SvgParser.prototype.load = function(svgString){
|
||||
|
||||
if(!svgString || typeof svgString !== 'string'){
|
||||
throw Error('invalid SVG string');
|
||||
}
|
||||
|
||||
var parser = new DOMParser();
|
||||
var svg = parser.parseFromString(svgString, "image/svg+xml");
|
||||
|
||||
this.svgRoot = false;
|
||||
|
||||
if(svg){
|
||||
this.svg = svg;
|
||||
|
||||
for(var i=0; i<svg.childNodes.length; i++){
|
||||
// svg document may start with comments or text nodes
|
||||
var child = svg.childNodes[i];
|
||||
if(child.tagName && child.tagName == 'svg'){
|
||||
this.svgRoot = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Failed to parse SVG string");
|
||||
}
|
||||
|
||||
if(!this.svgRoot){
|
||||
throw new Error("SVG has no children");
|
||||
}
|
||||
return this.svgRoot;
|
||||
}
|
||||
|
||||
// use the utility functions in this class to prepare the svg for CAD-CAM/nest related operations
|
||||
SvgParser.prototype.cleanInput = function(){
|
||||
|
||||
// apply any transformations, so that all path positions etc will be in the same coordinate space
|
||||
this.applyTransform(this.svgRoot);
|
||||
|
||||
// remove any g elements and bring all elements to the top level
|
||||
this.flatten(this.svgRoot);
|
||||
|
||||
// remove any non-contour elements like text
|
||||
this.filter(this.allowedElements);
|
||||
|
||||
// split any compound paths into individual path elements
|
||||
this.recurse(this.svgRoot, this.splitPath);
|
||||
|
||||
return this.svgRoot;
|
||||
|
||||
}
|
||||
|
||||
// return style node, if any
|
||||
SvgParser.prototype.getStyle = function(){
|
||||
if(!this.svgRoot){
|
||||
return false;
|
||||
}
|
||||
for(var i=0; i<this.svgRoot.childNodes.length; i++){
|
||||
var el = this.svgRoot.childNodes[i];
|
||||
if(el.tagName == 'style'){
|
||||
return el;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the given path as absolute coords (capital commands)
|
||||
// from http://stackoverflow.com/a/9677915/433888
|
||||
SvgParser.prototype.pathToAbsolute = function(path){
|
||||
if(!path || path.tagName != 'path'){
|
||||
throw Error('invalid path');
|
||||
}
|
||||
|
||||
var seglist = path.pathSegList;
|
||||
var x=0, y=0, x0=0, y0=0, x1=0, y1=0, x2=0, y2=0;
|
||||
|
||||
for(var i=0; i<seglist.numberOfItems; i++){
|
||||
var command = seglist.getItem(i).pathSegTypeAsLetter;
|
||||
var s = seglist.getItem(i);
|
||||
|
||||
if (/[MLHVCSQTA]/.test(command)){
|
||||
if ('x' in s) x=s.x;
|
||||
if ('y' in s) y=s.y;
|
||||
}
|
||||
else{
|
||||
if ('x1' in s) x1=x+s.x1;
|
||||
if ('x2' in s) x2=x+s.x2;
|
||||
if ('y1' in s) y1=y+s.y1;
|
||||
if ('y2' in s) y2=y+s.y2;
|
||||
if ('x' in s) x+=s.x;
|
||||
if ('y' in s) y+=s.y;
|
||||
switch(command){
|
||||
case 'm': seglist.replaceItem(path.createSVGPathSegMovetoAbs(x,y),i); break;
|
||||
case 'l': seglist.replaceItem(path.createSVGPathSegLinetoAbs(x,y),i); break;
|
||||
case 'h': seglist.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x),i); break;
|
||||
case 'v': seglist.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y),i); break;
|
||||
case 'c': seglist.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x,y,x1,y1,x2,y2),i); break;
|
||||
case 's': seglist.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x,y,x2,y2),i); break;
|
||||
case 'q': seglist.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x,y,x1,y1),i); break;
|
||||
case 't': seglist.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x,y),i); break;
|
||||
case 'a': seglist.replaceItem(path.createSVGPathSegArcAbs(x,y,s.r1,s.r2,s.angle,s.largeArcFlag,s.sweepFlag),i); break;
|
||||
case 'z': case 'Z': x=x0; y=y0; break;
|
||||
}
|
||||
}
|
||||
// Record the start of a subpath
|
||||
if (command=='M' || command=='m') x0=x, y0=y;
|
||||
}
|
||||
};
|
||||
|
||||
// takes an SVG transform string and returns corresponding SVGMatrix
|
||||
// from https://github.com/fontello/svgpath
|
||||
SvgParser.prototype.transformParse = function(transformString){
|
||||
var operations = {
|
||||
matrix: true,
|
||||
scale: true,
|
||||
rotate: true,
|
||||
translate: true,
|
||||
skewX: true,
|
||||
skewY: true
|
||||
};
|
||||
|
||||
var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;
|
||||
var PARAMS_SPLIT_RE = /[\s,]+/;
|
||||
|
||||
var matrix = new Matrix();
|
||||
var cmd, params;
|
||||
|
||||
// Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
|
||||
transformString.split(CMD_SPLIT_RE).forEach(function (item) {
|
||||
|
||||
// Skip empty elements
|
||||
if (!item.length) { return; }
|
||||
|
||||
// remember operation
|
||||
if (typeof operations[item] !== 'undefined') {
|
||||
cmd = item;
|
||||
return;
|
||||
}
|
||||
|
||||
// extract params & att operation to matrix
|
||||
params = item.split(PARAMS_SPLIT_RE).map(function (i) {
|
||||
return +i || 0;
|
||||
});
|
||||
|
||||
// If params count is not correct - ignore command
|
||||
switch (cmd) {
|
||||
case 'matrix':
|
||||
if (params.length === 6) {
|
||||
matrix.matrix(params);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'scale':
|
||||
if (params.length === 1) {
|
||||
matrix.scale(params[0], params[0]);
|
||||
} else if (params.length === 2) {
|
||||
matrix.scale(params[0], params[1]);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'rotate':
|
||||
if (params.length === 1) {
|
||||
matrix.rotate(params[0], 0, 0);
|
||||
} else if (params.length === 3) {
|
||||
matrix.rotate(params[0], params[1], params[2]);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'translate':
|
||||
if (params.length === 1) {
|
||||
matrix.translate(params[0], 0);
|
||||
} else if (params.length === 2) {
|
||||
matrix.translate(params[0], params[1]);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'skewX':
|
||||
if (params.length === 1) {
|
||||
matrix.skewX(params[0]);
|
||||
}
|
||||
return;
|
||||
|
||||
case 'skewY':
|
||||
if (params.length === 1) {
|
||||
matrix.skewY(params[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
// recursively apply the transform property to the given element
|
||||
SvgParser.prototype.applyTransform = function(element, globalTransform){
|
||||
|
||||
globalTransform = globalTransform || '';
|
||||
|
||||
var transformString = element.getAttribute('transform') || '';
|
||||
transformString = globalTransform + transformString;
|
||||
|
||||
var transform, scale, rotate;
|
||||
|
||||
if(transformString && transformString.length > 0){
|
||||
var transform = this.transformParse(transformString);
|
||||
}
|
||||
|
||||
if(!transform){
|
||||
transform = new Matrix();
|
||||
}
|
||||
|
||||
var tarray = transform.toArray();
|
||||
|
||||
// decompose affine matrix to rotate, scale components (translate is just the 3rd column)
|
||||
var rotate = Math.atan2(tarray[1], tarray[3])*180/Math.PI;
|
||||
var scale = Math.sqrt(tarray[0]*tarray[0]+tarray[2]*tarray[2]);
|
||||
|
||||
if(element.tagName == 'g' || element.tagName == 'svg' || element.tagName == 'defs' || element.tagName == 'clipPath'){
|
||||
element.removeAttribute('transform');
|
||||
var children = Array.prototype.slice.call(element.childNodes);
|
||||
|
||||
for(var i=0; i<children.length; i++){
|
||||
if(children[i].tagName){ // skip text nodes
|
||||
this.applyTransform(children[i], transformString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(transform && !transform.isIdentity()){
|
||||
const id = element.getAttribute('id')
|
||||
const className = element.getAttribute('class')
|
||||
|
||||
switch(element.tagName){
|
||||
case 'ellipse':
|
||||
// the goal is to remove the transform property, but an ellipse without a transform will have no rotation
|
||||
// for the sake of simplicity, we will replace the ellipse with a path, and apply the transform to that path
|
||||
var path = this.svg.createElementNS(element.namespaceURI, 'path');
|
||||
var move = path.createSVGPathSegMovetoAbs(parseFloat(element.getAttribute('cx'))-parseFloat(element.getAttribute('rx')),element.getAttribute('cy'));
|
||||
var arc1 = path.createSVGPathSegArcAbs(parseFloat(element.getAttribute('cx'))+parseFloat(element.getAttribute('rx')),element.getAttribute('cy'),element.getAttribute('rx'),element.getAttribute('ry'),0,1,0);
|
||||
var arc2 = path.createSVGPathSegArcAbs(parseFloat(element.getAttribute('cx'))-parseFloat(element.getAttribute('rx')),element.getAttribute('cy'),element.getAttribute('rx'),element.getAttribute('ry'),0,1,0);
|
||||
|
||||
path.pathSegList.appendItem(move);
|
||||
path.pathSegList.appendItem(arc1);
|
||||
path.pathSegList.appendItem(arc2);
|
||||
path.pathSegList.appendItem(path.createSVGPathSegClosePath());
|
||||
|
||||
var transformProperty = element.getAttribute('transform');
|
||||
if(transformProperty){
|
||||
path.setAttribute('transform', transformProperty);
|
||||
}
|
||||
|
||||
element.parentElement.replaceChild(path, element);
|
||||
|
||||
element = path;
|
||||
|
||||
case 'path':
|
||||
this.pathToAbsolute(element);
|
||||
var seglist = element.pathSegList;
|
||||
var prevx = 0;
|
||||
var prevy = 0;
|
||||
|
||||
let transformedPath = '';
|
||||
|
||||
for(var i=0; i<seglist.numberOfItems; i++){
|
||||
var s = seglist.getItem(i);
|
||||
var command = s.pathSegTypeAsLetter;
|
||||
|
||||
|
||||
if(command == 'H'){
|
||||
seglist.replaceItem(element.createSVGPathSegLinetoAbs(s.x,prevy),i);
|
||||
s = seglist.getItem(i);
|
||||
}
|
||||
else if(command == 'V'){
|
||||
seglist.replaceItem(element.createSVGPathSegLinetoAbs(prevx,s.y),i);
|
||||
s = seglist.getItem(i);
|
||||
}
|
||||
// currently only works for uniform scale, no skew
|
||||
// todo: fully support arbitrary affine transforms...
|
||||
else if(command == 'A'){
|
||||
seglist.replaceItem(element.createSVGPathSegArcAbs(s.x,s.y,s.r1*scale,s.r2*scale,s.angle+rotate,s.largeArcFlag,s.sweepFlag),i);
|
||||
s = seglist.getItem(i);
|
||||
}
|
||||
|
||||
const transPoints = {};
|
||||
|
||||
if('x' in s && 'y' in s){
|
||||
var transformed = transform.calc(s.x, s.y);
|
||||
prevx = s.x;
|
||||
prevy = s.y;
|
||||
transPoints.x = transformed[0];
|
||||
transPoints.y = transformed[1];
|
||||
}
|
||||
if('x1' in s && 'y1' in s){
|
||||
var transformed = transform.calc(s.x1, s.y1);
|
||||
transPoints.x1 = transformed[0];
|
||||
transPoints.y1 = transformed[1];
|
||||
}
|
||||
if('x2' in s && 'y2' in s){
|
||||
var transformed = transform.calc(s.x2, s.y2);
|
||||
transPoints.x2 = transformed[0];
|
||||
transPoints.y2 = transformed[1];
|
||||
}
|
||||
|
||||
let commandStringTransformed = ``;
|
||||
|
||||
//MLHVCSQTA
|
||||
//H and V are transformed to "L" commands above so we don't need to handle them. All lowercase (relative) are already handled too (converted to absolute)
|
||||
switch(command) {
|
||||
case 'M':
|
||||
commandStringTransformed += `${command} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'L':
|
||||
commandStringTransformed += `${command} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'C':
|
||||
commandStringTransformed += `${command} ${transPoints.x1} ${transPoints.y1} ${transPoints.x2} ${transPoints.y2} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'S':
|
||||
commandStringTransformed += `${command} ${transPoints.x2} ${transPoints.y2} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'Q':
|
||||
commandStringTransformed += `${command} ${transPoints.x1} ${transPoints.y1} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'T':
|
||||
commandStringTransformed += `${command} ${transPoints.x} ${transPoints.y}`;
|
||||
break;
|
||||
case 'A':
|
||||
const largeArcFlag = s.largeArcFlag ? 1 : 0;
|
||||
const sweepFlag = s.sweepFlag ? 1 : 0;
|
||||
commandStringTransformed += `${command} ${s.r1} ${s.r2} ${s.angle} ${largeArcFlag} ${sweepFlag} ${transPoints.x} ${transPoints.y}`
|
||||
break;
|
||||
case 'H':
|
||||
commandStringTransformed += `L ${transPoints.x} ${transPoints.y}`
|
||||
break;
|
||||
case 'V':
|
||||
commandStringTransformed += `L ${transPoints.x} ${transPoints.y}`
|
||||
break;
|
||||
case 'Z':
|
||||
case 'z':
|
||||
commandStringTransformed += command;
|
||||
break;
|
||||
default:
|
||||
console.log('FOUND COMMAND NOT HANDLED BY COMMAND STRING BUILDER', command);
|
||||
break;
|
||||
}
|
||||
|
||||
transformedPath += commandStringTransformed;
|
||||
}
|
||||
|
||||
element.setAttribute('d', transformedPath);
|
||||
element.removeAttribute('transform');
|
||||
break;
|
||||
case 'circle':
|
||||
var transformed = transform.calc(element.getAttribute('cx'), element.getAttribute('cy'));
|
||||
element.setAttribute('cx', transformed[0]);
|
||||
element.setAttribute('cy', transformed[1]);
|
||||
|
||||
// skew not supported
|
||||
element.setAttribute('r', element.getAttribute('r')*scale);
|
||||
break;
|
||||
case 'line':
|
||||
const transformedStartPt = transform.calc(element.getAttribute('x1'), element.getAttribute('y1'));
|
||||
const transformedEndPt = transform.calc(element.getAttribute('x2'), element.getAttribute('y2'));
|
||||
element.setAttribute('x1', transformedStartPt[0].toString());
|
||||
element.setAttribute('y1', transformedStartPt[1].toString());
|
||||
element.setAttribute('x2', transformedEndPt[0].toString());
|
||||
element.setAttribute('y2', transformedEndPt[1].toString());
|
||||
break;
|
||||
case 'rect':
|
||||
// similar to the ellipse, we'll replace rect with polygon
|
||||
var polygon = this.svg.createElementNS(element.namespaceURI, 'polygon');
|
||||
|
||||
var p1 = this.svgRoot.createSVGPoint();
|
||||
var p2 = this.svgRoot.createSVGPoint();
|
||||
var p3 = this.svgRoot.createSVGPoint();
|
||||
var p4 = this.svgRoot.createSVGPoint();
|
||||
|
||||
p1.x = parseFloat(element.getAttribute('x')) || 0;
|
||||
p1.y = parseFloat(element.getAttribute('y')) || 0;
|
||||
|
||||
p2.x = p1.x + parseFloat(element.getAttribute('width'));
|
||||
p2.y = p1.y;
|
||||
|
||||
p3.x = p2.x;
|
||||
p3.y = p1.y + parseFloat(element.getAttribute('height'));
|
||||
|
||||
p4.x = p1.x;
|
||||
p4.y = p3.y;
|
||||
|
||||
polygon.points.appendItem(p1);
|
||||
polygon.points.appendItem(p2);
|
||||
polygon.points.appendItem(p3);
|
||||
polygon.points.appendItem(p4);
|
||||
|
||||
var transformProperty = element.getAttribute('transform');
|
||||
if(transformProperty){
|
||||
polygon.setAttribute('transform', transformProperty);
|
||||
}
|
||||
|
||||
element.parentElement.replaceChild(polygon, element);
|
||||
element = polygon;
|
||||
case 'polygon':
|
||||
case 'polyline':
|
||||
let transformedPoly = ''
|
||||
for(var i=0; i<element.points.numberOfItems; i++){
|
||||
var point = element.points.getItem(i);
|
||||
var transformed = transform.calc(point.x, point.y);
|
||||
const pointPairString = `${transformed[0]},${transformed[1]} `;
|
||||
transformedPoly += pointPairString;
|
||||
}
|
||||
|
||||
element.setAttribute('points', transformedPoly);
|
||||
element.removeAttribute('transform');
|
||||
break;
|
||||
}
|
||||
if(id) {
|
||||
element.setAttribute('id', id);
|
||||
}
|
||||
if(className){
|
||||
element.setAttribute('class', className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bring all child elements to the top level
|
||||
SvgParser.prototype.flatten = function(element){
|
||||
|
||||
for(var i=0; i<element.childNodes.length; i++){
|
||||
this.flatten(element.childNodes[i]);
|
||||
}
|
||||
|
||||
if(element.tagName != 'svg'){
|
||||
while(element.childNodes.length > 0){
|
||||
element.parentElement.appendChild(element.childNodes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove all elements with tag name not in the whitelist
|
||||
// use this to remove <text>, <g> etc that don't represent shapes
|
||||
SvgParser.prototype.filter = function(whitelist, element){
|
||||
if(!whitelist || whitelist.length == 0){
|
||||
throw Error('invalid whitelist');
|
||||
}
|
||||
|
||||
element = element || this.svgRoot;
|
||||
|
||||
for(var i=0; i<element.childNodes.length; i++){
|
||||
this.filter(whitelist, element.childNodes[i]);
|
||||
}
|
||||
|
||||
if(element.childNodes.length == 0 && whitelist.indexOf(element.tagName) < 0){
|
||||
element.parentElement.removeChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
// split a compound path (paths with M, m commands) into an array of paths
|
||||
SvgParser.prototype.splitPath = function(path){
|
||||
if(!path || path.tagName != 'path' || !path.parentElement){
|
||||
return false;
|
||||
}
|
||||
|
||||
var seglist = [];
|
||||
|
||||
// make copy of seglist (appending to new path removes it from the original pathseglist)
|
||||
for(var i=0; i<path.pathSegList.numberOfItems; i++){
|
||||
seglist.push(path.pathSegList.getItem(i));
|
||||
}
|
||||
|
||||
var x=0, y=0, x0=0, y0=0;
|
||||
var paths = [];
|
||||
|
||||
var p;
|
||||
|
||||
var lastM = 0;
|
||||
for(var i=seglist.length-1; i>=0; i--){
|
||||
if(i > 0 && seglist[i].pathSegTypeAsLetter == 'M' || seglist[i].pathSegTypeAsLetter == 'm'){
|
||||
lastM = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lastM == 0){
|
||||
return false; // only 1 M command, no need to split
|
||||
}
|
||||
|
||||
for( i=0; i<seglist.length; i++){
|
||||
var s = seglist[i];
|
||||
var command = s.pathSegTypeAsLetter;
|
||||
|
||||
if(command == 'M' || command == 'm'){
|
||||
p = path.cloneNode();
|
||||
p.setAttribute('d','');
|
||||
paths.push(p);
|
||||
}
|
||||
|
||||
if (/[MLHVCSQTA]/.test(command)){
|
||||
if ('x' in s) x=s.x;
|
||||
if ('y' in s) y=s.y;
|
||||
|
||||
p.pathSegList.appendItem(s);
|
||||
}
|
||||
else{
|
||||
if ('x' in s) x+=s.x;
|
||||
if ('y' in s) y+=s.y;
|
||||
if(command == 'm'){
|
||||
p.pathSegList.appendItem(path.createSVGPathSegMovetoAbs(x,y));
|
||||
}
|
||||
else{
|
||||
if(command == 'Z' || command == 'z'){
|
||||
x = x0;
|
||||
y = y0;
|
||||
}
|
||||
p.pathSegList.appendItem(s);
|
||||
}
|
||||
}
|
||||
// Record the start of a subpath
|
||||
if (command=='M' || command=='m'){
|
||||
x0=x, y0=y;
|
||||
}
|
||||
}
|
||||
|
||||
var addedPaths = [];
|
||||
for(i=0; i<paths.length; i++){
|
||||
// don't add trivial paths from sequential M commands
|
||||
if(paths[i].pathSegList.numberOfItems > 1){
|
||||
path.parentElement.insertBefore(paths[i], path);
|
||||
addedPaths.push(paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
path.remove();
|
||||
|
||||
return addedPaths;
|
||||
}
|
||||
|
||||
// recursively run the given function on the given element
|
||||
SvgParser.prototype.recurse = function(element, func){
|
||||
// only operate on original DOM tree, ignore any children that are added. Avoid infinite loops
|
||||
var children = Array.prototype.slice.call(element.childNodes);
|
||||
for(var i=0; i<children.length; i++){
|
||||
this.recurse(children[i], func);
|
||||
}
|
||||
|
||||
func(element);
|
||||
}
|
||||
|
||||
// return a polygon from the given SVG element in the form of an array of points
|
||||
SvgParser.prototype.polygonify = function(element){
|
||||
var poly = [];
|
||||
var i;
|
||||
|
||||
switch(element.tagName){
|
||||
case 'polygon':
|
||||
case 'polyline':
|
||||
for(i=0; i<element.points.numberOfItems; i++){
|
||||
var point = element.points.getItem(i);
|
||||
poly.push({ x: point.x, y: point.y });
|
||||
}
|
||||
break;
|
||||
case 'rect':
|
||||
var p1 = {};
|
||||
var p2 = {};
|
||||
var p3 = {};
|
||||
var p4 = {};
|
||||
|
||||
p1.x = parseFloat(element.getAttribute('x')) || 0;
|
||||
p1.y = parseFloat(element.getAttribute('y')) || 0;
|
||||
|
||||
p2.x = p1.x + parseFloat(element.getAttribute('width'));
|
||||
p2.y = p1.y;
|
||||
|
||||
p3.x = p2.x;
|
||||
p3.y = p1.y + parseFloat(element.getAttribute('height'));
|
||||
|
||||
p4.x = p1.x;
|
||||
p4.y = p3.y;
|
||||
|
||||
poly.push(p1);
|
||||
poly.push(p2);
|
||||
poly.push(p3);
|
||||
poly.push(p4);
|
||||
break;
|
||||
case 'circle':
|
||||
var radius = parseFloat(element.getAttribute('r'));
|
||||
var cx = parseFloat(element.getAttribute('cx'));
|
||||
var cy = parseFloat(element.getAttribute('cy'));
|
||||
|
||||
// num is the smallest number of segments required to approximate the circle to the given tolerance
|
||||
var num = Math.ceil((2*Math.PI)/Math.acos(1 - (this.conf.tolerance/radius)));
|
||||
|
||||
if(num < 3){
|
||||
num = 3;
|
||||
}
|
||||
|
||||
for(var i=0; i<num; i++){
|
||||
var theta = i * ( (2*Math.PI) / num);
|
||||
var point = {};
|
||||
point.x = radius*Math.cos(theta) + cx;
|
||||
point.y = radius*Math.sin(theta) + cy;
|
||||
|
||||
poly.push(point);
|
||||
}
|
||||
break;
|
||||
case 'ellipse':
|
||||
// same as circle case. There is probably a way to reduce points but for convenience we will just flatten the equivalent circular polygon
|
||||
var rx = parseFloat(element.getAttribute('rx'))
|
||||
var ry = parseFloat(element.getAttribute('ry'));
|
||||
var maxradius = Math.max(rx, ry);
|
||||
|
||||
var cx = parseFloat(element.getAttribute('cx'));
|
||||
var cy = parseFloat(element.getAttribute('cy'));
|
||||
|
||||
var num = Math.ceil((2*Math.PI)/Math.acos(1 - (this.conf.tolerance/maxradius)));
|
||||
|
||||
if(num < 3){
|
||||
num = 3;
|
||||
}
|
||||
|
||||
for(var i=0; i<num; i++){
|
||||
var theta = i * ( (2*Math.PI) / num);
|
||||
var point = {};
|
||||
point.x = rx*Math.cos(theta) + cx;
|
||||
point.y = ry*Math.sin(theta) + cy;
|
||||
|
||||
poly.push(point);
|
||||
}
|
||||
break;
|
||||
case 'path':
|
||||
// we'll assume that splitpath has already been run on this path, and it only has one M/m command
|
||||
var seglist = element.pathSegList;
|
||||
|
||||
var firstCommand = seglist.getItem(0);
|
||||
var lastCommand = seglist.getItem(seglist.numberOfItems-1);
|
||||
|
||||
var x=0, y=0, x0=0, y0=0, x1=0, y1=0, x2=0, y2=0, prevx=0, prevy=0, prevx1=0, prevy1=0, prevx2=0, prevy2=0;
|
||||
|
||||
for(var i=0; i<seglist.numberOfItems; i++){
|
||||
var s = seglist.getItem(i);
|
||||
var command = s.pathSegTypeAsLetter;
|
||||
|
||||
prevx = x;
|
||||
prevy = y;
|
||||
|
||||
prevx1 = x1;
|
||||
prevy1 = y1;
|
||||
|
||||
prevx2 = x2;
|
||||
prevy2 = y2;
|
||||
|
||||
if (/[MLHVCSQTA]/.test(command)){
|
||||
if ('x1' in s) x1=s.x1;
|
||||
if ('x2' in s) x2=s.x2;
|
||||
if ('y1' in s) y1=s.y1;
|
||||
if ('y2' in s) y2=s.y2;
|
||||
if ('x' in s) x=s.x;
|
||||
if ('y' in s) y=s.y;
|
||||
}
|
||||
else{
|
||||
if ('x1' in s) x1=x+s.x1;
|
||||
if ('x2' in s) x2=x+s.x2;
|
||||
if ('y1' in s) y1=y+s.y1;
|
||||
if ('y2' in s) y2=y+s.y2;
|
||||
if ('x' in s) x+=s.x;
|
||||
if ('y' in s) y+=s.y;
|
||||
}
|
||||
switch(command){
|
||||
// linear line types
|
||||
case 'm':
|
||||
case 'M':
|
||||
case 'l':
|
||||
case 'L':
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'v':
|
||||
case 'V':
|
||||
var point = {};
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
poly.push(point);
|
||||
break;
|
||||
// Quadratic Beziers
|
||||
case 't':
|
||||
case 'T':
|
||||
// implicit control point
|
||||
if(i > 0 && /[QqTt]/.test(seglist.getItem(i-1).pathSegTypeAsLetter)){
|
||||
x1 = prevx + (prevx-prevx1);
|
||||
y1 = prevy + (prevy-prevy1);
|
||||
}
|
||||
else{
|
||||
x1 = prevx;
|
||||
y1 = prevy;
|
||||
}
|
||||
case 'q':
|
||||
case 'Q':
|
||||
var pointlist = GeometryUtil.QuadraticBezier.linearize({x: prevx, y: prevy}, {x: x, y: y}, {x: x1, y: y1}, this.conf.tolerance);
|
||||
pointlist.shift(); // firstpoint would already be in the poly
|
||||
for(var j=0; j<pointlist.length; j++){
|
||||
var point = {};
|
||||
point.x = pointlist[j].x;
|
||||
point.y = pointlist[j].y;
|
||||
poly.push(point);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if(i > 0 && /[CcSs]/.test(seglist.getItem(i-1).pathSegTypeAsLetter)){
|
||||
x1 = prevx + (prevx-prevx2);
|
||||
y1 = prevy + (prevy-prevy2);
|
||||
}
|
||||
else{
|
||||
x1 = prevx;
|
||||
y1 = prevy;
|
||||
}
|
||||
case 'c':
|
||||
case 'C':
|
||||
var pointlist = GeometryUtil.CubicBezier.linearize({x: prevx, y: prevy}, {x: x, y: y}, {x: x1, y: y1}, {x: x2, y: y2}, this.conf.tolerance);
|
||||
pointlist.shift(); // firstpoint would already be in the poly
|
||||
for(var j=0; j<pointlist.length; j++){
|
||||
var point = {};
|
||||
point.x = pointlist[j].x;
|
||||
point.y = pointlist[j].y;
|
||||
poly.push(point);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
var pointlist = GeometryUtil.Arc.linearize({x: prevx, y: prevy}, {x: x, y: y}, s.r1, s.r2, s.angle, s.largeArcFlag,s.sweepFlag, this.conf.tolerance);
|
||||
pointlist.shift();
|
||||
|
||||
for(var j=0; j<pointlist.length; j++){
|
||||
var point = {};
|
||||
point.x = pointlist[j].x;
|
||||
point.y = pointlist[j].y;
|
||||
poly.push(point);
|
||||
}
|
||||
break;
|
||||
case 'z': case 'Z': x=x0; y=y0; break;
|
||||
}
|
||||
// Record the start of a subpath
|
||||
if (command=='M' || command=='m') x0=x, y0=y;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// do not include last point if coincident with starting point
|
||||
while(poly.length > 0 && GeometryUtil.almostEqual(poly[0].x,poly[poly.length-1].x, this.conf.toleranceSvg) && GeometryUtil.almostEqual(poly[0].y,poly[poly.length-1].y, this.conf.toleranceSvg)){
|
||||
poly.pop();
|
||||
}
|
||||
|
||||
return poly;
|
||||
};
|
||||
|
||||
// expose public methods
|
||||
var parser = new SvgParser();
|
||||
|
||||
root.SvgParser = {
|
||||
config: parser.config.bind(parser),
|
||||
load: parser.load.bind(parser),
|
||||
getStyle: parser.getStyle.bind(parser),
|
||||
clean: parser.cleanInput.bind(parser),
|
||||
polygonify: parser.polygonify.bind(parser)
|
||||
};
|
||||
|
||||
}(window));
|
||||
244
public/svgnest/util/clipper.js
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
// rev 452
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 6.1.3a *
|
||||
* Date : 22 January 2014 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2014 *
|
||||
* *
|
||||
* License: *
|
||||
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
||||
* http://www.boost.org/LICENSE_1_0.txt *
|
||||
* *
|
||||
* Attributions: *
|
||||
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
|
||||
* "A generic solution to polygon clipping" *
|
||||
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
|
||||
* http://portal.acm.org/citation.cfm?id=129906 *
|
||||
* *
|
||||
* Computer graphics and geometric modeling: implementation and algorithms *
|
||||
* By Max K. Agoston *
|
||||
* Springer; 1 edition (January 4, 2005) *
|
||||
* http://books.google.com/books?q=vatti+clipping+agoston *
|
||||
* *
|
||||
* See also: *
|
||||
* "Polygon Offsetting by Computing Winding Numbers" *
|
||||
* Paper no. DETC2005-85513 pp. 565-575 *
|
||||
* ASME 2005 International Design Engineering Technical Conferences *
|
||||
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
||||
* September 24-28, 2005 , Long Beach, California, USA *
|
||||
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Timo *
|
||||
* Version : 6.1.3.2 *
|
||||
* Date : 1 February 2014 *
|
||||
* *
|
||||
* This is a translation of the C# Clipper library to Javascript. *
|
||||
* Int128 struct of C# is implemented using JSBN of Tom Wu. *
|
||||
* Because Javascript lacks support for 64-bit integers, the space *
|
||||
* is a little more restricted than in C# version. *
|
||||
* *
|
||||
* C# version has support for coordinate space: *
|
||||
* +-4611686018427387903 ( sqrt(2^127 -1)/2 ) *
|
||||
* while Javascript version has support for space: *
|
||||
* +-4503599627370495 ( sqrt(2^106 -1)/2 ) *
|
||||
* *
|
||||
* Tom Wu's JSBN proved to be the fastest big integer library: *
|
||||
* http://jsperf.com/big-integer-library-test *
|
||||
* *
|
||||
* This class can be made simpler when (if ever) 64-bit integer support comes. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Basic JavaScript BN library - subset useful for RSA encryption. *
|
||||
* http://www-cs-students.stanford.edu/~tjw/jsbn/ *
|
||||
* Copyright (c) 2005 Tom Wu *
|
||||
* All Rights Reserved. *
|
||||
* See "LICENSE" for details: *
|
||||
* http://www-cs-students.stanford.edu/~tjw/jsbn/LICENSE *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
(function(){function k(a,b,c){d.biginteger_used=1;null!=a&&("number"==typeof a&&"undefined"==typeof b?this.fromInt(a):"number"==typeof a?this.fromNumber(a,b,c):null==b&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))}function q(){return new k(null)}function Q(a,b,c,e,d,g){for(;0<=--g;){var h=b*this[a++]+c[e]+d;d=Math.floor(h/67108864);c[e++]=h&67108863}return d}function R(a,b,c,e,d,g){var h=b&32767;for(b>>=15;0<=--g;){var l=this[a]&32767,k=this[a++]>>15,n=b*l+k*h,l=h*l+((n&32767)<<
|
||||
15)+c[e]+(d&1073741823);d=(l>>>30)+(n>>>15)+b*k+(d>>>30);c[e++]=l&1073741823}return d}function S(a,b,c,e,d,g){var h=b&16383;for(b>>=14;0<=--g;){var l=this[a]&16383,k=this[a++]>>14,n=b*l+k*h,l=h*l+((n&16383)<<14)+c[e]+d;d=(l>>28)+(n>>14)+b*k;c[e++]=l&268435455}return d}function L(a,b){var c=B[a.charCodeAt(b)];return null==c?-1:c}function v(a){var b=q();b.fromInt(a);return b}function C(a){var b=1,c;0!=(c=a>>>16)&&(a=c,b+=16);0!=(c=a>>8)&&(a=c,b+=8);0!=(c=a>>4)&&(a=c,b+=4);0!=(c=a>>2)&&(a=c,b+=2);0!=
|
||||
a>>1&&(b+=1);return b}function x(a){this.m=a}function y(a){this.m=a;this.mp=a.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<a.DB-15)-1;this.mt2=2*a.t}function T(a,b){return a&b}function I(a,b){return a|b}function M(a,b){return a^b}function N(a,b){return a&~b}function A(){}function O(a){return a}function w(a){this.r2=q();this.q3=q();k.ONE.dlShiftTo(2*a.t,this.r2);this.mu=this.r2.divide(a);this.m=a}var d={},D=!1;"undefined"!==typeof module&&module.exports?(module.exports=d,D=!0):
|
||||
"undefined"!==typeof document?window.ClipperLib=d:self.ClipperLib=d;var r;if(D)p="chrome",r="Netscape";else{var p=navigator.userAgent.toString().toLowerCase();r=navigator.appName}var E,J,F,G,H,P;E=-1!=p.indexOf("chrome")&&-1==p.indexOf("chromium")?1:0;D=-1!=p.indexOf("chromium")?1:0;J=-1!=p.indexOf("safari")&&-1==p.indexOf("chrome")&&-1==p.indexOf("chromium")?1:0;F=-1!=p.indexOf("firefox")?1:0;p.indexOf("firefox/17");p.indexOf("firefox/15");p.indexOf("firefox/3");G=-1!=p.indexOf("opera")?1:0;p.indexOf("msie 10");
|
||||
p.indexOf("msie 9");H=-1!=p.indexOf("msie 8")?1:0;P=-1!=p.indexOf("msie 7")?1:0;p=-1!=p.indexOf("msie ")?1:0;d.biginteger_used=null;"Microsoft Internet Explorer"==r?(k.prototype.am=R,r=30):"Netscape"!=r?(k.prototype.am=Q,r=26):(k.prototype.am=S,r=28);k.prototype.DB=r;k.prototype.DM=(1<<r)-1;k.prototype.DV=1<<r;k.prototype.FV=Math.pow(2,52);k.prototype.F1=52-r;k.prototype.F2=2*r-52;var B=[],u;r=48;for(u=0;9>=u;++u)B[r++]=u;r=97;for(u=10;36>u;++u)B[r++]=u;r=65;for(u=10;36>u;++u)B[r++]=u;x.prototype.convert=
|
||||
function(a){return 0>a.s||0<=a.compareTo(this.m)?a.mod(this.m):a};x.prototype.revert=function(a){return a};x.prototype.reduce=function(a){a.divRemTo(this.m,null,a)};x.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};x.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};y.prototype.convert=function(a){var b=q();a.abs().dlShiftTo(this.m.t,b);b.divRemTo(this.m,null,b);0>a.s&&0<b.compareTo(k.ZERO)&&this.m.subTo(b,b);return b};y.prototype.revert=function(a){var b=q();a.copyTo(b);
|
||||
this.reduce(b);return b};y.prototype.reduce=function(a){for(;a.t<=this.mt2;)a[a.t++]=0;for(var b=0;b<this.m.t;++b){var c=a[b]&32767,e=c*this.mpl+((c*this.mph+(a[b]>>15)*this.mpl&this.um)<<15)&a.DM,c=b+this.m.t;for(a[c]+=this.m.am(0,e,a,b,0,this.m.t);a[c]>=a.DV;)a[c]-=a.DV,a[++c]++}a.clamp();a.drShiftTo(this.m.t,a);0<=a.compareTo(this.m)&&a.subTo(this.m,a)};y.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};y.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};k.prototype.copyTo=
|
||||
function(a){for(var b=this.t-1;0<=b;--b)a[b]=this[b];a.t=this.t;a.s=this.s};k.prototype.fromInt=function(a){this.t=1;this.s=0>a?-1:0;0<a?this[0]=a:-1>a?this[0]=a+this.DV:this.t=0};k.prototype.fromString=function(a,b){var c;if(16==b)c=4;else if(8==b)c=3;else if(256==b)c=8;else if(2==b)c=1;else if(32==b)c=5;else if(4==b)c=2;else{this.fromRadix(a,b);return}this.s=this.t=0;for(var e=a.length,d=!1,g=0;0<=--e;){var h=8==c?a[e]&255:L(a,e);0>h?"-"==a.charAt(e)&&(d=!0):(d=!1,0==g?this[this.t++]=h:g+c>this.DB?
|
||||
(this[this.t-1]|=(h&(1<<this.DB-g)-1)<<g,this[this.t++]=h>>this.DB-g):this[this.t-1]|=h<<g,g+=c,g>=this.DB&&(g-=this.DB))}8==c&&0!=(a[0]&128)&&(this.s=-1,0<g&&(this[this.t-1]|=(1<<this.DB-g)-1<<g));this.clamp();d&&k.ZERO.subTo(this,this)};k.prototype.clamp=function(){for(var a=this.s&this.DM;0<this.t&&this[this.t-1]==a;)--this.t};k.prototype.dlShiftTo=function(a,b){var c;for(c=this.t-1;0<=c;--c)b[c+a]=this[c];for(c=a-1;0<=c;--c)b[c]=0;b.t=this.t+a;b.s=this.s};k.prototype.drShiftTo=function(a,b){for(var c=
|
||||
a;c<this.t;++c)b[c-a]=this[c];b.t=Math.max(this.t-a,0);b.s=this.s};k.prototype.lShiftTo=function(a,b){var c=a%this.DB,e=this.DB-c,d=(1<<e)-1,g=Math.floor(a/this.DB),h=this.s<<c&this.DM,l;for(l=this.t-1;0<=l;--l)b[l+g+1]=this[l]>>e|h,h=(this[l]&d)<<c;for(l=g-1;0<=l;--l)b[l]=0;b[g]=h;b.t=this.t+g+1;b.s=this.s;b.clamp()};k.prototype.rShiftTo=function(a,b){b.s=this.s;var c=Math.floor(a/this.DB);if(c>=this.t)b.t=0;else{var e=a%this.DB,d=this.DB-e,g=(1<<e)-1;b[0]=this[c]>>e;for(var h=c+1;h<this.t;++h)b[h-
|
||||
c-1]|=(this[h]&g)<<d,b[h-c]=this[h]>>e;0<e&&(b[this.t-c-1]|=(this.s&g)<<d);b.t=this.t-c;b.clamp()}};k.prototype.subTo=function(a,b){for(var c=0,e=0,d=Math.min(a.t,this.t);c<d;)e+=this[c]-a[c],b[c++]=e&this.DM,e>>=this.DB;if(a.t<this.t){for(e-=a.s;c<this.t;)e+=this[c],b[c++]=e&this.DM,e>>=this.DB;e+=this.s}else{for(e+=this.s;c<a.t;)e-=a[c],b[c++]=e&this.DM,e>>=this.DB;e-=a.s}b.s=0>e?-1:0;-1>e?b[c++]=this.DV+e:0<e&&(b[c++]=e);b.t=c;b.clamp()};k.prototype.multiplyTo=function(a,b){var c=this.abs(),e=
|
||||
a.abs(),d=c.t;for(b.t=d+e.t;0<=--d;)b[d]=0;for(d=0;d<e.t;++d)b[d+c.t]=c.am(0,e[d],b,d,0,c.t);b.s=0;b.clamp();this.s!=a.s&&k.ZERO.subTo(b,b)};k.prototype.squareTo=function(a){for(var b=this.abs(),c=a.t=2*b.t;0<=--c;)a[c]=0;for(c=0;c<b.t-1;++c){var e=b.am(c,b[c],a,2*c,0,1);(a[c+b.t]+=b.am(c+1,2*b[c],a,2*c+1,e,b.t-c-1))>=b.DV&&(a[c+b.t]-=b.DV,a[c+b.t+1]=1)}0<a.t&&(a[a.t-1]+=b.am(c,b[c],a,2*c,0,1));a.s=0;a.clamp()};k.prototype.divRemTo=function(a,b,c){var e=a.abs();if(!(0>=e.t)){var d=this.abs();if(d.t<
|
||||
e.t)null!=b&&b.fromInt(0),null!=c&&this.copyTo(c);else{null==c&&(c=q());var g=q(),h=this.s;a=a.s;var l=this.DB-C(e[e.t-1]);0<l?(e.lShiftTo(l,g),d.lShiftTo(l,c)):(e.copyTo(g),d.copyTo(c));e=g.t;d=g[e-1];if(0!=d){var z=d*(1<<this.F1)+(1<e?g[e-2]>>this.F2:0),n=this.FV/z,z=(1<<this.F1)/z,U=1<<this.F2,m=c.t,p=m-e,s=null==b?q():b;g.dlShiftTo(p,s);0<=c.compareTo(s)&&(c[c.t++]=1,c.subTo(s,c));k.ONE.dlShiftTo(e,s);for(s.subTo(g,g);g.t<e;)g[g.t++]=0;for(;0<=--p;){var r=c[--m]==d?this.DM:Math.floor(c[m]*n+(c[m-
|
||||
1]+U)*z);if((c[m]+=g.am(0,r,c,p,0,e))<r)for(g.dlShiftTo(p,s),c.subTo(s,c);c[m]<--r;)c.subTo(s,c)}null!=b&&(c.drShiftTo(e,b),h!=a&&k.ZERO.subTo(b,b));c.t=e;c.clamp();0<l&&c.rShiftTo(l,c);0>h&&k.ZERO.subTo(c,c)}}}};k.prototype.invDigit=function(){if(1>this.t)return 0;var a=this[0];if(0==(a&1))return 0;var b=a&3,b=b*(2-(a&15)*b)&15,b=b*(2-(a&255)*b)&255,b=b*(2-((a&65535)*b&65535))&65535,b=b*(2-a*b%this.DV)%this.DV;return 0<b?this.DV-b:-b};k.prototype.isEven=function(){return 0==(0<this.t?this[0]&1:this.s)};
|
||||
k.prototype.exp=function(a,b){if(4294967295<a||1>a)return k.ONE;var c=q(),e=q(),d=b.convert(this),g=C(a)-1;for(d.copyTo(c);0<=--g;)if(b.sqrTo(c,e),0<(a&1<<g))b.mulTo(e,d,c);else var h=c,c=e,e=h;return b.revert(c)};k.prototype.toString=function(a){if(0>this.s)return"-"+this.negate().toString(a);if(16==a)a=4;else if(8==a)a=3;else if(2==a)a=1;else if(32==a)a=5;else if(4==a)a=2;else return this.toRadix(a);var b=(1<<a)-1,c,e=!1,d="",g=this.t,h=this.DB-g*this.DB%a;if(0<g--)for(h<this.DB&&0<(c=this[g]>>
|
||||
h)&&(e=!0,d="0123456789abcdefghijklmnopqrstuvwxyz".charAt(c));0<=g;)h<a?(c=(this[g]&(1<<h)-1)<<a-h,c|=this[--g]>>(h+=this.DB-a)):(c=this[g]>>(h-=a)&b,0>=h&&(h+=this.DB,--g)),0<c&&(e=!0),e&&(d+="0123456789abcdefghijklmnopqrstuvwxyz".charAt(c));return e?d:"0"};k.prototype.negate=function(){var a=q();k.ZERO.subTo(this,a);return a};k.prototype.abs=function(){return 0>this.s?this.negate():this};k.prototype.compareTo=function(a){var b=this.s-a.s;if(0!=b)return b;var c=this.t,b=c-a.t;if(0!=b)return 0>this.s?
|
||||
-b:b;for(;0<=--c;)if(0!=(b=this[c]-a[c]))return b;return 0};k.prototype.bitLength=function(){return 0>=this.t?0:this.DB*(this.t-1)+C(this[this.t-1]^this.s&this.DM)};k.prototype.mod=function(a){var b=q();this.abs().divRemTo(a,null,b);0>this.s&&0<b.compareTo(k.ZERO)&&a.subTo(b,b);return b};k.prototype.modPowInt=function(a,b){var c;c=256>a||b.isEven()?new x(b):new y(b);return this.exp(a,c)};k.ZERO=v(0);k.ONE=v(1);A.prototype.convert=O;A.prototype.revert=O;A.prototype.mulTo=function(a,b,c){a.multiplyTo(b,
|
||||
c)};A.prototype.sqrTo=function(a,b){a.squareTo(b)};w.prototype.convert=function(a){if(0>a.s||a.t>2*this.m.t)return a.mod(this.m);if(0>a.compareTo(this.m))return a;var b=q();a.copyTo(b);this.reduce(b);return b};w.prototype.revert=function(a){return a};w.prototype.reduce=function(a){a.drShiftTo(this.m.t-1,this.r2);a.t>this.m.t+1&&(a.t=this.m.t+1,a.clamp());this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);for(this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);0>a.compareTo(this.r2);)a.dAddOffset(1,
|
||||
this.m.t+1);for(a.subTo(this.r2,a);0<=a.compareTo(this.m);)a.subTo(this.m,a)};w.prototype.mulTo=function(a,b,c){a.multiplyTo(b,c);this.reduce(c)};w.prototype.sqrTo=function(a,b){a.squareTo(b);this.reduce(b)};var t=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,
|
||||
409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],V=67108864/t[t.length-1];k.prototype.chunkSize=function(a){return Math.floor(Math.LN2*this.DB/Math.log(a))};k.prototype.toRadix=function(a){null==
|
||||
a&&(a=10);if(0==this.signum()||2>a||36<a)return"0";var b=this.chunkSize(a),b=Math.pow(a,b),c=v(b),e=q(),d=q(),g="";for(this.divRemTo(c,e,d);0<e.signum();)g=(b+d.intValue()).toString(a).substr(1)+g,e.divRemTo(c,e,d);return d.intValue().toString(a)+g};k.prototype.fromRadix=function(a,b){this.fromInt(0);null==b&&(b=10);for(var c=this.chunkSize(b),e=Math.pow(b,c),d=!1,g=0,h=0,l=0;l<a.length;++l){var z=L(a,l);0>z?"-"==a.charAt(l)&&0==this.signum()&&(d=!0):(h=b*h+z,++g>=c&&(this.dMultiply(e),this.dAddOffset(h,
|
||||
0),h=g=0))}0<g&&(this.dMultiply(Math.pow(b,g)),this.dAddOffset(h,0));d&&k.ZERO.subTo(this,this)};k.prototype.fromNumber=function(a,b,c){if("number"==typeof b)if(2>a)this.fromInt(1);else for(this.fromNumber(a,c),this.testBit(a-1)||this.bitwiseTo(k.ONE.shiftLeft(a-1),I,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(k.ONE.shiftLeft(a-1),this);else{c=[];var e=a&7;c.length=(a>>3)+1;b.nextBytes(c);c[0]=0<e?c[0]&(1<<e)-1:0;this.fromString(c,
|
||||
256)}};k.prototype.bitwiseTo=function(a,b,c){var e,d,g=Math.min(a.t,this.t);for(e=0;e<g;++e)c[e]=b(this[e],a[e]);if(a.t<this.t){d=a.s&this.DM;for(e=g;e<this.t;++e)c[e]=b(this[e],d);c.t=this.t}else{d=this.s&this.DM;for(e=g;e<a.t;++e)c[e]=b(d,a[e]);c.t=a.t}c.s=b(this.s,a.s);c.clamp()};k.prototype.changeBit=function(a,b){var c=k.ONE.shiftLeft(a);this.bitwiseTo(c,b,c);return c};k.prototype.addTo=function(a,b){for(var c=0,e=0,d=Math.min(a.t,this.t);c<d;)e+=this[c]+a[c],b[c++]=e&this.DM,e>>=this.DB;if(a.t<
|
||||
this.t){for(e+=a.s;c<this.t;)e+=this[c],b[c++]=e&this.DM,e>>=this.DB;e+=this.s}else{for(e+=this.s;c<a.t;)e+=a[c],b[c++]=e&this.DM,e>>=this.DB;e+=a.s}b.s=0>e?-1:0;0<e?b[c++]=e:-1>e&&(b[c++]=this.DV+e);b.t=c;b.clamp()};k.prototype.dMultiply=function(a){this[this.t]=this.am(0,a-1,this,0,0,this.t);++this.t;this.clamp()};k.prototype.dAddOffset=function(a,b){if(0!=a){for(;this.t<=b;)this[this.t++]=0;for(this[b]+=a;this[b]>=this.DV;)this[b]-=this.DV,++b>=this.t&&(this[this.t++]=0),++this[b]}};k.prototype.multiplyLowerTo=
|
||||
function(a,b,c){var e=Math.min(this.t+a.t,b);c.s=0;for(c.t=e;0<e;)c[--e]=0;var d;for(d=c.t-this.t;e<d;++e)c[e+this.t]=this.am(0,a[e],c,e,0,this.t);for(d=Math.min(a.t,b);e<d;++e)this.am(0,a[e],c,e,0,b-e);c.clamp()};k.prototype.multiplyUpperTo=function(a,b,c){--b;var e=c.t=this.t+a.t-b;for(c.s=0;0<=--e;)c[e]=0;for(e=Math.max(b-this.t,0);e<a.t;++e)c[this.t+e-b]=this.am(b-e,a[e],c,0,0,this.t+e-b);c.clamp();c.drShiftTo(1,c)};k.prototype.modInt=function(a){if(0>=a)return 0;var b=this.DV%a,c=0>this.s?a-
|
||||
1:0;if(0<this.t)if(0==b)c=this[0]%a;else for(var e=this.t-1;0<=e;--e)c=(b*c+this[e])%a;return c};k.prototype.millerRabin=function(a){var b=this.subtract(k.ONE),c=b.getLowestSetBit();if(0>=c)return!1;var e=b.shiftRight(c);a=a+1>>1;a>t.length&&(a=t.length);for(var d=q(),g=0;g<a;++g){d.fromInt(t[Math.floor(Math.random()*t.length)]);var h=d.modPow(e,this);if(0!=h.compareTo(k.ONE)&&0!=h.compareTo(b)){for(var l=1;l++<c&&0!=h.compareTo(b);)if(h=h.modPowInt(2,this),0==h.compareTo(k.ONE))return!1;if(0!=h.compareTo(b))return!1}}return!0};
|
||||
k.prototype.clone=function(){var a=q();this.copyTo(a);return a};k.prototype.intValue=function(){if(0>this.s){if(1==this.t)return this[0]-this.DV;if(0==this.t)return-1}else{if(1==this.t)return this[0];if(0==this.t)return 0}return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]};k.prototype.byteValue=function(){return 0==this.t?this.s:this[0]<<24>>24};k.prototype.shortValue=function(){return 0==this.t?this.s:this[0]<<16>>16};k.prototype.signum=function(){return 0>this.s?-1:0>=this.t||1==this.t&&0>=this[0]?
|
||||
0:1};k.prototype.toByteArray=function(){var a=this.t,b=[];b[0]=this.s;var c=this.DB-a*this.DB%8,e,d=0;if(0<a--)for(c<this.DB&&(e=this[a]>>c)!=(this.s&this.DM)>>c&&(b[d++]=e|this.s<<this.DB-c);0<=a;)if(8>c?(e=(this[a]&(1<<c)-1)<<8-c,e|=this[--a]>>(c+=this.DB-8)):(e=this[a]>>(c-=8)&255,0>=c&&(c+=this.DB,--a)),0!=(e&128)&&(e|=-256),0==d&&(this.s&128)!=(e&128)&&++d,0<d||e!=this.s)b[d++]=e;return b};k.prototype.equals=function(a){return 0==this.compareTo(a)};k.prototype.min=function(a){return 0>this.compareTo(a)?
|
||||
this:a};k.prototype.max=function(a){return 0<this.compareTo(a)?this:a};k.prototype.and=function(a){var b=q();this.bitwiseTo(a,T,b);return b};k.prototype.or=function(a){var b=q();this.bitwiseTo(a,I,b);return b};k.prototype.xor=function(a){var b=q();this.bitwiseTo(a,M,b);return b};k.prototype.andNot=function(a){var b=q();this.bitwiseTo(a,N,b);return b};k.prototype.not=function(){for(var a=q(),b=0;b<this.t;++b)a[b]=this.DM&~this[b];a.t=this.t;a.s=~this.s;return a};k.prototype.shiftLeft=function(a){var b=
|
||||
q();0>a?this.rShiftTo(-a,b):this.lShiftTo(a,b);return b};k.prototype.shiftRight=function(a){var b=q();0>a?this.lShiftTo(-a,b):this.rShiftTo(a,b);return b};k.prototype.getLowestSetBit=function(){for(var a=0;a<this.t;++a)if(0!=this[a]){var b=a*this.DB;a=this[a];if(0==a)a=-1;else{var c=0;0==(a&65535)&&(a>>=16,c+=16);0==(a&255)&&(a>>=8,c+=8);0==(a&15)&&(a>>=4,c+=4);0==(a&3)&&(a>>=2,c+=2);0==(a&1)&&++c;a=c}return b+a}return 0>this.s?this.t*this.DB:-1};k.prototype.bitCount=function(){for(var a=0,b=this.s&
|
||||
this.DM,c=0;c<this.t;++c){for(var e=this[c]^b,d=0;0!=e;)e&=e-1,++d;a+=d}return a};k.prototype.testBit=function(a){var b=Math.floor(a/this.DB);return b>=this.t?0!=this.s:0!=(this[b]&1<<a%this.DB)};k.prototype.setBit=function(a){return this.changeBit(a,I)};k.prototype.clearBit=function(a){return this.changeBit(a,N)};k.prototype.flipBit=function(a){return this.changeBit(a,M)};k.prototype.add=function(a){var b=q();this.addTo(a,b);return b};k.prototype.subtract=function(a){var b=q();this.subTo(a,b);return b};
|
||||
k.prototype.multiply=function(a){var b=q();this.multiplyTo(a,b);return b};k.prototype.divide=function(a){var b=q();this.divRemTo(a,b,null);return b};k.prototype.remainder=function(a){var b=q();this.divRemTo(a,null,b);return b};k.prototype.divideAndRemainder=function(a){var b=q(),c=q();this.divRemTo(a,b,c);return[b,c]};k.prototype.modPow=function(a,b){var c=a.bitLength(),e,d=v(1),g;if(0>=c)return d;e=18>c?1:48>c?3:144>c?4:768>c?5:6;g=8>c?new x(b):b.isEven()?new w(b):new y(b);var h=[],l=3,k=e-1,n=(1<<
|
||||
e)-1;h[1]=g.convert(this);if(1<e)for(c=q(),g.sqrTo(h[1],c);l<=n;)h[l]=q(),g.mulTo(c,h[l-2],h[l]),l+=2;for(var m=a.t-1,p,r=!0,s=q(),c=C(a[m])-1;0<=m;){c>=k?p=a[m]>>c-k&n:(p=(a[m]&(1<<c+1)-1)<<k-c,0<m&&(p|=a[m-1]>>this.DB+c-k));for(l=e;0==(p&1);)p>>=1,--l;0>(c-=l)&&(c+=this.DB,--m);if(r)h[p].copyTo(d),r=!1;else{for(;1<l;)g.sqrTo(d,s),g.sqrTo(s,d),l-=2;0<l?g.sqrTo(d,s):(l=d,d=s,s=l);g.mulTo(s,h[p],d)}for(;0<=m&&0==(a[m]&1<<c);)g.sqrTo(d,s),l=d,d=s,s=l,0>--c&&(c=this.DB-1,--m)}return g.revert(d)};k.prototype.modInverse=
|
||||
function(a){var b=a.isEven();if(this.isEven()&&b||0==a.signum())return k.ZERO;for(var c=a.clone(),e=this.clone(),d=v(1),g=v(0),h=v(0),l=v(1);0!=c.signum();){for(;c.isEven();)c.rShiftTo(1,c),b?(d.isEven()&&g.isEven()||(d.addTo(this,d),g.subTo(a,g)),d.rShiftTo(1,d)):g.isEven()||g.subTo(a,g),g.rShiftTo(1,g);for(;e.isEven();)e.rShiftTo(1,e),b?(h.isEven()&&l.isEven()||(h.addTo(this,h),l.subTo(a,l)),h.rShiftTo(1,h)):l.isEven()||l.subTo(a,l),l.rShiftTo(1,l);0<=c.compareTo(e)?(c.subTo(e,c),b&&d.subTo(h,d),
|
||||
g.subTo(l,g)):(e.subTo(c,e),b&&h.subTo(d,h),l.subTo(g,l))}if(0!=e.compareTo(k.ONE))return k.ZERO;if(0<=l.compareTo(a))return l.subtract(a);if(0>l.signum())l.addTo(a,l);else return l;return 0>l.signum()?l.add(a):l};k.prototype.pow=function(a){return this.exp(a,new A)};k.prototype.gcd=function(a){var b=0>this.s?this.negate():this.clone();a=0>a.s?a.negate():a.clone();if(0>b.compareTo(a)){var c=b,b=a;a=c}var c=b.getLowestSetBit(),e=a.getLowestSetBit();if(0>e)return b;c<e&&(e=c);0<e&&(b.rShiftTo(e,b),
|
||||
a.rShiftTo(e,a));for(;0<b.signum();)0<(c=b.getLowestSetBit())&&b.rShiftTo(c,b),0<(c=a.getLowestSetBit())&&a.rShiftTo(c,a),0<=b.compareTo(a)?(b.subTo(a,b),b.rShiftTo(1,b)):(a.subTo(b,a),a.rShiftTo(1,a));0<e&&a.lShiftTo(e,a);return a};k.prototype.isProbablePrime=function(a){var b,c=this.abs();if(1==c.t&&c[0]<=t[t.length-1]){for(b=0;b<t.length;++b)if(c[0]==t[b])return!0;return!1}if(c.isEven())return!1;for(b=1;b<t.length;){for(var e=t[b],d=b+1;d<t.length&&e<V;)e*=t[d++];for(e=c.modInt(e);b<d;)if(0==e%
|
||||
t[b++])return!1}return c.millerRabin(a)};k.prototype.square=function(){var a=q();this.squareTo(a);return a};var m=k;m.prototype.IsNegative=function(){return-1==this.compareTo(m.ZERO)?!0:!1};m.op_Equality=function(a,b){return 0==a.compareTo(b)?!0:!1};m.op_Inequality=function(a,b){return 0!=a.compareTo(b)?!0:!1};m.op_GreaterThan=function(a,b){return 0<a.compareTo(b)?!0:!1};m.op_LessThan=function(a,b){return 0>a.compareTo(b)?!0:!1};m.op_Addition=function(a,b){return(new m(a)).add(new m(b))};m.op_Subtraction=
|
||||
function(a,b){return(new m(a)).subtract(new m(b))};m.Int128Mul=function(a,b){return(new m(a)).multiply(new m(b))};m.op_Division=function(a,b){return a.divide(b)};m.prototype.ToDouble=function(){return parseFloat(this.toString())};if("undefined"==typeof K)var K=function(a,b){var c;if("undefined"==typeof Object.getOwnPropertyNames)for(c in b.prototype){if("undefined"==typeof a.prototype[c]||a.prototype[c]==Object.prototype[c])a.prototype[c]=b.prototype[c]}else for(var e=Object.getOwnPropertyNames(b.prototype),
|
||||
d=0;d<e.length;d++)"undefined"==typeof Object.getOwnPropertyDescriptor(a.prototype,e[d])&&Object.defineProperty(a.prototype,e[d],Object.getOwnPropertyDescriptor(b.prototype,e[d]));for(c in b)"undefined"==typeof a[c]&&(a[c]=b[c]);a.$baseCtor=b};d.Path=function(){return[]};d.Paths=function(){return[]};d.DoublePoint=function(){var a=arguments;this.Y=this.X=0;1==a.length?(this.X=a[0].X,this.Y=a[0].Y):2==a.length&&(this.X=a[0],this.Y=a[1])};d.DoublePoint0=function(){this.Y=this.X=0};d.DoublePoint1=function(a){this.X=
|
||||
a.X;this.Y=a.Y};d.DoublePoint2=function(a,b){this.X=a;this.Y=b};d.PolyNode=function(){this.m_Parent=null;this.m_polygon=new d.Path;this.m_endtype=this.m_jointype=this.m_Index=0;this.m_Childs=[];this.IsOpen=!1};d.PolyNode.prototype.IsHoleNode=function(){for(var a=!0,b=this.m_Parent;null!==b;)a=!a,b=b.m_Parent;return a};d.PolyNode.prototype.ChildCount=function(){return this.m_Childs.length};d.PolyNode.prototype.Contour=function(){return this.m_polygon};d.PolyNode.prototype.AddChild=function(a){var b=
|
||||
this.m_Childs.length;this.m_Childs.push(a);a.m_Parent=this;a.m_Index=b};d.PolyNode.prototype.GetNext=function(){return 0<this.m_Childs.length?this.m_Childs[0]:this.GetNextSiblingUp()};d.PolyNode.prototype.GetNextSiblingUp=function(){return null===this.m_Parent?null:this.m_Index==this.m_Parent.m_Childs.length-1?this.m_Parent.GetNextSiblingUp():this.m_Parent.m_Childs[this.m_Index+1]};d.PolyNode.prototype.Childs=function(){return this.m_Childs};d.PolyNode.prototype.Parent=function(){return this.m_Parent};
|
||||
d.PolyNode.prototype.IsHole=function(){return this.IsHoleNode()};d.PolyTree=function(){this.m_AllPolys=[];d.PolyNode.call(this)};d.PolyTree.prototype.Clear=function(){for(var a=0,b=this.m_AllPolys.length;a<b;a++)this.m_AllPolys[a]=null;this.m_AllPolys.length=0;this.m_Childs.length=0};d.PolyTree.prototype.GetFirst=function(){return 0<this.m_Childs.length?this.m_Childs[0]:null};d.PolyTree.prototype.Total=function(){return this.m_AllPolys.length};K(d.PolyTree,d.PolyNode);d.Math_Abs_Int64=d.Math_Abs_Int32=
|
||||
d.Math_Abs_Double=function(a){return Math.abs(a)};d.Math_Max_Int32_Int32=function(a,b){return Math.max(a,b)};d.Cast_Int32=p||G||J?function(a){return a|0}:function(a){return~~a};d.Cast_Int64=E?function(a){return-2147483648>a||2147483647<a?0>a?Math.ceil(a):Math.floor(a):~~a}:F&&"function"==typeof Number.toInteger?function(a){return Number.toInteger(a)}:P||H?function(a){return parseInt(a,10)}:p?function(a){return-2147483648>a||2147483647<a?0>a?Math.ceil(a):Math.floor(a):a|0}:function(a){return 0>a?Math.ceil(a):
|
||||
Math.floor(a)};d.Clear=function(a){a.length=0};d.PI=3.141592653589793;d.PI2=6.283185307179586;d.IntPoint=function(){var a;a=arguments;var b=a.length;this.Y=this.X=0;2==b?(this.X=a[0],this.Y=a[1]):1==b?a[0]instanceof d.DoublePoint?(a=a[0],this.X=d.Clipper.Round(a.X),this.Y=d.Clipper.Round(a.Y)):(a=a[0],this.X=a.X,this.Y=a.Y):this.Y=this.X=0};d.IntPoint.op_Equality=function(a,b){return a.X==b.X&&a.Y==b.Y};d.IntPoint.op_Inequality=function(a,b){return a.X!=b.X||a.Y!=b.Y};d.IntPoint0=function(){this.Y=
|
||||
this.X=0};d.IntPoint1=function(a){this.X=a.X;this.Y=a.Y};d.IntPoint1dp=function(a){this.X=d.Clipper.Round(a.X);this.Y=d.Clipper.Round(a.Y)};d.IntPoint2=function(a,b){this.X=a;this.Y=b};d.IntRect=function(){var a=arguments,b=a.length;4==b?(this.left=a[0],this.top=a[1],this.right=a[2],this.bottom=a[3]):1==b?(this.left=ir.left,this.top=ir.top,this.right=ir.right,this.bottom=ir.bottom):this.bottom=this.right=this.top=this.left=0};d.IntRect0=function(){this.bottom=this.right=this.top=this.left=0};d.IntRect1=
|
||||
function(a){this.left=a.left;this.top=a.top;this.right=a.right;this.bottom=a.bottom};d.IntRect4=function(a,b,c,e){this.left=a;this.top=b;this.right=c;this.bottom=e};d.ClipType={ctIntersection:0,ctUnion:1,ctDifference:2,ctXor:3};d.PolyType={ptSubject:0,ptClip:1};d.PolyFillType={pftEvenOdd:0,pftNonZero:1,pftPositive:2,pftNegative:3};d.JoinType={jtSquare:0,jtRound:1,jtMiter:2};d.EndType={etOpenSquare:0,etOpenRound:1,etOpenButt:2,etClosedLine:3,etClosedPolygon:4};d.EdgeSide={esLeft:0,esRight:1};d.Direction=
|
||||
{dRightToLeft:0,dLeftToRight:1};d.TEdge=function(){this.Bot=new d.IntPoint;this.Curr=new d.IntPoint;this.Top=new d.IntPoint;this.Delta=new d.IntPoint;this.Dx=0;this.PolyTyp=d.PolyType.ptSubject;this.Side=d.EdgeSide.esLeft;this.OutIdx=this.WindCnt2=this.WindCnt=this.WindDelta=0;this.PrevInSEL=this.NextInSEL=this.PrevInAEL=this.NextInAEL=this.NextInLML=this.Prev=this.Next=null};d.IntersectNode=function(){this.Edge2=this.Edge1=null;this.Pt=new d.IntPoint};d.MyIntersectNodeSort=function(){};d.MyIntersectNodeSort.Compare=
|
||||
function(a,b){return b.Pt.Y-a.Pt.Y};d.LocalMinima=function(){this.Y=0;this.Next=this.RightBound=this.LeftBound=null};d.Scanbeam=function(){this.Y=0;this.Next=null};d.OutRec=function(){this.Idx=0;this.IsOpen=this.IsHole=!1;this.PolyNode=this.BottomPt=this.Pts=this.FirstLeft=null};d.OutPt=function(){this.Idx=0;this.Pt=new d.IntPoint;this.Prev=this.Next=null};d.Join=function(){this.OutPt2=this.OutPt1=null;this.OffPt=new d.IntPoint};d.ClipperBase=function(){this.m_CurrentLM=this.m_MinimaList=null;this.m_edges=
|
||||
[];this.PreserveCollinear=this.m_HasOpenPaths=this.m_UseFullRange=!1;this.m_CurrentLM=this.m_MinimaList=null;this.m_HasOpenPaths=this.m_UseFullRange=!1};d.ClipperBase.horizontal=-9007199254740992;d.ClipperBase.Skip=-2;d.ClipperBase.Unassigned=-1;d.ClipperBase.tolerance=1E-20;d.ClipperBase.loRange=47453132;d.ClipperBase.hiRange=0xfffffffffffff;d.ClipperBase.near_zero=function(a){return a>-d.ClipperBase.tolerance&&a<d.ClipperBase.tolerance};d.ClipperBase.IsHorizontal=function(a){return 0===a.Delta.Y};
|
||||
d.ClipperBase.prototype.PointIsVertex=function(a,b){var c=b;do{if(d.IntPoint.op_Equality(c.Pt,a))return!0;c=c.Next}while(c!=b);return!1};d.ClipperBase.prototype.PointOnLineSegment=function(a,b,c,e){return e?a.X==b.X&&a.Y==b.Y||a.X==c.X&&a.Y==c.Y||a.X>b.X==a.X<c.X&&a.Y>b.Y==a.Y<c.Y&&m.op_Equality(m.Int128Mul(a.X-b.X,c.Y-b.Y),m.Int128Mul(c.X-b.X,a.Y-b.Y)):a.X==b.X&&a.Y==b.Y||a.X==c.X&&a.Y==c.Y||a.X>b.X==a.X<c.X&&a.Y>b.Y==a.Y<c.Y&&(a.X-b.X)*(c.Y-b.Y)==(c.X-b.X)*(a.Y-b.Y)};d.ClipperBase.prototype.PointOnPolygon=
|
||||
function(a,b,c){for(var e=b;;){if(this.PointOnLineSegment(a,e.Pt,e.Next.Pt,c))return!0;e=e.Next;if(e==b)break}return!1};d.ClipperBase.prototype.SlopesEqual=d.ClipperBase.SlopesEqual=function(){var a=arguments,b=a.length,c,e,f;if(3==b)return b=a[0],c=a[1],(a=a[2])?m.op_Equality(m.Int128Mul(b.Delta.Y,c.Delta.X),m.Int128Mul(b.Delta.X,c.Delta.Y)):d.Cast_Int64(b.Delta.Y*c.Delta.X)==d.Cast_Int64(b.Delta.X*c.Delta.Y);if(4==b)return b=a[0],c=a[1],e=a[2],(a=a[3])?m.op_Equality(m.Int128Mul(b.Y-c.Y,c.X-e.X),
|
||||
m.Int128Mul(b.X-c.X,c.Y-e.Y)):0===d.Cast_Int64((b.Y-c.Y)*(c.X-e.X))-d.Cast_Int64((b.X-c.X)*(c.Y-e.Y));b=a[0];c=a[1];e=a[2];f=a[3];return(a=a[4])?m.op_Equality(m.Int128Mul(b.Y-c.Y,e.X-f.X),m.Int128Mul(b.X-c.X,e.Y-f.Y)):0===d.Cast_Int64((b.Y-c.Y)*(e.X-f.X))-d.Cast_Int64((b.X-c.X)*(e.Y-f.Y))};d.ClipperBase.SlopesEqual3=function(a,b,c){return c?m.op_Equality(m.Int128Mul(a.Delta.Y,b.Delta.X),m.Int128Mul(a.Delta.X,b.Delta.Y)):d.Cast_Int64(a.Delta.Y*b.Delta.X)==d.Cast_Int64(a.Delta.X*b.Delta.Y)};d.ClipperBase.SlopesEqual4=
|
||||
function(a,b,c,e){return e?m.op_Equality(m.Int128Mul(a.Y-b.Y,b.X-c.X),m.Int128Mul(a.X-b.X,b.Y-c.Y)):0===d.Cast_Int64((a.Y-b.Y)*(b.X-c.X))-d.Cast_Int64((a.X-b.X)*(b.Y-c.Y))};d.ClipperBase.SlopesEqual5=function(a,b,c,e,f){return f?m.op_Equality(m.Int128Mul(a.Y-b.Y,c.X-e.X),m.Int128Mul(a.X-b.X,c.Y-e.Y)):0===d.Cast_Int64((a.Y-b.Y)*(c.X-e.X))-d.Cast_Int64((a.X-b.X)*(c.Y-e.Y))};d.ClipperBase.prototype.Clear=function(){this.DisposeLocalMinimaList();for(var a=0,b=this.m_edges.length;a<b;++a){for(var c=0,
|
||||
e=this.m_edges[a].length;c<e;++c)this.m_edges[a][c]=null;d.Clear(this.m_edges[a])}d.Clear(this.m_edges);this.m_HasOpenPaths=this.m_UseFullRange=!1};d.ClipperBase.prototype.DisposeLocalMinimaList=function(){for(;null!==this.m_MinimaList;){var a=this.m_MinimaList.Next;this.m_MinimaList=null;this.m_MinimaList=a}this.m_CurrentLM=null};d.ClipperBase.prototype.RangeTest=function(a,b){if(b.Value)(a.X>d.ClipperBase.hiRange||a.Y>d.ClipperBase.hiRange||-a.X>d.ClipperBase.hiRange||-a.Y>d.ClipperBase.hiRange)&&
|
||||
d.Error("Coordinate outside allowed range in RangeTest().");else if(a.X>d.ClipperBase.loRange||a.Y>d.ClipperBase.loRange||-a.X>d.ClipperBase.loRange||-a.Y>d.ClipperBase.loRange)b.Value=!0,this.RangeTest(a,b)};d.ClipperBase.prototype.InitEdge=function(a,b,c,e){a.Next=b;a.Prev=c;a.Curr.X=e.X;a.Curr.Y=e.Y;a.OutIdx=-1};d.ClipperBase.prototype.InitEdge2=function(a,b){a.Curr.Y>=a.Next.Curr.Y?(a.Bot.X=a.Curr.X,a.Bot.Y=a.Curr.Y,a.Top.X=a.Next.Curr.X,a.Top.Y=a.Next.Curr.Y):(a.Top.X=a.Curr.X,a.Top.Y=a.Curr.Y,
|
||||
a.Bot.X=a.Next.Curr.X,a.Bot.Y=a.Next.Curr.Y);this.SetDx(a);a.PolyTyp=b};d.ClipperBase.prototype.FindNextLocMin=function(a){for(var b;;){for(;d.IntPoint.op_Inequality(a.Bot,a.Prev.Bot)||d.IntPoint.op_Equality(a.Curr,a.Top);)a=a.Next;if(a.Dx!=d.ClipperBase.horizontal&&a.Prev.Dx!=d.ClipperBase.horizontal)break;for(;a.Prev.Dx==d.ClipperBase.horizontal;)a=a.Prev;for(b=a;a.Dx==d.ClipperBase.horizontal;)a=a.Next;if(a.Top.Y!=a.Prev.Bot.Y){b.Prev.Bot.X<a.Bot.X&&(a=b);break}}return a};d.ClipperBase.prototype.ProcessBound=
|
||||
function(a,b){var c=a,e=a,f;a.Dx==d.ClipperBase.horizontal&&(f=b?a.Prev.Bot.X:a.Next.Bot.X,a.Bot.X!=f&&this.ReverseHorizontal(a));if(e.OutIdx!=d.ClipperBase.Skip)if(b){for(;e.Top.Y==e.Next.Bot.Y&&e.Next.OutIdx!=d.ClipperBase.Skip;)e=e.Next;if(e.Dx==d.ClipperBase.horizontal&&e.Next.OutIdx!=d.ClipperBase.Skip){for(f=e;f.Prev.Dx==d.ClipperBase.horizontal;)f=f.Prev;f.Prev.Top.X==e.Next.Top.X?b||(e=f.Prev):f.Prev.Top.X>e.Next.Top.X&&(e=f.Prev)}for(;a!=e;)a.NextInLML=a.Next,a.Dx==d.ClipperBase.horizontal&&
|
||||
a!=c&&a.Bot.X!=a.Prev.Top.X&&this.ReverseHorizontal(a),a=a.Next;a.Dx==d.ClipperBase.horizontal&&a!=c&&a.Bot.X!=a.Prev.Top.X&&this.ReverseHorizontal(a);e=e.Next}else{for(;e.Top.Y==e.Prev.Bot.Y&&e.Prev.OutIdx!=d.ClipperBase.Skip;)e=e.Prev;if(e.Dx==d.ClipperBase.horizontal&&e.Prev.OutIdx!=d.ClipperBase.Skip){for(f=e;f.Next.Dx==d.ClipperBase.horizontal;)f=f.Next;f.Next.Top.X==e.Prev.Top.X?b||(e=f.Next):f.Next.Top.X>e.Prev.Top.X&&(e=f.Next)}for(;a!=e;)a.NextInLML=a.Prev,a.Dx==d.ClipperBase.horizontal&&
|
||||
a!=c&&a.Bot.X!=a.Next.Top.X&&this.ReverseHorizontal(a),a=a.Prev;a.Dx==d.ClipperBase.horizontal&&a!=c&&a.Bot.X!=a.Next.Top.X&&this.ReverseHorizontal(a);e=e.Prev}if(e.OutIdx==d.ClipperBase.Skip){a=e;if(b){for(;a.Top.Y==a.Next.Bot.Y;)a=a.Next;for(;a!=e&&a.Dx==d.ClipperBase.horizontal;)a=a.Prev}else{for(;a.Top.Y==a.Prev.Bot.Y;)a=a.Prev;for(;a!=e&&a.Dx==d.ClipperBase.horizontal;)a=a.Next}a==e?e=b?a.Next:a.Prev:(a=b?e.Next:e.Prev,c=new d.LocalMinima,c.Next=null,c.Y=a.Bot.Y,c.LeftBound=null,c.RightBound=
|
||||
a,c.RightBound.WindDelta=0,e=this.ProcessBound(c.RightBound,b),this.InsertLocalMinima(c))}return e};d.ClipperBase.prototype.AddPath=function(a,b,c){c||b!=d.PolyType.ptClip||d.Error("AddPath: Open paths must be subject.");var e=a.length-1;if(c)for(;0<e&&d.IntPoint.op_Equality(a[e],a[0]);)--e;for(;0<e&&d.IntPoint.op_Equality(a[e],a[e-1]);)--e;if(c&&2>e||!c&&1>e)return!1;for(var f=[],g=0;g<=e;g++)f.push(new d.TEdge);var h=!0;f[1].Curr.X=a[1].X;f[1].Curr.Y=a[1].Y;var l={Value:this.m_UseFullRange};this.RangeTest(a[0],
|
||||
l);this.m_UseFullRange=l.Value;l.Value=this.m_UseFullRange;this.RangeTest(a[e],l);this.m_UseFullRange=l.Value;this.InitEdge(f[0],f[1],f[e],a[0]);this.InitEdge(f[e],f[0],f[e-1],a[e]);for(g=e-1;1<=g;--g)l.Value=this.m_UseFullRange,this.RangeTest(a[g],l),this.m_UseFullRange=l.Value,this.InitEdge(f[g],f[g+1],f[g-1],a[g]);for(g=a=e=f[0];;)if(d.IntPoint.op_Equality(a.Curr,a.Next.Curr)){if(a==a.Next)break;a==e&&(e=a.Next);g=a=this.RemoveEdge(a)}else{if(a.Prev==a.Next)break;else if(c&&d.ClipperBase.SlopesEqual(a.Prev.Curr,
|
||||
a.Curr,a.Next.Curr,this.m_UseFullRange)&&(!this.PreserveCollinear||!this.Pt2IsBetweenPt1AndPt3(a.Prev.Curr,a.Curr,a.Next.Curr))){a==e&&(e=a.Next);a=this.RemoveEdge(a);g=a=a.Prev;continue}a=a.Next;if(a==g)break}if(!c&&a==a.Next||c&&a.Prev==a.Next)return!1;c||(this.m_HasOpenPaths=!0,e.Prev.OutIdx=d.ClipperBase.Skip);a=e;do this.InitEdge2(a,b),a=a.Next,h&&a.Curr.Y!=e.Curr.Y&&(h=!1);while(a!=e);if(h){if(c)return!1;a.Prev.OutIdx=d.ClipperBase.Skip;a.Prev.Bot.X<a.Prev.Top.X&&this.ReverseHorizontal(a.Prev);
|
||||
b=new d.LocalMinima;b.Next=null;b.Y=a.Bot.Y;b.LeftBound=null;b.RightBound=a;b.RightBound.Side=d.EdgeSide.esRight;for(b.RightBound.WindDelta=0;a.Next.OutIdx!=d.ClipperBase.Skip;)a.NextInLML=a.Next,a.Bot.X!=a.Prev.Top.X&&this.ReverseHorizontal(a),a=a.Next;this.InsertLocalMinima(b);this.m_edges.push(f);return!0}this.m_edges.push(f);for(h=null;;){a=this.FindNextLocMin(a);if(a==h)break;else null==h&&(h=a);b=new d.LocalMinima;b.Next=null;b.Y=a.Bot.Y;a.Dx<a.Prev.Dx?(b.LeftBound=a.Prev,b.RightBound=a,f=!1):
|
||||
(b.LeftBound=a,b.RightBound=a.Prev,f=!0);b.LeftBound.Side=d.EdgeSide.esLeft;b.RightBound.Side=d.EdgeSide.esRight;b.LeftBound.WindDelta=c?b.LeftBound.Next==b.RightBound?-1:1:0;b.RightBound.WindDelta=-b.LeftBound.WindDelta;a=this.ProcessBound(b.LeftBound,f);e=this.ProcessBound(b.RightBound,!f);b.LeftBound.OutIdx==d.ClipperBase.Skip?b.LeftBound=null:b.RightBound.OutIdx==d.ClipperBase.Skip&&(b.RightBound=null);this.InsertLocalMinima(b);f||(a=e)}return!0};d.ClipperBase.prototype.AddPaths=function(a,b,
|
||||
c){for(var e=!1,d=0,g=a.length;d<g;++d)this.AddPath(a[d],b,c)&&(e=!0);return e};d.ClipperBase.prototype.Pt2IsBetweenPt1AndPt3=function(a,b,c){return d.IntPoint.op_Equality(a,c)||d.IntPoint.op_Equality(a,b)||d.IntPoint.op_Equality(c,b)?!1:a.X!=c.X?b.X>a.X==b.X<c.X:b.Y>a.Y==b.Y<c.Y};d.ClipperBase.prototype.RemoveEdge=function(a){a.Prev.Next=a.Next;a.Next.Prev=a.Prev;var b=a.Next;a.Prev=null;return b};d.ClipperBase.prototype.SetDx=function(a){a.Delta.X=a.Top.X-a.Bot.X;a.Delta.Y=a.Top.Y-a.Bot.Y;a.Dx=
|
||||
0===a.Delta.Y?d.ClipperBase.horizontal:a.Delta.X/a.Delta.Y};d.ClipperBase.prototype.InsertLocalMinima=function(a){if(null===this.m_MinimaList)this.m_MinimaList=a;else if(a.Y>=this.m_MinimaList.Y)a.Next=this.m_MinimaList,this.m_MinimaList=a;else{for(var b=this.m_MinimaList;null!==b.Next&&a.Y<b.Next.Y;)b=b.Next;a.Next=b.Next;b.Next=a}};d.ClipperBase.prototype.PopLocalMinima=function(){null!==this.m_CurrentLM&&(this.m_CurrentLM=this.m_CurrentLM.Next)};d.ClipperBase.prototype.ReverseHorizontal=function(a){var b=
|
||||
a.Top.X;a.Top.X=a.Bot.X;a.Bot.X=b};d.ClipperBase.prototype.Reset=function(){this.m_CurrentLM=this.m_MinimaList;if(null!=this.m_CurrentLM)for(var a=this.m_MinimaList;null!=a;){var b=a.LeftBound;null!=b&&(b.Curr.X=b.Bot.X,b.Curr.Y=b.Bot.Y,b.Side=d.EdgeSide.esLeft,b.OutIdx=d.ClipperBase.Unassigned);b=a.RightBound;null!=b&&(b.Curr.X=b.Bot.X,b.Curr.Y=b.Bot.Y,b.Side=d.EdgeSide.esRight,b.OutIdx=d.ClipperBase.Unassigned);a=a.Next}};d.Clipper=function(a){"undefined"==typeof a&&(a=0);this.m_PolyOuts=null;this.m_ClipType=
|
||||
d.ClipType.ctIntersection;this.m_IntersectNodeComparer=this.m_IntersectList=this.m_SortedEdges=this.m_ActiveEdges=this.m_Scanbeam=null;this.m_ExecuteLocked=!1;this.m_SubjFillType=this.m_ClipFillType=d.PolyFillType.pftEvenOdd;this.m_GhostJoins=this.m_Joins=null;this.StrictlySimple=this.ReverseSolution=this.m_UsingPolyTree=!1;d.ClipperBase.call(this);this.m_SortedEdges=this.m_ActiveEdges=this.m_Scanbeam=null;this.m_IntersectList=[];this.m_IntersectNodeComparer=d.MyIntersectNodeSort.Compare;this.m_UsingPolyTree=
|
||||
this.m_ExecuteLocked=!1;this.m_PolyOuts=[];this.m_Joins=[];this.m_GhostJoins=[];this.ReverseSolution=0!==(1&a);this.StrictlySimple=0!==(2&a);this.PreserveCollinear=0!==(4&a)};d.Clipper.ioReverseSolution=1;d.Clipper.ioStrictlySimple=2;d.Clipper.ioPreserveCollinear=4;d.Clipper.prototype.Clear=function(){0!==this.m_edges.length&&(this.DisposeAllPolyPts(),d.ClipperBase.prototype.Clear.call(this))};d.Clipper.prototype.DisposeScanbeamList=function(){for(;null!==this.m_Scanbeam;){var a=this.m_Scanbeam.Next;
|
||||
this.m_Scanbeam=null;this.m_Scanbeam=a}};d.Clipper.prototype.Reset=function(){d.ClipperBase.prototype.Reset.call(this);this.m_SortedEdges=this.m_ActiveEdges=this.m_Scanbeam=null;for(var a=this.m_MinimaList;null!==a;)this.InsertScanbeam(a.Y),a=a.Next};d.Clipper.prototype.InsertScanbeam=function(a){if(null===this.m_Scanbeam)this.m_Scanbeam=new d.Scanbeam,this.m_Scanbeam.Next=null,this.m_Scanbeam.Y=a;else if(a>this.m_Scanbeam.Y){var b=new d.Scanbeam;b.Y=a;b.Next=this.m_Scanbeam;this.m_Scanbeam=b}else{for(var c=
|
||||
this.m_Scanbeam;null!==c.Next&&a<=c.Next.Y;)c=c.Next;a!=c.Y&&(b=new d.Scanbeam,b.Y=a,b.Next=c.Next,c.Next=b)}};d.Clipper.prototype.Execute=function(){var a=arguments,b=a.length,c=a[1]instanceof d.PolyTree;if(4!=b||c){if(4==b&&c){var b=a[0],e=a[1],c=a[2],a=a[3];if(this.m_ExecuteLocked)return!1;this.m_ExecuteLocked=!0;this.m_SubjFillType=c;this.m_ClipFillType=a;this.m_ClipType=b;this.m_UsingPolyTree=!0;try{(f=this.ExecuteInternal())&&this.BuildResult2(e)}finally{this.DisposeAllPolyPts(),this.m_ExecuteLocked=
|
||||
!1}return f}if(2==b&&!c||2==b&&c)return b=a[0],e=a[1],this.Execute(b,e,d.PolyFillType.pftEvenOdd,d.PolyFillType.pftEvenOdd)}else{b=a[0];e=a[1];c=a[2];a=a[3];if(this.m_ExecuteLocked)return!1;this.m_HasOpenPaths&&d.Error("Error: PolyTree struct is need for open path clipping.");this.m_ExecuteLocked=!0;d.Clear(e);this.m_SubjFillType=c;this.m_ClipFillType=a;this.m_ClipType=b;this.m_UsingPolyTree=!1;try{var f=this.ExecuteInternal();f&&this.BuildResult(e)}finally{this.DisposeAllPolyPts(),this.m_ExecuteLocked=
|
||||
!1}return f}};d.Clipper.prototype.FixHoleLinkage=function(a){if(null!==a.FirstLeft&&(a.IsHole==a.FirstLeft.IsHole||null===a.FirstLeft.Pts)){for(var b=a.FirstLeft;null!==b&&(b.IsHole==a.IsHole||null===b.Pts);)b=b.FirstLeft;a.FirstLeft=b}};d.Clipper.prototype.ExecuteInternal=function(){try{this.Reset();if(null===this.m_CurrentLM)return!1;var a=this.PopScanbeam();do{this.InsertLocalMinimaIntoAEL(a);d.Clear(this.m_GhostJoins);this.ProcessHorizontals(!1);if(null===this.m_Scanbeam)break;var b=this.PopScanbeam();
|
||||
if(!this.ProcessIntersections(a,b))return!1;this.ProcessEdgesAtTopOfScanbeam(b);a=b}while(null!==this.m_Scanbeam||null!==this.m_CurrentLM);for(var a=0,c=this.m_PolyOuts.length;a<c;a++){var e=this.m_PolyOuts[a];null===e.Pts||e.IsOpen||(e.IsHole^this.ReverseSolution)==0<this.Area(e)&&this.ReversePolyPtLinks(e.Pts)}this.JoinCommonEdges();a=0;for(c=this.m_PolyOuts.length;a<c;a++)e=this.m_PolyOuts[a],null===e.Pts||e.IsOpen||this.FixupOutPolygon(e);this.StrictlySimple&&this.DoSimplePolygons();return!0}finally{d.Clear(this.m_Joins),
|
||||
d.Clear(this.m_GhostJoins)}};d.Clipper.prototype.PopScanbeam=function(){var a=this.m_Scanbeam.Y;this.m_Scanbeam=this.m_Scanbeam.Next;return a};d.Clipper.prototype.DisposeAllPolyPts=function(){for(var a=0,b=this.m_PolyOuts.length;a<b;++a)this.DisposeOutRec(a);d.Clear(this.m_PolyOuts)};d.Clipper.prototype.DisposeOutRec=function(a){var b=this.m_PolyOuts[a];null!==b.Pts&&this.DisposeOutPts(b.Pts);this.m_PolyOuts[a]=null};d.Clipper.prototype.DisposeOutPts=function(a){if(null!==a)for(a.Prev.Next=null;null!==
|
||||
a;)a=a.Next};d.Clipper.prototype.AddJoin=function(a,b,c){var e=new d.Join;e.OutPt1=a;e.OutPt2=b;e.OffPt.X=c.X;e.OffPt.Y=c.Y;this.m_Joins.push(e)};d.Clipper.prototype.AddGhostJoin=function(a,b){var c=new d.Join;c.OutPt1=a;c.OffPt.X=b.X;c.OffPt.Y=b.Y;this.m_GhostJoins.push(c)};d.Clipper.prototype.InsertLocalMinimaIntoAEL=function(a){for(;null!==this.m_CurrentLM&&this.m_CurrentLM.Y==a;){var b=this.m_CurrentLM.LeftBound,c=this.m_CurrentLM.RightBound;this.PopLocalMinima();var e=null;null===b?(this.InsertEdgeIntoAEL(c,
|
||||
null),this.SetWindingCount(c),this.IsContributing(c)&&(e=this.AddOutPt(c,c.Bot))):(null==c?(this.InsertEdgeIntoAEL(b,null),this.SetWindingCount(b),this.IsContributing(b)&&(e=this.AddOutPt(b,b.Bot))):(this.InsertEdgeIntoAEL(b,null),this.InsertEdgeIntoAEL(c,b),this.SetWindingCount(b),c.WindCnt=b.WindCnt,c.WindCnt2=b.WindCnt2,this.IsContributing(b)&&(e=this.AddLocalMinPoly(b,c,b.Bot))),this.InsertScanbeam(b.Top.Y));null!=c&&(d.ClipperBase.IsHorizontal(c)?this.AddEdgeToSEL(c):this.InsertScanbeam(c.Top.Y));
|
||||
if(null!=b&&null!=c){if(null!==e&&d.ClipperBase.IsHorizontal(c)&&0<this.m_GhostJoins.length&&0!==c.WindDelta)for(var f=0,g=this.m_GhostJoins.length;f<g;f++){var h=this.m_GhostJoins[f];this.HorzSegmentsOverlap(h.OutPt1.Pt,h.OffPt,c.Bot,c.Top)&&this.AddJoin(h.OutPt1,e,h.OffPt)}0<=b.OutIdx&&null!==b.PrevInAEL&&b.PrevInAEL.Curr.X==b.Bot.X&&0<=b.PrevInAEL.OutIdx&&d.ClipperBase.SlopesEqual(b.PrevInAEL,b,this.m_UseFullRange)&&0!==b.WindDelta&&0!==b.PrevInAEL.WindDelta&&(f=this.AddOutPt(b.PrevInAEL,b.Bot),
|
||||
this.AddJoin(e,f,b.Top));if(b.NextInAEL!=c&&(0<=c.OutIdx&&0<=c.PrevInAEL.OutIdx&&d.ClipperBase.SlopesEqual(c.PrevInAEL,c,this.m_UseFullRange)&&0!==c.WindDelta&&0!==c.PrevInAEL.WindDelta&&(f=this.AddOutPt(c.PrevInAEL,c.Bot),this.AddJoin(e,f,c.Top)),e=b.NextInAEL,null!==e))for(;e!=c;)this.IntersectEdges(c,e,b.Curr,!1),e=e.NextInAEL}}};d.Clipper.prototype.InsertEdgeIntoAEL=function(a,b){if(null===this.m_ActiveEdges)a.PrevInAEL=null,a.NextInAEL=null,this.m_ActiveEdges=a;else if(null===b&&this.E2InsertsBeforeE1(this.m_ActiveEdges,
|
||||
a))a.PrevInAEL=null,a.NextInAEL=this.m_ActiveEdges,this.m_ActiveEdges=this.m_ActiveEdges.PrevInAEL=a;else{null===b&&(b=this.m_ActiveEdges);for(;null!==b.NextInAEL&&!this.E2InsertsBeforeE1(b.NextInAEL,a);)b=b.NextInAEL;a.NextInAEL=b.NextInAEL;null!==b.NextInAEL&&(b.NextInAEL.PrevInAEL=a);a.PrevInAEL=b;b.NextInAEL=a}};d.Clipper.prototype.E2InsertsBeforeE1=function(a,b){return b.Curr.X==a.Curr.X?b.Top.Y>a.Top.Y?b.Top.X<d.Clipper.TopX(a,b.Top.Y):a.Top.X>d.Clipper.TopX(b,a.Top.Y):b.Curr.X<a.Curr.X};d.Clipper.prototype.IsEvenOddFillType=
|
||||
function(a){return a.PolyTyp==d.PolyType.ptSubject?this.m_SubjFillType==d.PolyFillType.pftEvenOdd:this.m_ClipFillType==d.PolyFillType.pftEvenOdd};d.Clipper.prototype.IsEvenOddAltFillType=function(a){return a.PolyTyp==d.PolyType.ptSubject?this.m_ClipFillType==d.PolyFillType.pftEvenOdd:this.m_SubjFillType==d.PolyFillType.pftEvenOdd};d.Clipper.prototype.IsContributing=function(a){var b,c;a.PolyTyp==d.PolyType.ptSubject?(b=this.m_SubjFillType,c=this.m_ClipFillType):(b=this.m_ClipFillType,c=this.m_SubjFillType);
|
||||
switch(b){case d.PolyFillType.pftEvenOdd:if(0===a.WindDelta&&1!=a.WindCnt)return!1;break;case d.PolyFillType.pftNonZero:if(1!=Math.abs(a.WindCnt))return!1;break;case d.PolyFillType.pftPositive:if(1!=a.WindCnt)return!1;break;default:if(-1!=a.WindCnt)return!1}switch(this.m_ClipType){case d.ClipType.ctIntersection:switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0!==a.WindCnt2;case d.PolyFillType.pftPositive:return 0<a.WindCnt2;default:return 0>a.WindCnt2}case d.ClipType.ctUnion:switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0===
|
||||
a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}case d.ClipType.ctDifference:if(a.PolyTyp==d.PolyType.ptSubject)switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0===a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}else switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0!==a.WindCnt2;case d.PolyFillType.pftPositive:return 0<a.WindCnt2;default:return 0>
|
||||
a.WindCnt2}case d.ClipType.ctXor:if(0===a.WindDelta)switch(c){case d.PolyFillType.pftEvenOdd:case d.PolyFillType.pftNonZero:return 0===a.WindCnt2;case d.PolyFillType.pftPositive:return 0>=a.WindCnt2;default:return 0<=a.WindCnt2}}return!0};d.Clipper.prototype.SetWindingCount=function(a){for(var b=a.PrevInAEL;null!==b&&(b.PolyTyp!=a.PolyTyp||0===b.WindDelta);)b=b.PrevInAEL;if(null===b)a.WindCnt=0===a.WindDelta?1:a.WindDelta,a.WindCnt2=0,b=this.m_ActiveEdges;else{if(0===a.WindDelta&&this.m_ClipType!=
|
||||
d.ClipType.ctUnion)a.WindCnt=1;else if(this.IsEvenOddFillType(a))if(0===a.WindDelta){for(var c=!0,e=b.PrevInAEL;null!==e;)e.PolyTyp==b.PolyTyp&&0!==e.WindDelta&&(c=!c),e=e.PrevInAEL;a.WindCnt=c?0:1}else a.WindCnt=a.WindDelta;else 0>b.WindCnt*b.WindDelta?1<Math.abs(b.WindCnt)?a.WindCnt=0>b.WindDelta*a.WindDelta?b.WindCnt:b.WindCnt+a.WindDelta:a.WindCnt=0===a.WindDelta?1:a.WindDelta:a.WindCnt=0===a.WindDelta?0>b.WindCnt?b.WindCnt-1:b.WindCnt+1:0>b.WindDelta*a.WindDelta?b.WindCnt:b.WindCnt+a.WindDelta;
|
||||
a.WindCnt2=b.WindCnt2;b=b.NextInAEL}if(this.IsEvenOddAltFillType(a))for(;b!=a;)0!==b.WindDelta&&(a.WindCnt2=0===a.WindCnt2?1:0),b=b.NextInAEL;else for(;b!=a;)a.WindCnt2+=b.WindDelta,b=b.NextInAEL};d.Clipper.prototype.AddEdgeToSEL=function(a){null===this.m_SortedEdges?(this.m_SortedEdges=a,a.PrevInSEL=null,a.NextInSEL=null):(a.NextInSEL=this.m_SortedEdges,a.PrevInSEL=null,this.m_SortedEdges=this.m_SortedEdges.PrevInSEL=a)};d.Clipper.prototype.CopyAELToSEL=function(){var a=this.m_ActiveEdges;for(this.m_SortedEdges=
|
||||
a;null!==a;)a.PrevInSEL=a.PrevInAEL,a=a.NextInSEL=a.NextInAEL};d.Clipper.prototype.SwapPositionsInAEL=function(a,b){if(a.NextInAEL!=a.PrevInAEL&&b.NextInAEL!=b.PrevInAEL){if(a.NextInAEL==b){var c=b.NextInAEL;null!==c&&(c.PrevInAEL=a);var e=a.PrevInAEL;null!==e&&(e.NextInAEL=b);b.PrevInAEL=e;b.NextInAEL=a;a.PrevInAEL=b;a.NextInAEL=c}else b.NextInAEL==a?(c=a.NextInAEL,null!==c&&(c.PrevInAEL=b),e=b.PrevInAEL,null!==e&&(e.NextInAEL=a),a.PrevInAEL=e,a.NextInAEL=b,b.PrevInAEL=a,b.NextInAEL=c):(c=a.NextInAEL,
|
||||
e=a.PrevInAEL,a.NextInAEL=b.NextInAEL,null!==a.NextInAEL&&(a.NextInAEL.PrevInAEL=a),a.PrevInAEL=b.PrevInAEL,null!==a.PrevInAEL&&(a.PrevInAEL.NextInAEL=a),b.NextInAEL=c,null!==b.NextInAEL&&(b.NextInAEL.PrevInAEL=b),b.PrevInAEL=e,null!==b.PrevInAEL&&(b.PrevInAEL.NextInAEL=b));null===a.PrevInAEL?this.m_ActiveEdges=a:null===b.PrevInAEL&&(this.m_ActiveEdges=b)}};d.Clipper.prototype.SwapPositionsInSEL=function(a,b){if(null!==a.NextInSEL||null!==a.PrevInSEL)if(null!==b.NextInSEL||null!==b.PrevInSEL){if(a.NextInSEL==
|
||||
b){var c=b.NextInSEL;null!==c&&(c.PrevInSEL=a);var e=a.PrevInSEL;null!==e&&(e.NextInSEL=b);b.PrevInSEL=e;b.NextInSEL=a;a.PrevInSEL=b;a.NextInSEL=c}else b.NextInSEL==a?(c=a.NextInSEL,null!==c&&(c.PrevInSEL=b),e=b.PrevInSEL,null!==e&&(e.NextInSEL=a),a.PrevInSEL=e,a.NextInSEL=b,b.PrevInSEL=a,b.NextInSEL=c):(c=a.NextInSEL,e=a.PrevInSEL,a.NextInSEL=b.NextInSEL,null!==a.NextInSEL&&(a.NextInSEL.PrevInSEL=a),a.PrevInSEL=b.PrevInSEL,null!==a.PrevInSEL&&(a.PrevInSEL.NextInSEL=a),b.NextInSEL=c,null!==b.NextInSEL&&
|
||||
(b.NextInSEL.PrevInSEL=b),b.PrevInSEL=e,null!==b.PrevInSEL&&(b.PrevInSEL.NextInSEL=b));null===a.PrevInSEL?this.m_SortedEdges=a:null===b.PrevInSEL&&(this.m_SortedEdges=b)}};d.Clipper.prototype.AddLocalMaxPoly=function(a,b,c){this.AddOutPt(a,c);0==b.WindDelta&&this.AddOutPt(b,c);a.OutIdx==b.OutIdx?(a.OutIdx=-1,b.OutIdx=-1):a.OutIdx<b.OutIdx?this.AppendPolygon(a,b):this.AppendPolygon(b,a)};d.Clipper.prototype.AddLocalMinPoly=function(a,b,c){var e,f;d.ClipperBase.IsHorizontal(b)||a.Dx>b.Dx?(e=this.AddOutPt(a,
|
||||
c),b.OutIdx=a.OutIdx,a.Side=d.EdgeSide.esLeft,b.Side=d.EdgeSide.esRight,f=a,a=f.PrevInAEL==b?b.PrevInAEL:f.PrevInAEL):(e=this.AddOutPt(b,c),a.OutIdx=b.OutIdx,a.Side=d.EdgeSide.esRight,b.Side=d.EdgeSide.esLeft,f=b,a=f.PrevInAEL==a?a.PrevInAEL:f.PrevInAEL);null!==a&&0<=a.OutIdx&&d.Clipper.TopX(a,c.Y)==d.Clipper.TopX(f,c.Y)&&d.ClipperBase.SlopesEqual(f,a,this.m_UseFullRange)&&0!==f.WindDelta&&0!==a.WindDelta&&(c=this.AddOutPt(a,c),this.AddJoin(e,c,f.Top));return e};d.Clipper.prototype.CreateOutRec=function(){var a=
|
||||
new d.OutRec;a.Idx=-1;a.IsHole=!1;a.IsOpen=!1;a.FirstLeft=null;a.Pts=null;a.BottomPt=null;a.PolyNode=null;this.m_PolyOuts.push(a);a.Idx=this.m_PolyOuts.length-1;return a};d.Clipper.prototype.AddOutPt=function(a,b){var c=a.Side==d.EdgeSide.esLeft;if(0>a.OutIdx){var e=this.CreateOutRec();e.IsOpen=0===a.WindDelta;var f=new d.OutPt;e.Pts=f;f.Idx=e.Idx;f.Pt.X=b.X;f.Pt.Y=b.Y;f.Next=f;f.Prev=f;e.IsOpen||this.SetHoleState(a,e);a.OutIdx=e.Idx}else{var e=this.m_PolyOuts[a.OutIdx],g=e.Pts;if(c&&d.IntPoint.op_Equality(b,
|
||||
g.Pt))return g;if(!c&&d.IntPoint.op_Equality(b,g.Prev.Pt))return g.Prev;f=new d.OutPt;f.Idx=e.Idx;f.Pt.X=b.X;f.Pt.Y=b.Y;f.Next=g;f.Prev=g.Prev;f.Prev.Next=f;g.Prev=f;c&&(e.Pts=f)}return f};d.Clipper.prototype.SwapPoints=function(a,b){var c=new d.IntPoint(a.Value);a.Value.X=b.Value.X;a.Value.Y=b.Value.Y;b.Value.X=c.X;b.Value.Y=c.Y};d.Clipper.prototype.HorzSegmentsOverlap=function(a,b,c,e){return a.X>c.X==a.X<e.X?!0:b.X>c.X==b.X<e.X?!0:c.X>a.X==c.X<b.X?!0:e.X>a.X==e.X<b.X?!0:a.X==c.X&&b.X==e.X?!0:a.X==
|
||||
e.X&&b.X==c.X?!0:!1};d.Clipper.prototype.InsertPolyPtBetween=function(a,b,c){var e=new d.OutPt;e.Pt.X=c.X;e.Pt.Y=c.Y;b==a.Next?(a.Next=e,b.Prev=e,e.Next=b,e.Prev=a):(b.Next=e,a.Prev=e,e.Next=a,e.Prev=b);return e};d.Clipper.prototype.SetHoleState=function(a,b){for(var c=!1,e=a.PrevInAEL;null!==e;)0<=e.OutIdx&&0!=e.WindDelta&&(c=!c,null===b.FirstLeft&&(b.FirstLeft=this.m_PolyOuts[e.OutIdx])),e=e.PrevInAEL;c&&(b.IsHole=!0)};d.Clipper.prototype.GetDx=function(a,b){return a.Y==b.Y?d.ClipperBase.horizontal:
|
||||
(b.X-a.X)/(b.Y-a.Y)};d.Clipper.prototype.FirstIsBottomPt=function(a,b){for(var c=a.Prev;d.IntPoint.op_Equality(c.Pt,a.Pt)&&c!=a;)c=c.Prev;for(var e=Math.abs(this.GetDx(a.Pt,c.Pt)),c=a.Next;d.IntPoint.op_Equality(c.Pt,a.Pt)&&c!=a;)c=c.Next;for(var f=Math.abs(this.GetDx(a.Pt,c.Pt)),c=b.Prev;d.IntPoint.op_Equality(c.Pt,b.Pt)&&c!=b;)c=c.Prev;for(var g=Math.abs(this.GetDx(b.Pt,c.Pt)),c=b.Next;d.IntPoint.op_Equality(c.Pt,b.Pt)&&c!=b;)c=c.Next;c=Math.abs(this.GetDx(b.Pt,c.Pt));return e>=g&&e>=c||f>=g&&f>=
|
||||
c};d.Clipper.prototype.GetBottomPt=function(a){for(var b=null,c=a.Next;c!=a;)c.Pt.Y>a.Pt.Y?(a=c,b=null):c.Pt.Y==a.Pt.Y&&c.Pt.X<=a.Pt.X&&(c.Pt.X<a.Pt.X?(b=null,a=c):c.Next!=a&&c.Prev!=a&&(b=c)),c=c.Next;if(null!==b)for(;b!=c;)for(this.FirstIsBottomPt(c,b)||(a=b),b=b.Next;d.IntPoint.op_Inequality(b.Pt,a.Pt);)b=b.Next;return a};d.Clipper.prototype.GetLowermostRec=function(a,b){null===a.BottomPt&&(a.BottomPt=this.GetBottomPt(a.Pts));null===b.BottomPt&&(b.BottomPt=this.GetBottomPt(b.Pts));var c=a.BottomPt,
|
||||
e=b.BottomPt;return c.Pt.Y>e.Pt.Y?a:c.Pt.Y<e.Pt.Y?b:c.Pt.X<e.Pt.X?a:c.Pt.X>e.Pt.X?b:c.Next==c?b:e.Next==e?a:this.FirstIsBottomPt(c,e)?a:b};d.Clipper.prototype.Param1RightOfParam2=function(a,b){do if(a=a.FirstLeft,a==b)return!0;while(null!==a);return!1};d.Clipper.prototype.GetOutRec=function(a){for(a=this.m_PolyOuts[a];a!=this.m_PolyOuts[a.Idx];)a=this.m_PolyOuts[a.Idx];return a};d.Clipper.prototype.AppendPolygon=function(a,b){var c=this.m_PolyOuts[a.OutIdx],e=this.m_PolyOuts[b.OutIdx],f;f=this.Param1RightOfParam2(c,
|
||||
e)?e:this.Param1RightOfParam2(e,c)?c:this.GetLowermostRec(c,e);var g=c.Pts,h=g.Prev,l=e.Pts,k=l.Prev;a.Side==d.EdgeSide.esLeft?(b.Side==d.EdgeSide.esLeft?(this.ReversePolyPtLinks(l),l.Next=g,g.Prev=l,h.Next=k,k.Prev=h,c.Pts=k):(k.Next=g,g.Prev=k,l.Prev=h,h.Next=l,c.Pts=l),g=d.EdgeSide.esLeft):(b.Side==d.EdgeSide.esRight?(this.ReversePolyPtLinks(l),h.Next=k,k.Prev=h,l.Next=g,g.Prev=l):(h.Next=l,l.Prev=h,g.Prev=k,k.Next=g),g=d.EdgeSide.esRight);c.BottomPt=null;f==e&&(e.FirstLeft!=c&&(c.FirstLeft=e.FirstLeft),
|
||||
c.IsHole=e.IsHole);e.Pts=null;e.BottomPt=null;e.FirstLeft=c;f=a.OutIdx;h=b.OutIdx;a.OutIdx=-1;b.OutIdx=-1;for(l=this.m_ActiveEdges;null!==l;){if(l.OutIdx==h){l.OutIdx=f;l.Side=g;break}l=l.NextInAEL}e.Idx=c.Idx};d.Clipper.prototype.ReversePolyPtLinks=function(a){if(null!==a){var b,c;b=a;do c=b.Next,b.Next=b.Prev,b=b.Prev=c;while(b!=a)}};d.Clipper.SwapSides=function(a,b){var c=a.Side;a.Side=b.Side;b.Side=c};d.Clipper.SwapPolyIndexes=function(a,b){var c=a.OutIdx;a.OutIdx=b.OutIdx;b.OutIdx=c};d.Clipper.prototype.IntersectEdges=
|
||||
function(a,b,c,e){var f=!e&&null===a.NextInLML&&a.Top.X==c.X&&a.Top.Y==c.Y;e=!e&&null===b.NextInLML&&b.Top.X==c.X&&b.Top.Y==c.Y;var g=0<=a.OutIdx,h=0<=b.OutIdx;if(0===a.WindDelta||0===b.WindDelta)0===a.WindDelta&&0===b.WindDelta?(f||e)&&g&&h&&this.AddLocalMaxPoly(a,b,c):a.PolyTyp==b.PolyTyp&&a.WindDelta!=b.WindDelta&&this.m_ClipType==d.ClipType.ctUnion?0===a.WindDelta?h&&(this.AddOutPt(a,c),g&&(a.OutIdx=-1)):g&&(this.AddOutPt(b,c),h&&(b.OutIdx=-1)):a.PolyTyp!=b.PolyTyp&&(0!==a.WindDelta||1!=Math.abs(b.WindCnt)||
|
||||
this.m_ClipType==d.ClipType.ctUnion&&0!==b.WindCnt2?0!==b.WindDelta||1!=Math.abs(a.WindCnt)||this.m_ClipType==d.ClipType.ctUnion&&0!==a.WindCnt2||(this.AddOutPt(b,c),h&&(b.OutIdx=-1)):(this.AddOutPt(a,c),g&&(a.OutIdx=-1))),f&&(0>a.OutIdx?this.DeleteFromAEL(a):d.Error("Error intersecting polylines")),e&&(0>b.OutIdx?this.DeleteFromAEL(b):d.Error("Error intersecting polylines"));else{if(a.PolyTyp==b.PolyTyp)if(this.IsEvenOddFillType(a)){var l=a.WindCnt;a.WindCnt=b.WindCnt;b.WindCnt=l}else a.WindCnt=
|
||||
0===a.WindCnt+b.WindDelta?-a.WindCnt:a.WindCnt+b.WindDelta,b.WindCnt=0===b.WindCnt-a.WindDelta?-b.WindCnt:b.WindCnt-a.WindDelta;else this.IsEvenOddFillType(b)?a.WindCnt2=0===a.WindCnt2?1:0:a.WindCnt2+=b.WindDelta,this.IsEvenOddFillType(a)?b.WindCnt2=0===b.WindCnt2?1:0:b.WindCnt2-=a.WindDelta;var k,n,m;a.PolyTyp==d.PolyType.ptSubject?(k=this.m_SubjFillType,m=this.m_ClipFillType):(k=this.m_ClipFillType,m=this.m_SubjFillType);b.PolyTyp==d.PolyType.ptSubject?(n=this.m_SubjFillType,l=this.m_ClipFillType):
|
||||
(n=this.m_ClipFillType,l=this.m_SubjFillType);switch(k){case d.PolyFillType.pftPositive:k=a.WindCnt;break;case d.PolyFillType.pftNegative:k=-a.WindCnt;break;default:k=Math.abs(a.WindCnt)}switch(n){case d.PolyFillType.pftPositive:n=b.WindCnt;break;case d.PolyFillType.pftNegative:n=-b.WindCnt;break;default:n=Math.abs(b.WindCnt)}if(g&&h)f||e||0!==k&&1!=k||0!==n&&1!=n||a.PolyTyp!=b.PolyTyp&&this.m_ClipType!=d.ClipType.ctXor?this.AddLocalMaxPoly(a,b,c):(this.AddOutPt(a,c),this.AddOutPt(b,c),d.Clipper.SwapSides(a,
|
||||
b),d.Clipper.SwapPolyIndexes(a,b));else if(g){if(0===n||1==n)this.AddOutPt(a,c),d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b)}else if(h){if(0===k||1==k)this.AddOutPt(b,c),d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b)}else if(!(0!==k&&1!=k||0!==n&&1!=n||f||e)){switch(m){case d.PolyFillType.pftPositive:g=a.WindCnt2;break;case d.PolyFillType.pftNegative:g=-a.WindCnt2;break;default:g=Math.abs(a.WindCnt2)}switch(l){case d.PolyFillType.pftPositive:h=b.WindCnt2;break;case d.PolyFillType.pftNegative:h=
|
||||
-b.WindCnt2;break;default:h=Math.abs(b.WindCnt2)}if(a.PolyTyp!=b.PolyTyp)this.AddLocalMinPoly(a,b,c);else if(1==k&&1==n)switch(this.m_ClipType){case d.ClipType.ctIntersection:0<g&&0<h&&this.AddLocalMinPoly(a,b,c);break;case d.ClipType.ctUnion:0>=g&&0>=h&&this.AddLocalMinPoly(a,b,c);break;case d.ClipType.ctDifference:(a.PolyTyp==d.PolyType.ptClip&&0<g&&0<h||a.PolyTyp==d.PolyType.ptSubject&&0>=g&&0>=h)&&this.AddLocalMinPoly(a,b,c);break;case d.ClipType.ctXor:this.AddLocalMinPoly(a,b,c)}else d.Clipper.SwapSides(a,
|
||||
b)}f!=e&&(f&&0<=a.OutIdx||e&&0<=b.OutIdx)&&(d.Clipper.SwapSides(a,b),d.Clipper.SwapPolyIndexes(a,b));f&&this.DeleteFromAEL(a);e&&this.DeleteFromAEL(b)}};d.Clipper.prototype.DeleteFromAEL=function(a){var b=a.PrevInAEL,c=a.NextInAEL;if(null!==b||null!==c||a==this.m_ActiveEdges)null!==b?b.NextInAEL=c:this.m_ActiveEdges=c,null!==c&&(c.PrevInAEL=b),a.NextInAEL=null,a.PrevInAEL=null};d.Clipper.prototype.DeleteFromSEL=function(a){var b=a.PrevInSEL,c=a.NextInSEL;if(null!==b||null!==c||a==this.m_SortedEdges)null!==
|
||||
b?b.NextInSEL=c:this.m_SortedEdges=c,null!==c&&(c.PrevInSEL=b),a.NextInSEL=null,a.PrevInSEL=null};d.Clipper.prototype.UpdateEdgeIntoAEL=function(a){null===a.NextInLML&&d.Error("UpdateEdgeIntoAEL: invalid call");var b=a.PrevInAEL,c=a.NextInAEL;a.NextInLML.OutIdx=a.OutIdx;null!==b?b.NextInAEL=a.NextInLML:this.m_ActiveEdges=a.NextInLML;null!==c&&(c.PrevInAEL=a.NextInLML);a.NextInLML.Side=a.Side;a.NextInLML.WindDelta=a.WindDelta;a.NextInLML.WindCnt=a.WindCnt;a.NextInLML.WindCnt2=a.WindCnt2;a=a.NextInLML;
|
||||
a.Curr.X=a.Bot.X;a.Curr.Y=a.Bot.Y;a.PrevInAEL=b;a.NextInAEL=c;d.ClipperBase.IsHorizontal(a)||this.InsertScanbeam(a.Top.Y);return a};d.Clipper.prototype.ProcessHorizontals=function(a){for(var b=this.m_SortedEdges;null!==b;)this.DeleteFromSEL(b),this.ProcessHorizontal(b,a),b=this.m_SortedEdges};d.Clipper.prototype.GetHorzDirection=function(a,b){a.Bot.X<a.Top.X?(b.Left=a.Bot.X,b.Right=a.Top.X,b.Dir=d.Direction.dLeftToRight):(b.Left=a.Top.X,b.Right=a.Bot.X,b.Dir=d.Direction.dRightToLeft)};d.Clipper.prototype.PrepareHorzJoins=
|
||||
function(a,b){var c=this.m_PolyOuts[a.OutIdx].Pts;a.Side!=d.EdgeSide.esLeft&&(c=c.Prev);b&&(d.IntPoint.op_Equality(c.Pt,a.Top)?this.AddGhostJoin(c,a.Bot):this.AddGhostJoin(c,a.Top))};d.Clipper.prototype.ProcessHorizontal=function(a,b){var c={Dir:null,Left:null,Right:null};this.GetHorzDirection(a,c);for(var e=c.Dir,f=c.Left,g=c.Right,h=a,l=null;null!==h.NextInLML&&d.ClipperBase.IsHorizontal(h.NextInLML);)h=h.NextInLML;for(null===h.NextInLML&&(l=this.GetMaximaPair(h));;){for(var k=a==h,n=this.GetNextInAEL(a,
|
||||
e);null!==n&&!(n.Curr.X==a.Top.X&&null!==a.NextInLML&&n.Dx<a.NextInLML.Dx);){c=this.GetNextInAEL(n,e);if(e==d.Direction.dLeftToRight&&n.Curr.X<=g||e==d.Direction.dRightToLeft&&n.Curr.X>=f){0<=a.OutIdx&&0!=a.WindDelta&&this.PrepareHorzJoins(a,b);if(n==l&&k){e==d.Direction.dLeftToRight?this.IntersectEdges(a,n,n.Top,!1):this.IntersectEdges(n,a,n.Top,!1);0<=l.OutIdx&&d.Error("ProcessHorizontal error");return}if(e==d.Direction.dLeftToRight){var m=new d.IntPoint(n.Curr.X,a.Curr.Y);this.IntersectEdges(a,
|
||||
n,m,!0)}else m=new d.IntPoint(n.Curr.X,a.Curr.Y),this.IntersectEdges(n,a,m,!0);this.SwapPositionsInAEL(a,n)}else if(e==d.Direction.dLeftToRight&&n.Curr.X>=g||e==d.Direction.dRightToLeft&&n.Curr.X<=f)break;n=c}0<=a.OutIdx&&0!==a.WindDelta&&this.PrepareHorzJoins(a,b);if(null!==a.NextInLML&&d.ClipperBase.IsHorizontal(a.NextInLML))a=this.UpdateEdgeIntoAEL(a),0<=a.OutIdx&&this.AddOutPt(a,a.Bot),c={Dir:e,Left:f,Right:g},this.GetHorzDirection(a,c),e=c.Dir,f=c.Left,g=c.Right;else break}null!==a.NextInLML?
|
||||
0<=a.OutIdx?(e=this.AddOutPt(a,a.Top),a=this.UpdateEdgeIntoAEL(a),0!==a.WindDelta&&(f=a.PrevInAEL,c=a.NextInAEL,null!==f&&f.Curr.X==a.Bot.X&&f.Curr.Y==a.Bot.Y&&0!==f.WindDelta&&0<=f.OutIdx&&f.Curr.Y>f.Top.Y&&d.ClipperBase.SlopesEqual(a,f,this.m_UseFullRange)?(c=this.AddOutPt(f,a.Bot),this.AddJoin(e,c,a.Top)):null!==c&&c.Curr.X==a.Bot.X&&c.Curr.Y==a.Bot.Y&&0!==c.WindDelta&&0<=c.OutIdx&&c.Curr.Y>c.Top.Y&&d.ClipperBase.SlopesEqual(a,c,this.m_UseFullRange)&&(c=this.AddOutPt(c,a.Bot),this.AddJoin(e,c,
|
||||
a.Top)))):this.UpdateEdgeIntoAEL(a):null!==l?0<=l.OutIdx?(e==d.Direction.dLeftToRight?this.IntersectEdges(a,l,a.Top,!1):this.IntersectEdges(l,a,a.Top,!1),0<=l.OutIdx&&d.Error("ProcessHorizontal error")):(this.DeleteFromAEL(a),this.DeleteFromAEL(l)):(0<=a.OutIdx&&this.AddOutPt(a,a.Top),this.DeleteFromAEL(a))};d.Clipper.prototype.GetNextInAEL=function(a,b){return b==d.Direction.dLeftToRight?a.NextInAEL:a.PrevInAEL};d.Clipper.prototype.IsMinima=function(a){return null!==a&&a.Prev.NextInLML!=a&&a.Next.NextInLML!=
|
||||
a};d.Clipper.prototype.IsMaxima=function(a,b){return null!==a&&a.Top.Y==b&&null===a.NextInLML};d.Clipper.prototype.IsIntermediate=function(a,b){return a.Top.Y==b&&null!==a.NextInLML};d.Clipper.prototype.GetMaximaPair=function(a){var b=null;d.IntPoint.op_Equality(a.Next.Top,a.Top)&&null===a.Next.NextInLML?b=a.Next:d.IntPoint.op_Equality(a.Prev.Top,a.Top)&&null===a.Prev.NextInLML&&(b=a.Prev);return null===b||-2!=b.OutIdx&&(b.NextInAEL!=b.PrevInAEL||d.ClipperBase.IsHorizontal(b))?b:null};d.Clipper.prototype.ProcessIntersections=
|
||||
function(a,b){if(null==this.m_ActiveEdges)return!0;try{this.BuildIntersectList(a,b);if(0==this.m_IntersectList.length)return!0;if(1==this.m_IntersectList.length||this.FixupIntersectionOrder())this.ProcessIntersectList();else return!1}catch(c){this.m_SortedEdges=null,this.m_IntersectList.length=0,d.Error("ProcessIntersections error")}this.m_SortedEdges=null;return!0};d.Clipper.prototype.BuildIntersectList=function(a,b){if(null!==this.m_ActiveEdges){var c=this.m_ActiveEdges;for(this.m_SortedEdges=c;null!==
|
||||
c;)c.PrevInSEL=c.PrevInAEL,c.NextInSEL=c.NextInAEL,c.Curr.X=d.Clipper.TopX(c,b),c=c.NextInAEL;for(var e=!0;e&&null!==this.m_SortedEdges;){e=!1;for(c=this.m_SortedEdges;null!==c.NextInSEL;){var f=c.NextInSEL,g=new d.IntPoint;c.Curr.X>f.Curr.X?(!this.IntersectPoint(c,f,g)&&c.Curr.X>f.Curr.X+1&&d.Error("Intersection error"),g.Y>a&&(g.Y=a,Math.abs(c.Dx)>Math.abs(f.Dx)?g.X=d.Clipper.TopX(f,a):g.X=d.Clipper.TopX(c,a)),e=new d.IntersectNode,e.Edge1=c,e.Edge2=f,e.Pt.X=g.X,e.Pt.Y=g.Y,this.m_IntersectList.push(e),
|
||||
this.SwapPositionsInSEL(c,f),e=!0):c=f}if(null!==c.PrevInSEL)c.PrevInSEL.NextInSEL=null;else break}this.m_SortedEdges=null}};d.Clipper.prototype.EdgesAdjacent=function(a){return a.Edge1.NextInSEL==a.Edge2||a.Edge1.PrevInSEL==a.Edge2};d.Clipper.IntersectNodeSort=function(a,b){return b.Pt.Y-a.Pt.Y};d.Clipper.prototype.FixupIntersectionOrder=function(){this.m_IntersectList.sort(this.m_IntersectNodeComparer);this.CopyAELToSEL();for(var a=this.m_IntersectList.length,b=0;b<a;b++){if(!this.EdgesAdjacent(this.m_IntersectList[b])){for(var c=
|
||||
b+1;c<a&&!this.EdgesAdjacent(this.m_IntersectList[c]);)c++;if(c==a)return!1;var e=this.m_IntersectList[b];this.m_IntersectList[b]=this.m_IntersectList[c];this.m_IntersectList[c]=e}this.SwapPositionsInSEL(this.m_IntersectList[b].Edge1,this.m_IntersectList[b].Edge2)}return!0};d.Clipper.prototype.ProcessIntersectList=function(){for(var a=0,b=this.m_IntersectList.length;a<b;a++){var c=this.m_IntersectList[a];this.IntersectEdges(c.Edge1,c.Edge2,c.Pt,!0);this.SwapPositionsInAEL(c.Edge1,c.Edge2)}this.m_IntersectList.length=
|
||||
0};E=function(a){return 0>a?Math.ceil(a-0.5):Math.round(a)};F=function(a){return 0>a?Math.ceil(a-0.5):Math.floor(a+0.5)};G=function(a){return 0>a?-Math.round(Math.abs(a)):Math.round(a)};H=function(a){if(0>a)return a-=0.5,-2147483648>a?Math.ceil(a):a|0;a+=0.5;return 2147483647<a?Math.floor(a):a|0};d.Clipper.Round=p?E:D?G:J?H:F;d.Clipper.TopX=function(a,b){return b==a.Top.Y?a.Top.X:a.Bot.X+d.Clipper.Round(a.Dx*(b-a.Bot.Y))};d.Clipper.prototype.IntersectPoint=function(a,b,c){c.X=0;c.Y=0;var e,f;if(d.ClipperBase.SlopesEqual(a,
|
||||
b,this.m_UseFullRange)||a.Dx==b.Dx)return b.Bot.Y>a.Bot.Y?(c.X=b.Bot.X,c.Y=b.Bot.Y):(c.X=a.Bot.X,c.Y=a.Bot.Y),!1;if(0===a.Delta.X)c.X=a.Bot.X,d.ClipperBase.IsHorizontal(b)?c.Y=b.Bot.Y:(f=b.Bot.Y-b.Bot.X/b.Dx,c.Y=d.Clipper.Round(c.X/b.Dx+f));else if(0===b.Delta.X)c.X=b.Bot.X,d.ClipperBase.IsHorizontal(a)?c.Y=a.Bot.Y:(e=a.Bot.Y-a.Bot.X/a.Dx,c.Y=d.Clipper.Round(c.X/a.Dx+e));else{e=a.Bot.X-a.Bot.Y*a.Dx;f=b.Bot.X-b.Bot.Y*b.Dx;var g=(f-e)/(a.Dx-b.Dx);c.Y=d.Clipper.Round(g);Math.abs(a.Dx)<Math.abs(b.Dx)?
|
||||
c.X=d.Clipper.Round(a.Dx*g+e):c.X=d.Clipper.Round(b.Dx*g+f)}if(c.Y<a.Top.Y||c.Y<b.Top.Y){if(a.Top.Y>b.Top.Y)return c.Y=a.Top.Y,c.X=d.Clipper.TopX(b,a.Top.Y),c.X<a.Top.X;c.Y=b.Top.Y;Math.abs(a.Dx)<Math.abs(b.Dx)?c.X=d.Clipper.TopX(a,c.Y):c.X=d.Clipper.TopX(b,c.Y)}return!0};d.Clipper.prototype.ProcessEdgesAtTopOfScanbeam=function(a){for(var b=this.m_ActiveEdges;null!==b;){var c=this.IsMaxima(b,a);c&&(c=this.GetMaximaPair(b),c=null===c||!d.ClipperBase.IsHorizontal(c));if(c){var e=b.PrevInAEL;this.DoMaxima(b);
|
||||
b=null===e?this.m_ActiveEdges:e.NextInAEL}else this.IsIntermediate(b,a)&&d.ClipperBase.IsHorizontal(b.NextInLML)?(b=this.UpdateEdgeIntoAEL(b),0<=b.OutIdx&&this.AddOutPt(b,b.Bot),this.AddEdgeToSEL(b)):(b.Curr.X=d.Clipper.TopX(b,a),b.Curr.Y=a),this.StrictlySimple&&(e=b.PrevInAEL,0<=b.OutIdx&&0!==b.WindDelta&&null!==e&&0<=e.OutIdx&&e.Curr.X==b.Curr.X&&0!==e.WindDelta&&(c=this.AddOutPt(e,b.Curr),e=this.AddOutPt(b,b.Curr),this.AddJoin(c,e,b.Curr))),b=b.NextInAEL}this.ProcessHorizontals(!0);for(b=this.m_ActiveEdges;null!==
|
||||
b;){if(this.IsIntermediate(b,a)){c=null;0<=b.OutIdx&&(c=this.AddOutPt(b,b.Top));var b=this.UpdateEdgeIntoAEL(b),e=b.PrevInAEL,f=b.NextInAEL;null!==e&&e.Curr.X==b.Bot.X&&e.Curr.Y==b.Bot.Y&&null!==c&&0<=e.OutIdx&&e.Curr.Y>e.Top.Y&&d.ClipperBase.SlopesEqual(b,e,this.m_UseFullRange)&&0!==b.WindDelta&&0!==e.WindDelta?(e=this.AddOutPt(e,b.Bot),this.AddJoin(c,e,b.Top)):null!==f&&f.Curr.X==b.Bot.X&&f.Curr.Y==b.Bot.Y&&null!==c&&0<=f.OutIdx&&f.Curr.Y>f.Top.Y&&d.ClipperBase.SlopesEqual(b,f,this.m_UseFullRange)&&
|
||||
0!==b.WindDelta&&0!==f.WindDelta&&(e=this.AddOutPt(f,b.Bot),this.AddJoin(c,e,b.Top))}b=b.NextInAEL}};d.Clipper.prototype.DoMaxima=function(a){var b=this.GetMaximaPair(a);if(null===b)0<=a.OutIdx&&this.AddOutPt(a,a.Top),this.DeleteFromAEL(a);else{for(var c=a.NextInAEL;null!==c&&c!=b;)this.IntersectEdges(a,c,a.Top,!0),this.SwapPositionsInAEL(a,c),c=a.NextInAEL;-1==a.OutIdx&&-1==b.OutIdx?(this.DeleteFromAEL(a),this.DeleteFromAEL(b)):0<=a.OutIdx&&0<=b.OutIdx?this.IntersectEdges(a,b,a.Top,!1):0===a.WindDelta?
|
||||
(0<=a.OutIdx&&(this.AddOutPt(a,a.Top),a.OutIdx=-1),this.DeleteFromAEL(a),0<=b.OutIdx&&(this.AddOutPt(b,a.Top),b.OutIdx=-1),this.DeleteFromAEL(b)):d.Error("DoMaxima error")}};d.Clipper.ReversePaths=function(a){for(var b=0,c=a.length;b<c;b++)a[b].reverse()};d.Clipper.Orientation=function(a){return 0<=d.Clipper.Area(a)};d.Clipper.prototype.PointCount=function(a){if(null===a)return 0;var b=0,c=a;do b++,c=c.Next;while(c!=a);return b};d.Clipper.prototype.BuildResult=function(a){d.Clear(a);for(var b=0,c=
|
||||
this.m_PolyOuts.length;b<c;b++){var e=this.m_PolyOuts[b];if(null!==e.Pts){var e=e.Pts.Prev,f=this.PointCount(e);if(!(2>f)){for(var g=Array(f),h=0;h<f;h++)g[h]=e.Pt,e=e.Prev;a.push(g)}}}};d.Clipper.prototype.BuildResult2=function(a){a.Clear();for(var b=0,c=this.m_PolyOuts.length;b<c;b++){var e=this.m_PolyOuts[b],f=this.PointCount(e.Pts);if(!(e.IsOpen&&2>f||!e.IsOpen&&3>f)){this.FixHoleLinkage(e);var g=new d.PolyNode;a.m_AllPolys.push(g);e.PolyNode=g;g.m_polygon.length=f;for(var e=e.Pts.Prev,h=0;h<
|
||||
f;h++)g.m_polygon[h]=e.Pt,e=e.Prev}}b=0;for(c=this.m_PolyOuts.length;b<c;b++)e=this.m_PolyOuts[b],null!==e.PolyNode&&(e.IsOpen?(e.PolyNode.IsOpen=!0,a.AddChild(e.PolyNode)):null!==e.FirstLeft&&null!=e.FirstLeft.PolyNode?e.FirstLeft.PolyNode.AddChild(e.PolyNode):a.AddChild(e.PolyNode))};d.Clipper.prototype.FixupOutPolygon=function(a){var b=null;a.BottomPt=null;for(var c=a.Pts;;){if(c.Prev==c||c.Prev==c.Next){this.DisposeOutPts(c);a.Pts=null;return}if(d.IntPoint.op_Equality(c.Pt,c.Next.Pt)||d.IntPoint.op_Equality(c.Pt,
|
||||
c.Prev.Pt)||d.ClipperBase.SlopesEqual(c.Prev.Pt,c.Pt,c.Next.Pt,this.m_UseFullRange)&&(!this.PreserveCollinear||!this.Pt2IsBetweenPt1AndPt3(c.Prev.Pt,c.Pt,c.Next.Pt)))b=null,c.Prev.Next=c.Next,c=c.Next.Prev=c.Prev;else if(c==b)break;else null===b&&(b=c),c=c.Next}a.Pts=c};d.Clipper.prototype.DupOutPt=function(a,b){var c=new d.OutPt;c.Pt.X=a.Pt.X;c.Pt.Y=a.Pt.Y;c.Idx=a.Idx;b?(c.Next=a.Next,c.Prev=a,a.Next.Prev=c,a.Next=c):(c.Prev=a.Prev,c.Next=a,a.Prev.Next=c,a.Prev=c);return c};d.Clipper.prototype.GetOverlap=
|
||||
function(a,b,c,e,d){a<b?c<e?(d.Left=Math.max(a,c),d.Right=Math.min(b,e)):(d.Left=Math.max(a,e),d.Right=Math.min(b,c)):c<e?(d.Left=Math.max(b,c),d.Right=Math.min(a,e)):(d.Left=Math.max(b,e),d.Right=Math.min(a,c));return d.Left<d.Right};d.Clipper.prototype.JoinHorz=function(a,b,c,e,f,g){var h=a.Pt.X>b.Pt.X?d.Direction.dRightToLeft:d.Direction.dLeftToRight;e=c.Pt.X>e.Pt.X?d.Direction.dRightToLeft:d.Direction.dLeftToRight;if(h==e)return!1;if(h==d.Direction.dLeftToRight){for(;a.Next.Pt.X<=f.X&&a.Next.Pt.X>=
|
||||
a.Pt.X&&a.Next.Pt.Y==f.Y;)a=a.Next;g&&a.Pt.X!=f.X&&(a=a.Next);b=this.DupOutPt(a,!g);d.IntPoint.op_Inequality(b.Pt,f)&&(a=b,a.Pt.X=f.X,a.Pt.Y=f.Y,b=this.DupOutPt(a,!g))}else{for(;a.Next.Pt.X>=f.X&&a.Next.Pt.X<=a.Pt.X&&a.Next.Pt.Y==f.Y;)a=a.Next;g||a.Pt.X==f.X||(a=a.Next);b=this.DupOutPt(a,g);d.IntPoint.op_Inequality(b.Pt,f)&&(a=b,a.Pt.X=f.X,a.Pt.Y=f.Y,b=this.DupOutPt(a,g))}if(e==d.Direction.dLeftToRight){for(;c.Next.Pt.X<=f.X&&c.Next.Pt.X>=c.Pt.X&&c.Next.Pt.Y==f.Y;)c=c.Next;g&&c.Pt.X!=f.X&&(c=c.Next);
|
||||
e=this.DupOutPt(c,!g);d.IntPoint.op_Inequality(e.Pt,f)&&(c=e,c.Pt.X=f.X,c.Pt.Y=f.Y,e=this.DupOutPt(c,!g))}else{for(;c.Next.Pt.X>=f.X&&c.Next.Pt.X<=c.Pt.X&&c.Next.Pt.Y==f.Y;)c=c.Next;g||c.Pt.X==f.X||(c=c.Next);e=this.DupOutPt(c,g);d.IntPoint.op_Inequality(e.Pt,f)&&(c=e,c.Pt.X=f.X,c.Pt.Y=f.Y,e=this.DupOutPt(c,g))}h==d.Direction.dLeftToRight==g?(a.Prev=c,c.Next=a,b.Next=e,e.Prev=b):(a.Next=c,c.Prev=a,b.Prev=e,e.Next=b);return!0};d.Clipper.prototype.JoinPoints=function(a,b,c){var e=a.OutPt1,f=new d.OutPt,
|
||||
g=a.OutPt2,h=new d.OutPt;if((h=a.OutPt1.Pt.Y==a.OffPt.Y)&&d.IntPoint.op_Equality(a.OffPt,a.OutPt1.Pt)&&d.IntPoint.op_Equality(a.OffPt,a.OutPt2.Pt)){for(f=a.OutPt1.Next;f!=e&&d.IntPoint.op_Equality(f.Pt,a.OffPt);)f=f.Next;f=f.Pt.Y>a.OffPt.Y;for(h=a.OutPt2.Next;h!=g&&d.IntPoint.op_Equality(h.Pt,a.OffPt);)h=h.Next;if(f==h.Pt.Y>a.OffPt.Y)return!1;f?(f=this.DupOutPt(e,!1),h=this.DupOutPt(g,!0),e.Prev=g,g.Next=e,f.Next=h,h.Prev=f):(f=this.DupOutPt(e,!0),h=this.DupOutPt(g,!1),e.Next=g,g.Prev=e,f.Prev=h,
|
||||
h.Next=f);a.OutPt1=e;a.OutPt2=f;return!0}if(h){for(f=e;e.Prev.Pt.Y==e.Pt.Y&&e.Prev!=f&&e.Prev!=g;)e=e.Prev;for(;f.Next.Pt.Y==f.Pt.Y&&f.Next!=e&&f.Next!=g;)f=f.Next;if(f.Next==e||f.Next==g)return!1;for(h=g;g.Prev.Pt.Y==g.Pt.Y&&g.Prev!=h&&g.Prev!=f;)g=g.Prev;for(;h.Next.Pt.Y==h.Pt.Y&&h.Next!=g&&h.Next!=e;)h=h.Next;if(h.Next==g||h.Next==e)return!1;c={Left:null,Right:null};if(!this.GetOverlap(e.Pt.X,f.Pt.X,g.Pt.X,h.Pt.X,c))return!1;b=c.Left;var l=c.Right;c=new d.IntPoint;e.Pt.X>=b&&e.Pt.X<=l?(c.X=e.Pt.X,
|
||||
c.Y=e.Pt.Y,b=e.Pt.X>f.Pt.X):g.Pt.X>=b&&g.Pt.X<=l?(c.X=g.Pt.X,c.Y=g.Pt.Y,b=g.Pt.X>h.Pt.X):f.Pt.X>=b&&f.Pt.X<=l?(c.X=f.Pt.X,c.Y=f.Pt.Y,b=f.Pt.X>e.Pt.X):(c.X=h.Pt.X,c.Y=h.Pt.Y,b=h.Pt.X>g.Pt.X);a.OutPt1=e;a.OutPt2=g;return this.JoinHorz(e,f,g,h,c,b)}for(f=e.Next;d.IntPoint.op_Equality(f.Pt,e.Pt)&&f!=e;)f=f.Next;if(l=f.Pt.Y>e.Pt.Y||!d.ClipperBase.SlopesEqual(e.Pt,f.Pt,a.OffPt,this.m_UseFullRange)){for(f=e.Prev;d.IntPoint.op_Equality(f.Pt,e.Pt)&&f!=e;)f=f.Prev;if(f.Pt.Y>e.Pt.Y||!d.ClipperBase.SlopesEqual(e.Pt,
|
||||
f.Pt,a.OffPt,this.m_UseFullRange))return!1}for(h=g.Next;d.IntPoint.op_Equality(h.Pt,g.Pt)&&h!=g;)h=h.Next;var k=h.Pt.Y>g.Pt.Y||!d.ClipperBase.SlopesEqual(g.Pt,h.Pt,a.OffPt,this.m_UseFullRange);if(k){for(h=g.Prev;d.IntPoint.op_Equality(h.Pt,g.Pt)&&h!=g;)h=h.Prev;if(h.Pt.Y>g.Pt.Y||!d.ClipperBase.SlopesEqual(g.Pt,h.Pt,a.OffPt,this.m_UseFullRange))return!1}if(f==e||h==g||f==h||b==c&&l==k)return!1;l?(f=this.DupOutPt(e,!1),h=this.DupOutPt(g,!0),e.Prev=g,g.Next=e,f.Next=h,h.Prev=f):(f=this.DupOutPt(e,!0),
|
||||
h=this.DupOutPt(g,!1),e.Next=g,g.Prev=e,f.Prev=h,h.Next=f);a.OutPt1=e;a.OutPt2=f;return!0};d.Clipper.GetBounds=function(a){for(var b=0,c=a.length;b<c&&0==a[b].length;)b++;if(b==c)return new d.IntRect(0,0,0,0);var e=new d.IntRect;e.left=a[b][0].X;e.right=e.left;e.top=a[b][0].Y;for(e.bottom=e.top;b<c;b++)for(var f=0,g=a[b].length;f<g;f++)a[b][f].X<e.left?e.left=a[b][f].X:a[b][f].X>e.right&&(e.right=a[b][f].X),a[b][f].Y<e.top?e.top=a[b][f].Y:a[b][f].Y>e.bottom&&(e.bottom=a[b][f].Y);return e};d.Clipper.prototype.GetBounds2=
|
||||
function(a){var b=a,c=new d.IntRect;c.left=a.Pt.X;c.right=a.Pt.X;c.top=a.Pt.Y;c.bottom=a.Pt.Y;for(a=a.Next;a!=b;)a.Pt.X<c.left&&(c.left=a.Pt.X),a.Pt.X>c.right&&(c.right=a.Pt.X),a.Pt.Y<c.top&&(c.top=a.Pt.Y),a.Pt.Y>c.bottom&&(c.bottom=a.Pt.Y),a=a.Next;return c};d.Clipper.PointInPolygon=function(a,b){var c=0,e=b.length;if(3>e)return 0;for(var d=b[0],g=1;g<=e;++g){var h=g==e?b[0]:b[g];if(h.Y==a.Y&&(h.X==a.X||d.Y==a.Y&&h.X>a.X==d.X<a.X))return-1;if(d.Y<a.Y!=h.Y<a.Y)if(d.X>=a.X)if(h.X>a.X)c=1-c;else{var l=
|
||||
(d.X-a.X)*(h.Y-a.Y)-(h.X-a.X)*(d.Y-a.Y);if(0==l)return-1;0<l==h.Y>d.Y&&(c=1-c)}else if(h.X>a.X){l=(d.X-a.X)*(h.Y-a.Y)-(h.X-a.X)*(d.Y-a.Y);if(0==l)return-1;0<l==h.Y>d.Y&&(c=1-c)}d=h}return c};d.Clipper.prototype.PointInPolygon=function(a,b){for(var c=0,e=b;;){var d=b.Pt.X,g=b.Pt.Y,h=b.Next.Pt.X,l=b.Next.Pt.Y;if(l==a.Y&&(h==a.X||g==a.Y&&h>a.X==d<a.X))return-1;if(g<a.Y!=l<a.Y)if(d>=a.X)if(h>a.X)c=1-c;else{d=(d-a.X)*(l-a.Y)-(h-a.X)*(g-a.Y);if(0==d)return-1;0<d==l>g&&(c=1-c)}else if(h>a.X){d=(d-a.X)*(l-
|
||||
a.Y)-(h-a.X)*(g-a.Y);if(0==d)return-1;0<d==l>g&&(c=1-c)}b=b.Next;if(e==b)break}return c};d.Clipper.prototype.Poly2ContainsPoly1=function(a,b){var c=a;do{var e=this.PointInPolygon(c.Pt,b);if(0<=e)return 0!=e;c=c.Next}while(c!=a);return!0};d.Clipper.prototype.FixupFirstLefts1=function(a,b){for(var c=0,e=this.m_PolyOuts.length;c<e;c++){var d=this.m_PolyOuts[c];null!==d.Pts&&d.FirstLeft==a&&this.Poly2ContainsPoly1(d.Pts,b.Pts)&&(d.FirstLeft=b)}};d.Clipper.prototype.FixupFirstLefts2=function(a,b){for(var c=
|
||||
0,e=this.m_PolyOuts,d=e.length,g=e[c];c<d;c++,g=e[c])g.FirstLeft==a&&(g.FirstLeft=b)};d.Clipper.ParseFirstLeft=function(a){for(;null!=a&&null==a.Pts;)a=a.FirstLeft;return a};d.Clipper.prototype.JoinCommonEdges=function(){for(var a=0,b=this.m_Joins.length;a<b;a++){var c=this.m_Joins[a],e=this.GetOutRec(c.OutPt1.Idx),f=this.GetOutRec(c.OutPt2.Idx);if(null!=e.Pts&&null!=f.Pts){var g;g=e==f?e:this.Param1RightOfParam2(e,f)?f:this.Param1RightOfParam2(f,e)?e:this.GetLowermostRec(e,f);if(this.JoinPoints(c,
|
||||
e,f))if(e==f){e.Pts=c.OutPt1;e.BottomPt=null;f=this.CreateOutRec();f.Pts=c.OutPt2;this.UpdateOutPtIdxs(f);if(this.m_UsingPolyTree){g=0;for(var h=this.m_PolyOuts.length;g<h-1;g++){var l=this.m_PolyOuts[g];null!=l.Pts&&d.Clipper.ParseFirstLeft(l.FirstLeft)==e&&l.IsHole!=e.IsHole&&this.Poly2ContainsPoly1(l.Pts,c.OutPt2)&&(l.FirstLeft=f)}}this.Poly2ContainsPoly1(f.Pts,e.Pts)?(f.IsHole=!e.IsHole,f.FirstLeft=e,this.m_UsingPolyTree&&this.FixupFirstLefts2(f,e),(f.IsHole^this.ReverseSolution)==0<this.Area(f)&&
|
||||
this.ReversePolyPtLinks(f.Pts)):this.Poly2ContainsPoly1(e.Pts,f.Pts)?(f.IsHole=e.IsHole,e.IsHole=!f.IsHole,f.FirstLeft=e.FirstLeft,e.FirstLeft=f,this.m_UsingPolyTree&&this.FixupFirstLefts2(e,f),(e.IsHole^this.ReverseSolution)==0<this.Area(e)&&this.ReversePolyPtLinks(e.Pts)):(f.IsHole=e.IsHole,f.FirstLeft=e.FirstLeft,this.m_UsingPolyTree&&this.FixupFirstLefts1(e,f))}else f.Pts=null,f.BottomPt=null,f.Idx=e.Idx,e.IsHole=g.IsHole,g==f&&(e.FirstLeft=f.FirstLeft),f.FirstLeft=e,this.m_UsingPolyTree&&this.FixupFirstLefts2(f,
|
||||
e)}}};d.Clipper.prototype.UpdateOutPtIdxs=function(a){var b=a.Pts;do b.Idx=a.Idx,b=b.Prev;while(b!=a.Pts)};d.Clipper.prototype.DoSimplePolygons=function(){for(var a=0;a<this.m_PolyOuts.length;){var b=this.m_PolyOuts[a++],c=b.Pts;if(null!==c){do{for(var e=c.Next;e!=b.Pts;){if(d.IntPoint.op_Equality(c.Pt,e.Pt)&&e.Next!=c&&e.Prev!=c){var f=c.Prev,g=e.Prev;c.Prev=g;g.Next=c;e.Prev=f;f.Next=e;b.Pts=c;f=this.CreateOutRec();f.Pts=e;this.UpdateOutPtIdxs(f);this.Poly2ContainsPoly1(f.Pts,b.Pts)?(f.IsHole=!b.IsHole,
|
||||
f.FirstLeft=b):this.Poly2ContainsPoly1(b.Pts,f.Pts)?(f.IsHole=b.IsHole,b.IsHole=!f.IsHole,f.FirstLeft=b.FirstLeft,b.FirstLeft=f):(f.IsHole=b.IsHole,f.FirstLeft=b.FirstLeft);e=c}e=e.Next}c=c.Next}while(c!=b.Pts)}}};d.Clipper.Area=function(a){var b=a.length;if(3>b)return 0;for(var c=0,e=0,d=b-1;e<b;++e)c+=(a[d].X+a[e].X)*(a[d].Y-a[e].Y),d=e;return 0.5*-c};d.Clipper.prototype.Area=function(a){var b=a.Pts;if(null==b)return 0;var c=0;do c+=(b.Prev.Pt.X+b.Pt.X)*(b.Prev.Pt.Y-b.Pt.Y),b=b.Next;while(b!=a.Pts);
|
||||
return 0.5*c};d.Clipper.SimplifyPolygon=function(a,b){var c=[],e=new d.Clipper(0);e.StrictlySimple=!0;e.AddPath(a,d.PolyType.ptSubject,!0);e.Execute(d.ClipType.ctUnion,c,b,b);return c};d.Clipper.SimplifyPolygons=function(a,b){"undefined"==typeof b&&(b=d.PolyFillType.pftEvenOdd);var c=[],e=new d.Clipper(0);e.StrictlySimple=!0;e.AddPaths(a,d.PolyType.ptSubject,!0);e.Execute(d.ClipType.ctUnion,c,b,b);return c};d.Clipper.DistanceSqrd=function(a,b){var c=a.X-b.X,e=a.Y-b.Y;return c*c+e*e};d.Clipper.DistanceFromLineSqrd=
|
||||
function(a,b,c){var e=b.Y-c.Y;c=c.X-b.X;b=e*b.X+c*b.Y;b=e*a.X+c*a.Y-b;return b*b/(e*e+c*c)};d.Clipper.SlopesNearCollinear=function(a,b,c,e){return d.Clipper.DistanceFromLineSqrd(b,a,c)<e};d.Clipper.PointsAreClose=function(a,b,c){var e=a.X-b.X;a=a.Y-b.Y;return e*e+a*a<=c};d.Clipper.ExcludeOp=function(a){var b=a.Prev;b.Next=a.Next;a.Next.Prev=b;b.Idx=0;return b};d.Clipper.CleanPolygon=function(a,b){"undefined"==typeof b&&(b=1.415);var c=a.length;if(0==c)return[];for(var e=Array(c),f=0;f<c;++f)e[f]=
|
||||
new d.OutPt;for(f=0;f<c;++f)e[f].Pt=a[f],e[f].Next=e[(f+1)%c],e[f].Next.Prev=e[f],e[f].Idx=0;f=b*b;for(e=e[0];0==e.Idx&&e.Next!=e.Prev;)d.Clipper.PointsAreClose(e.Pt,e.Prev.Pt,f)?(e=d.Clipper.ExcludeOp(e),c--):d.Clipper.PointsAreClose(e.Prev.Pt,e.Next.Pt,f)?(d.Clipper.ExcludeOp(e.Next),e=d.Clipper.ExcludeOp(e),c-=2):d.Clipper.SlopesNearCollinear(e.Prev.Pt,e.Pt,e.Next.Pt,f)?(e=d.Clipper.ExcludeOp(e),c--):(e.Idx=1,e=e.Next);3>c&&(c=0);for(var g=Array(c),f=0;f<c;++f)g[f]=new d.IntPoint(e.Pt),e=e.Next;
|
||||
return g};d.Clipper.CleanPolygons=function(a,b){for(var c=Array(a.length),e=0,f=a.length;e<f;e++)c[e]=d.Clipper.CleanPolygon(a[e],b);return c};d.Clipper.Minkowski=function(a,b,c,e){var f=e?1:0,g=a.length,h=b.length;e=[];if(c)for(c=0;c<h;c++){for(var l=Array(g),k=0,n=a.length,m=a[k];k<n;k++,m=a[k])l[k]=new d.IntPoint(b[c].X+m.X,b[c].Y+m.Y);e.push(l)}else for(c=0;c<h;c++){l=Array(g);k=0;n=a.length;for(m=a[k];k<n;k++,m=a[k])l[k]=new d.IntPoint(b[c].X-m.X,b[c].Y-m.Y);e.push(l)}a=[];for(c=0;c<h-1+f;c++)for(k=
|
||||
0;k<g;k++)b=[],b.push(e[c%h][k%g]),b.push(e[(c+1)%h][k%g]),b.push(e[(c+1)%h][(k+1)%g]),b.push(e[c%h][(k+1)%g]),d.Clipper.Orientation(b)||b.reverse(),a.push(b);f=new d.Clipper(0);f.AddPaths(a,d.PolyType.ptSubject,!0);f.Execute(d.ClipType.ctUnion,e,d.PolyFillType.pftNonZero,d.PolyFillType.pftNonZero);return e};d.Clipper.MinkowskiSum=function(){var a=arguments,b=a.length;if(3==b){var c=a[0],e=a[2];return d.Clipper.Minkowski(c,a[1],!0,e)}if(4==b){for(var c=a[0],f=a[1],b=a[2],e=a[3],a=new d.Clipper,g,
|
||||
h=0,l=f.length;h<l;++h)g=d.Clipper.Minkowski(c,f[h],!0,e),a.AddPaths(g,d.PolyType.ptSubject,!0);e&&a.AddPaths(f,d.PolyType.ptClip,!0);c=new d.Paths;a.Execute(d.ClipType.ctUnion,c,b,b);return c}};d.Clipper.MinkowskiDiff=function(a,b,c){return d.Clipper.Minkowski(a,b,!1,c)};d.Clipper.PolyTreeToPaths=function(a){var b=[];d.Clipper.AddPolyNodeToPaths(a,d.Clipper.NodeType.ntAny,b);return b};d.Clipper.AddPolyNodeToPaths=function(a,b,c){var e=!0;switch(b){case d.Clipper.NodeType.ntOpen:return;case d.Clipper.NodeType.ntClosed:e=
|
||||
!a.IsOpen}0<a.m_polygon.length&&e&&c.push(a.m_polygon);e=0;a=a.Childs();for(var f=a.length,g=a[e];e<f;e++,g=a[e])d.Clipper.AddPolyNodeToPaths(g,b,c)};d.Clipper.OpenPathsFromPolyTree=function(a){for(var b=new d.Paths,c=0,e=a.ChildCount();c<e;c++)a.Childs()[c].IsOpen&&b.push(a.Childs()[c].m_polygon);return b};d.Clipper.ClosedPathsFromPolyTree=function(a){var b=new d.Paths;d.Clipper.AddPolyNodeToPaths(a,d.Clipper.NodeType.ntClosed,b);return b};K(d.Clipper,d.ClipperBase);d.Clipper.NodeType={ntAny:0,ntOpen:1,
|
||||
ntClosed:2};d.ClipperOffset=function(a,b){"undefined"==typeof a&&(a=2);"undefined"==typeof b&&(b=d.ClipperOffset.def_arc_tolerance);this.m_destPolys=new d.Paths;this.m_srcPoly=new d.Path;this.m_destPoly=new d.Path;this.m_normals=[];this.m_StepsPerRad=this.m_miterLim=this.m_cos=this.m_sin=this.m_sinA=this.m_delta=0;this.m_lowest=new d.IntPoint;this.m_polyNodes=new d.PolyNode;this.MiterLimit=a;this.ArcTolerance=b;this.m_lowest.X=-1};d.ClipperOffset.two_pi=6.28318530717959;d.ClipperOffset.def_arc_tolerance=
|
||||
0.25;d.ClipperOffset.prototype.Clear=function(){d.Clear(this.m_polyNodes.Childs());this.m_lowest.X=-1};d.ClipperOffset.Round=d.Clipper.Round;d.ClipperOffset.prototype.AddPath=function(a,b,c){var e=a.length-1;if(!(0>e)){var f=new d.PolyNode;f.m_jointype=b;f.m_endtype=c;if(c==d.EndType.etClosedLine||c==d.EndType.etClosedPolygon)for(;0<e&&d.IntPoint.op_Equality(a[0],a[e]);)e--;f.m_polygon.push(a[0]);var g=0;b=0;for(var h=1;h<=e;h++)d.IntPoint.op_Inequality(f.m_polygon[g],a[h])&&(g++,f.m_polygon.push(a[h]),
|
||||
a[h].Y>f.m_polygon[b].Y||a[h].Y==f.m_polygon[b].Y&&a[h].X<f.m_polygon[b].X)&&(b=g);if(!(c==d.EndType.etClosedPolygon&&2>g||c!=d.EndType.etClosedPolygon&&0>g)&&(this.m_polyNodes.AddChild(f),c==d.EndType.etClosedPolygon))if(0>this.m_lowest.X)this.m_lowest=new d.IntPoint(0,b);else if(a=this.m_polyNodes.Childs()[this.m_lowest.X].m_polygon[this.m_lowest.Y],f.m_polygon[b].Y>a.Y||f.m_polygon[b].Y==a.Y&&f.m_polygon[b].X<a.X)this.m_lowest=new d.IntPoint(this.m_polyNodes.ChildCount()-1,b)}};d.ClipperOffset.prototype.AddPaths=
|
||||
function(a,b,c){for(var e=0,d=a.length;e<d;e++)this.AddPath(a[e],b,c)};d.ClipperOffset.prototype.FixOrientations=function(){if(0<=this.m_lowest.X&&!d.Clipper.Orientation(this.m_polyNodes.Childs()[this.m_lowest.X].m_polygon))for(var a=0;a<this.m_polyNodes.ChildCount();a++){var b=this.m_polyNodes.Childs()[a];(b.m_endtype==d.EndType.etClosedPolygon||b.m_endtype==d.EndType.etClosedLine&&d.Clipper.Orientation(b.m_polygon))&&b.m_polygon.reverse()}else for(a=0;a<this.m_polyNodes.ChildCount();a++)b=this.m_polyNodes.Childs()[a],
|
||||
b.m_endtype!=d.EndType.etClosedLine||d.Clipper.Orientation(b.m_polygon)||b.m_polygon.reverse()};d.ClipperOffset.GetUnitNormal=function(a,b){var c=b.X-a.X,e=b.Y-a.Y;if(0==c&&0==e)return new d.DoublePoint(0,0);var f=1/Math.sqrt(c*c+e*e);return new d.DoublePoint(e*f,-(c*f))};d.ClipperOffset.prototype.DoOffset=function(a){this.m_destPolys=[];this.m_delta=a;if(d.ClipperBase.near_zero(a))for(var b=0;b<this.m_polyNodes.ChildCount();b++){var c=this.m_polyNodes.Childs()[b];c.m_endtype==d.EndType.etClosedPolygon&&
|
||||
this.m_destPolys.push(c.m_polygon)}else{this.m_miterLim=2<this.MiterLimit?2/(this.MiterLimit*this.MiterLimit):0.5;var b=0>=this.ArcTolerance?d.ClipperOffset.def_arc_tolerance:this.ArcTolerance>Math.abs(a)*d.ClipperOffset.def_arc_tolerance?Math.abs(a)*d.ClipperOffset.def_arc_tolerance:this.ArcTolerance,e=3.14159265358979/Math.acos(1-b/Math.abs(a));this.m_sin=Math.sin(d.ClipperOffset.two_pi/e);this.m_cos=Math.cos(d.ClipperOffset.two_pi/e);this.m_StepsPerRad=e/d.ClipperOffset.two_pi;0>a&&(this.m_sin=
|
||||
-this.m_sin);for(b=0;b<this.m_polyNodes.ChildCount();b++){c=this.m_polyNodes.Childs()[b];this.m_srcPoly=c.m_polygon;var f=this.m_srcPoly.length;if(!(0==f||0>=a&&(3>f||c.m_endtype!=d.EndType.etClosedPolygon))){this.m_destPoly=[];if(1==f)if(c.m_jointype==d.JoinType.jtRound)for(var c=1,f=0,g=1;g<=e;g++){this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X+c*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y+f*a)));var h=c,c=c*this.m_cos-this.m_sin*f,f=h*this.m_sin+f*this.m_cos}else for(f=
|
||||
c=-1,g=0;4>g;++g)this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X+c*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y+f*a))),0>c?c=1:0>f?f=1:c=-1;else{for(g=this.m_normals.length=0;g<f-1;g++)this.m_normals.push(d.ClipperOffset.GetUnitNormal(this.m_srcPoly[g],this.m_srcPoly[g+1]));c.m_endtype==d.EndType.etClosedLine||c.m_endtype==d.EndType.etClosedPolygon?this.m_normals.push(d.ClipperOffset.GetUnitNormal(this.m_srcPoly[f-1],this.m_srcPoly[0])):this.m_normals.push(new d.DoublePoint(this.m_normals[f-
|
||||
2]));if(c.m_endtype==d.EndType.etClosedPolygon)for(h=f-1,g=0;g<f;g++)h=this.OffsetPoint(g,h,c.m_jointype);else if(c.m_endtype==d.EndType.etClosedLine){h=f-1;for(g=0;g<f;g++)h=this.OffsetPoint(g,h,c.m_jointype);this.m_destPolys.push(this.m_destPoly);this.m_destPoly=[];h=this.m_normals[f-1];for(g=f-1;0<g;g--)this.m_normals[g]=new d.DoublePoint(-this.m_normals[g-1].X,-this.m_normals[g-1].Y);this.m_normals[0]=new d.DoublePoint(-h.X,-h.Y);h=0;for(g=f-1;0<=g;g--)h=this.OffsetPoint(g,h,c.m_jointype)}else{h=
|
||||
0;for(g=1;g<f-1;++g)h=this.OffsetPoint(g,h,c.m_jointype);c.m_endtype==d.EndType.etOpenButt?(g=f-1,h=new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[g].X+this.m_normals[g].X*a),d.ClipperOffset.Round(this.m_srcPoly[g].Y+this.m_normals[g].Y*a)),this.m_destPoly.push(h),h=new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[g].X-this.m_normals[g].X*a),d.ClipperOffset.Round(this.m_srcPoly[g].Y-this.m_normals[g].Y*a)),this.m_destPoly.push(h)):(g=f-1,h=f-2,this.m_sinA=0,this.m_normals[g]=new d.DoublePoint(-this.m_normals[g].X,
|
||||
-this.m_normals[g].Y),c.m_endtype==d.EndType.etOpenSquare?this.DoSquare(g,h):this.DoRound(g,h));for(g=f-1;0<g;g--)this.m_normals[g]=new d.DoublePoint(-this.m_normals[g-1].X,-this.m_normals[g-1].Y);this.m_normals[0]=new d.DoublePoint(-this.m_normals[1].X,-this.m_normals[1].Y);h=f-1;for(g=h-1;0<g;--g)h=this.OffsetPoint(g,h,c.m_jointype);c.m_endtype==d.EndType.etOpenButt?(h=new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X-this.m_normals[0].X*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y-this.m_normals[0].Y*
|
||||
a)),this.m_destPoly.push(h),h=new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[0].X+this.m_normals[0].X*a),d.ClipperOffset.Round(this.m_srcPoly[0].Y+this.m_normals[0].Y*a)),this.m_destPoly.push(h)):(this.m_sinA=0,c.m_endtype==d.EndType.etOpenSquare?this.DoSquare(0,1):this.DoRound(0,1))}}this.m_destPolys.push(this.m_destPoly)}}}};d.ClipperOffset.prototype.Execute=function(){var a=arguments;if(a[0]instanceof d.PolyTree)if(b=a[0],c=a[1],b.Clear(),this.FixOrientations(),this.DoOffset(c),a=new d.Clipper(0),
|
||||
a.AddPaths(this.m_destPolys,d.PolyType.ptSubject,!0),0<c)a.Execute(d.ClipType.ctUnion,b,d.PolyFillType.pftPositive,d.PolyFillType.pftPositive);else if(c=d.Clipper.GetBounds(this.m_destPolys),e=new d.Path,e.push(new d.IntPoint(c.left-10,c.bottom+10)),e.push(new d.IntPoint(c.right+10,c.bottom+10)),e.push(new d.IntPoint(c.right+10,c.top-10)),e.push(new d.IntPoint(c.left-10,c.top-10)),a.AddPath(e,d.PolyType.ptSubject,!0),a.ReverseSolution=!0,a.Execute(d.ClipType.ctUnion,b,d.PolyFillType.pftNegative,d.PolyFillType.pftNegative),
|
||||
1==b.ChildCount()&&0<b.Childs()[0].ChildCount())for(a=b.Childs()[0],b.Childs()[0]=a.Childs()[0],c=1;c<a.ChildCount();c++)b.AddChild(a.Childs()[c]);else b.Clear();else{var b=a[0],c=a[1];d.Clear(b);this.FixOrientations();this.DoOffset(c);a=new d.Clipper(0);a.AddPaths(this.m_destPolys,d.PolyType.ptSubject,!0);if(0<c)a.Execute(d.ClipType.ctUnion,b,d.PolyFillType.pftPositive,d.PolyFillType.pftPositive);else{var c=d.Clipper.GetBounds(this.m_destPolys),e=new d.Path;e.push(new d.IntPoint(c.left-10,c.bottom+
|
||||
10));e.push(new d.IntPoint(c.right+10,c.bottom+10));e.push(new d.IntPoint(c.right+10,c.top-10));e.push(new d.IntPoint(c.left-10,c.top-10));a.AddPath(e,d.PolyType.ptSubject,!0);a.ReverseSolution=!0;a.Execute(d.ClipType.ctUnion,b,d.PolyFillType.pftNegative,d.PolyFillType.pftNegative);0<b.length&&b.splice(0,1)}}};d.ClipperOffset.prototype.OffsetPoint=function(a,b,c){this.m_sinA=this.m_normals[b].X*this.m_normals[a].Y-this.m_normals[a].X*this.m_normals[b].Y;if(5E-5>this.m_sinA&&-5E-5<this.m_sinA)return b;
|
||||
1<this.m_sinA?this.m_sinA=1:-1>this.m_sinA&&(this.m_sinA=-1);if(0>this.m_sinA*this.m_delta)this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_normals[b].X*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_normals[b].Y*this.m_delta))),this.m_destPoly.push(new d.IntPoint(this.m_srcPoly[a])),this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_normals[a].X*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_normals[a].Y*
|
||||
this.m_delta)));else switch(c){case d.JoinType.jtMiter:c=1+(this.m_normals[a].X*this.m_normals[b].X+this.m_normals[a].Y*this.m_normals[b].Y);c>=this.m_miterLim?this.DoMiter(a,b,c):this.DoSquare(a,b);break;case d.JoinType.jtSquare:this.DoSquare(a,b);break;case d.JoinType.jtRound:this.DoRound(a,b)}return a};d.ClipperOffset.prototype.DoSquare=function(a,b){var c=Math.tan(Math.atan2(this.m_sinA,this.m_normals[b].X*this.m_normals[a].X+this.m_normals[b].Y*this.m_normals[a].Y)/4);this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+
|
||||
this.m_delta*(this.m_normals[b].X-this.m_normals[b].Y*c)),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_delta*(this.m_normals[b].Y+this.m_normals[b].X*c))));this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_delta*(this.m_normals[a].X+this.m_normals[a].Y*c)),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_delta*(this.m_normals[a].Y-this.m_normals[a].X*c))))};d.ClipperOffset.prototype.DoMiter=function(a,b,c){c=this.m_delta/c;this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+
|
||||
(this.m_normals[b].X+this.m_normals[a].X)*c),d.ClipperOffset.Round(this.m_srcPoly[a].Y+(this.m_normals[b].Y+this.m_normals[a].Y)*c)))};d.ClipperOffset.prototype.DoRound=function(a,b){for(var c=Math.atan2(this.m_sinA,this.m_normals[b].X*this.m_normals[a].X+this.m_normals[b].Y*this.m_normals[a].Y),c=d.Cast_Int32(d.ClipperOffset.Round(this.m_StepsPerRad*Math.abs(c))),e=this.m_normals[b].X,f=this.m_normals[b].Y,g,h=0;h<c;++h)this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+
|
||||
e*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+f*this.m_delta))),g=e,e=e*this.m_cos-this.m_sin*f,f=g*this.m_sin+f*this.m_cos;this.m_destPoly.push(new d.IntPoint(d.ClipperOffset.Round(this.m_srcPoly[a].X+this.m_normals[a].X*this.m_delta),d.ClipperOffset.Round(this.m_srcPoly[a].Y+this.m_normals[a].Y*this.m_delta)))};d.Error=function(a){try{throw Error(a);}catch(b){alert(b.message)}};d.JS={};d.JS.AreaOfPolygon=function(a,b){b||(b=1);return d.Clipper.Area(a)/(b*b)};d.JS.AreaOfPolygons=function(a,
|
||||
b){b||(b=1);for(var c=0,e=0;e<a.length;e++)c+=d.Clipper.Area(a[e]);return c/(b*b)};d.JS.BoundsOfPath=function(a,b){return d.JS.BoundsOfPaths([a],b)};d.JS.BoundsOfPaths=function(a,b){b||(b=1);var c=d.Clipper.GetBounds(a);c.left/=b;c.bottom/=b;c.right/=b;c.top/=b;return c};d.JS.Clean=function(a,b){if(!(a instanceof Array))return[];var c=a[0]instanceof Array;a=d.JS.Clone(a);if("number"!=typeof b||null===b)return d.Error("Delta is not a number in Clean()."),a;if(0===a.length||1==a.length&&0===a[0].length||
|
||||
0>b)return a;c||(a=[a]);for(var e=a.length,f,g,h,l,k,n,m,p=[],q=0;q<e;q++)if(g=a[q],f=g.length,0!==f)if(3>f)h=g,p.push(h);else{h=g;l=b*b;k=g[0];for(m=n=1;m<f;m++)(g[m].X-k.X)*(g[m].X-k.X)+(g[m].Y-k.Y)*(g[m].Y-k.Y)<=l||(h[n]=g[m],k=g[m],n++);k=g[n-1];(g[0].X-k.X)*(g[0].X-k.X)+(g[0].Y-k.Y)*(g[0].Y-k.Y)<=l&&n--;n<f&&h.splice(n,f-n);h.length&&p.push(h)}!c&&p.length?p=p[0]:c||0!==p.length?c&&0===p.length&&(p=[[]]):p=[];return p};d.JS.Clone=function(a){if(!(a instanceof Array)||0===a.length)return[];if(1==
|
||||
a.length&&0===a[0].length)return[[]];var b=a[0]instanceof Array;b||(a=[a]);var c=a.length,e,d,g,h,l=Array(c);for(d=0;d<c;d++){e=a[d].length;h=Array(e);for(g=0;g<e;g++)h[g]={X:a[d][g].X,Y:a[d][g].Y};l[d]=h}b||(l=l[0]);return l};d.JS.Lighten=function(a,b){if(!(a instanceof Array))return[];if("number"!=typeof b||null===b)return d.Error("Tolerance is not a number in Lighten()."),d.JS.Clone(a);if(0===a.length||1==a.length&&0===a[0].length||0>b)return d.JS.Clone(a);a[0]instanceof Array||(a=[a]);var c,e,
|
||||
f,g,h,l,k,m,p,q,r,s,t,u,v,x=a.length,y=b*b,w=[];for(c=0;c<x;c++)if(f=a[c],l=f.length,0!=l){for(g=0;1E6>g;g++){h=[];l=f.length;f[l-1].X!=f[0].X||f[l-1].Y!=f[0].Y?(r=1,f.push({X:f[0].X,Y:f[0].Y}),l=f.length):r=0;q=[];for(e=0;e<l-2;e++){k=f[e];p=f[e+1];m=f[e+2];u=k.X;v=k.Y;k=m.X-u;s=m.Y-v;if(0!==k||0!==s)t=((p.X-u)*k+(p.Y-v)*s)/(k*k+s*s),1<t?(u=m.X,v=m.Y):0<t&&(u+=k*t,v+=s*t);k=p.X-u;s=p.Y-v;m=k*k+s*s;m<=y&&(q[e+1]=1,e++)}h.push({X:f[0].X,Y:f[0].Y});for(e=1;e<l-1;e++)q[e]||h.push({X:f[e].X,Y:f[e].Y});
|
||||
h.push({X:f[l-1].X,Y:f[l-1].Y});r&&f.pop();if(q.length)f=h;else break}l=h.length;h[l-1].X==h[0].X&&h[l-1].Y==h[0].Y&&h.pop();2<h.length&&w.push(h)}!a[0]instanceof Array&&(w=w[0]);"undefined"==typeof w&&(w=[[]]);return w};d.JS.PerimeterOfPath=function(a,b,c){if("undefined"==typeof a)return 0;var e=Math.sqrt,d=0,g,h,k=0,m=g=0;h=0;var n=a.length;if(2>n)return 0;b&&(a[n]=a[0],n++);for(;--n;)g=a[n],k=g.X,g=g.Y,h=a[n-1],m=h.X,h=h.Y,d+=e((k-m)*(k-m)+(g-h)*(g-h));b&&a.pop();return d/c};d.JS.PerimeterOfPaths=
|
||||
function(a,b,c){c||(c=1);for(var e=0,f=0;f<a.length;f++)e+=d.JS.PerimeterOfPath(a[f],b,c);return e};d.JS.ScaleDownPath=function(a,b){var c,d;b||(b=1);for(c=a.length;c--;)d=a[c],d.X/=b,d.Y/=b};d.JS.ScaleDownPaths=function(a,b){var c,d,f;b||(b=1);for(c=a.length;c--;)for(d=a[c].length;d--;)f=a[c][d],f.X/=b,f.Y/=b};d.JS.ScaleUpPath=function(a,b){var c,d,f=Math.round;b||(b=1);for(c=a.length;c--;)d=a[c],d.X=f(d.X*b),d.Y=f(d.Y*b)};d.JS.ScaleUpPaths=function(a,b){var c,d,f,g=Math.round;b||(b=1);for(c=a.length;c--;)for(d=
|
||||
a[c].length;d--;)f=a[c][d],f.X=g(f.X*b),f.Y=g(f.Y*b)};d.ExPolygons=function(){return[]};d.ExPolygon=function(){this.holes=this.outer=null};d.JS.AddOuterPolyNodeToExPolygons=function(a,b){var c=new d.ExPolygon;c.outer=a.Contour();var e=a.Childs(),f=e.length;c.holes=Array(f);var g,h,k,m,n;for(h=0;h<f;h++)for(g=e[h],c.holes[h]=g.Contour(),k=0,m=g.Childs(),n=m.length;k<n;k++)g=m[k],d.JS.AddOuterPolyNodeToExPolygons(g,b);b.push(c)};d.JS.ExPolygonsToPaths=function(a){var b,c,e,f,g=new d.Paths;b=0;for(e=
|
||||
a.length;b<e;b++)for(g.push(a[b].outer),c=0,f=a[b].holes.length;c<f;c++)g.push(a[b].holes[c]);return g};d.JS.PolyTreeToExPolygons=function(a){var b=new d.ExPolygons,c,e,f;c=0;e=a.Childs();for(f=e.length;c<f;c++)a=e[c],d.JS.AddOuterPolyNodeToExPolygons(a,b);return b}})();
|
||||
37
public/svgnest/util/domparser.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* inspired by https://gist.github.com/1129031 */
|
||||
/*global document, DOMParser*/
|
||||
|
||||
(function(DOMParser) {
|
||||
"use strict";
|
||||
|
||||
var
|
||||
proto = DOMParser.prototype
|
||||
, nativeParse = proto.parseFromString
|
||||
;
|
||||
|
||||
// Firefox/Opera/IE throw errors on unsupported types
|
||||
try {
|
||||
// WebKit returns null on unsupported types
|
||||
if ((new DOMParser()).parseFromString("", "text/html")) {
|
||||
// text/html parsing is natively supported
|
||||
return;
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
proto.parseFromString = function(markup, type) {
|
||||
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
|
||||
var
|
||||
doc = document.implementation.createHTMLDocument("")
|
||||
;
|
||||
if (markup.toLowerCase().indexOf('<!doctype') > -1) {
|
||||
doc.documentElement.innerHTML = markup;
|
||||
}
|
||||
else {
|
||||
doc.body.innerHTML = markup;
|
||||
}
|
||||
return doc;
|
||||
} else {
|
||||
return nativeParse.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}(DOMParser));
|
||||
11
public/svgnest/util/eval.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
var isNode = typeof module !== 'undefined' && module.exports;
|
||||
|
||||
if (isNode) {
|
||||
process.once('message', function (code) {
|
||||
eval(JSON.parse(code).data);
|
||||
});
|
||||
} else {
|
||||
self.onmessage = function (code) {
|
||||
eval(code.data);
|
||||
};
|
||||
}
|
||||
188
public/svgnest/util/filesaver.js
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* FileSaver.js
|
||||
* A saveAs() FileSaver implementation.
|
||||
* 1.3.2
|
||||
* 2016-06-16 18:25:19
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
* License: MIT
|
||||
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
/*global self */
|
||||
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
|
||||
|
||||
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||
|
||||
var saveAs = saveAs || (function(view) {
|
||||
"use strict";
|
||||
// IE <10 is explicitly unsupported
|
||||
if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
|
||||
return;
|
||||
}
|
||||
var
|
||||
doc = view.document
|
||||
// only get URL when necessary in case Blob.js hasn't overridden it yet
|
||||
, get_URL = function() {
|
||||
return view.URL || view.webkitURL || view;
|
||||
}
|
||||
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||
, can_use_save_link = "download" in save_link
|
||||
, click = function(node) {
|
||||
var event = new MouseEvent("click");
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
|
||||
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
|
||||
, throw_outside = function(ex) {
|
||||
(view.setImmediate || view.setTimeout)(function() {
|
||||
throw ex;
|
||||
}, 0);
|
||||
}
|
||||
, force_saveable_type = "application/octet-stream"
|
||||
// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
|
||||
, arbitrary_revoke_timeout = 1000 * 40 // in ms
|
||||
, revoke = function(file) {
|
||||
var revoker = function() {
|
||||
if (typeof file === "string") { // file is an object URL
|
||||
get_URL().revokeObjectURL(file);
|
||||
} else { // file is a File
|
||||
file.remove();
|
||||
}
|
||||
};
|
||||
setTimeout(revoker, arbitrary_revoke_timeout);
|
||||
}
|
||||
, dispatch = function(filesaver, event_types, event) {
|
||||
event_types = [].concat(event_types);
|
||||
var i = event_types.length;
|
||||
while (i--) {
|
||||
var listener = filesaver["on" + event_types[i]];
|
||||
if (typeof listener === "function") {
|
||||
try {
|
||||
listener.call(filesaver, event || filesaver);
|
||||
} catch (ex) {
|
||||
throw_outside(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
, auto_bom = function(blob) {
|
||||
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
, FileSaver = function(blob, name, no_auto_bom) {
|
||||
if (!no_auto_bom) {
|
||||
blob = auto_bom(blob);
|
||||
}
|
||||
// First try a.download, then web filesystem, then object URLs
|
||||
var
|
||||
filesaver = this
|
||||
, type = blob.type
|
||||
, force = type === force_saveable_type
|
||||
, object_url
|
||||
, dispatch_all = function() {
|
||||
dispatch(filesaver, "writestart progress write writeend".split(" "));
|
||||
}
|
||||
// on any filesys errors revert to saving with object URLs
|
||||
, fs_error = function() {
|
||||
if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
|
||||
// Safari doesn't allow downloading of blob urls
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
|
||||
var popup = view.open(url, '_blank');
|
||||
if(!popup) view.location.href = url;
|
||||
url=undefined; // release reference before dispatching
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
filesaver.readyState = filesaver.INIT;
|
||||
return;
|
||||
}
|
||||
// don't create more object URLs than needed
|
||||
if (!object_url) {
|
||||
object_url = get_URL().createObjectURL(blob);
|
||||
}
|
||||
if (force) {
|
||||
view.location.href = object_url;
|
||||
} else {
|
||||
var opened = view.open(object_url, "_blank");
|
||||
if (!opened) {
|
||||
// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
|
||||
view.location.href = object_url;
|
||||
}
|
||||
}
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
revoke(object_url);
|
||||
}
|
||||
;
|
||||
filesaver.readyState = filesaver.INIT;
|
||||
|
||||
if (can_use_save_link) {
|
||||
object_url = get_URL().createObjectURL(blob);
|
||||
setTimeout(function() {
|
||||
save_link.href = object_url;
|
||||
save_link.download = name;
|
||||
click(save_link);
|
||||
dispatch_all();
|
||||
revoke(object_url);
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fs_error();
|
||||
}
|
||||
, FS_proto = FileSaver.prototype
|
||||
, saveAs = function(blob, name, no_auto_bom) {
|
||||
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
|
||||
}
|
||||
;
|
||||
// IE 10+ (native saveAs)
|
||||
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
|
||||
return function(blob, name, no_auto_bom) {
|
||||
name = name || blob.name || "download";
|
||||
|
||||
if (!no_auto_bom) {
|
||||
blob = auto_bom(blob);
|
||||
}
|
||||
return navigator.msSaveOrOpenBlob(blob, name);
|
||||
};
|
||||
}
|
||||
|
||||
FS_proto.abort = function(){};
|
||||
FS_proto.readyState = FS_proto.INIT = 0;
|
||||
FS_proto.WRITING = 1;
|
||||
FS_proto.DONE = 2;
|
||||
|
||||
FS_proto.error =
|
||||
FS_proto.onwritestart =
|
||||
FS_proto.onprogress =
|
||||
FS_proto.onwrite =
|
||||
FS_proto.onabort =
|
||||
FS_proto.onerror =
|
||||
FS_proto.onwriteend =
|
||||
null;
|
||||
|
||||
return saveAs;
|
||||
}(
|
||||
typeof self !== "undefined" && self
|
||||
|| typeof window !== "undefined" && window
|
||||
|| this.content
|
||||
));
|
||||
// `self` is undefined in Firefox for Android content script context
|
||||
// while `this` is nsIContentFrameMessageManager
|
||||
// with an attribute `content` that corresponds to the window
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports.saveAs = saveAs;
|
||||
} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
|
||||
define("FileSaver.js", function() {
|
||||
return saveAs;
|
||||
});
|
||||
}
|
||||
1891
public/svgnest/util/geometryutil.js
Normal file
1
public/svgnest/util/json.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
var JSON;if(!JSON){JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==="string"){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
|
||||
156
public/svgnest/util/matrix.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// matrix utility from SvgPath
|
||||
// https://github.com/fontello/svgpath
|
||||
|
||||
'use strict';
|
||||
|
||||
function Matrix() {
|
||||
if (!(this instanceof Matrix)) { return new Matrix(); }
|
||||
this.queue = []; // list of matrixes to apply
|
||||
this.cache = null; // combined matrix cache
|
||||
}
|
||||
(typeof window !== 'undefined' ? window : self).Matrix = Matrix;
|
||||
|
||||
// combine 2 matrixes
|
||||
// m1, m2 - [a, b, c, d, e, g]
|
||||
//
|
||||
Matrix.prototype.combine = function(m1, m2) {
|
||||
return [
|
||||
m1[0] * m2[0] + m1[2] * m2[1],
|
||||
m1[1] * m2[0] + m1[3] * m2[1],
|
||||
m1[0] * m2[2] + m1[2] * m2[3],
|
||||
m1[1] * m2[2] + m1[3] * m2[3],
|
||||
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
||||
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
||||
];
|
||||
}
|
||||
|
||||
Matrix.prototype.isIdentity = function(){
|
||||
if (!this.cache) {
|
||||
this.cache = this.toArray();
|
||||
}
|
||||
|
||||
var m = this.cache;
|
||||
|
||||
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Matrix.prototype.matrix = function (m) {
|
||||
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
|
||||
return this;
|
||||
}
|
||||
this.cache = null;
|
||||
this.queue.push(m);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Matrix.prototype.translate = function (tx, ty) {
|
||||
if (tx !== 0 || ty !== 0) {
|
||||
this.cache = null;
|
||||
this.queue.push([ 1, 0, 0, 1, tx, ty ]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Matrix.prototype.scale = function (sx, sy) {
|
||||
if (sx !== 1 || sy !== 1) {
|
||||
this.cache = null;
|
||||
this.queue.push([ sx, 0, 0, sy, 0, 0 ]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Matrix.prototype.rotate = function (angle, rx, ry) {
|
||||
var rad, cos, sin;
|
||||
|
||||
if (angle !== 0) {
|
||||
this.translate(rx, ry);
|
||||
|
||||
rad = angle * Math.PI / 180;
|
||||
cos = Math.cos(rad);
|
||||
sin = Math.sin(rad);
|
||||
|
||||
this.queue.push([ cos, sin, -sin, cos, 0, 0 ]);
|
||||
this.cache = null;
|
||||
|
||||
this.translate(-rx, -ry);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Matrix.prototype.skewX = function (angle) {
|
||||
if (angle !== 0) {
|
||||
this.cache = null;
|
||||
this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Matrix.prototype.skewY = function (angle) {
|
||||
if (angle !== 0) {
|
||||
this.cache = null;
|
||||
this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
// Flatten queue
|
||||
//
|
||||
Matrix.prototype.toArray = function () {
|
||||
if (this.cache) {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
if (!this.queue.length) {
|
||||
this.cache = [ 1, 0, 0, 1, 0, 0 ];
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
this.cache = this.queue[0];
|
||||
|
||||
if (this.queue.length === 1) {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
for (var i = 1; i < this.queue.length; i++) {
|
||||
this.cache = this.combine(this.cache, this.queue[i]);
|
||||
}
|
||||
|
||||
return this.cache;
|
||||
};
|
||||
|
||||
|
||||
// Apply list of matrixes to (x,y) point.
|
||||
// If `isRelative` set, `translate` component of matrix will be skipped
|
||||
//
|
||||
Matrix.prototype.calc = function (x, y, isRelative) {
|
||||
var m, i, len;
|
||||
|
||||
// Don't change point on empty transforms queue
|
||||
if (!this.queue.length) { return [ x, y ]; }
|
||||
|
||||
// Calculate final matrix, if not exists
|
||||
//
|
||||
// NB. if you deside to apply transforms to point one-by-one,
|
||||
// they should be taken in reverse order
|
||||
|
||||
if (!this.cache) {
|
||||
this.cache = this.toArray();
|
||||
}
|
||||
|
||||
m = this.cache;
|
||||
|
||||
// Apply matrix to point
|
||||
return [
|
||||
x * m[0] + y * m[2] + (isRelative ? 0 : m[4]),
|
||||
x * m[1] + y * m[3] + (isRelative ? 0 : m[5])
|
||||
];
|
||||
};
|
||||
386
public/svgnest/util/parallel.js
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
(function (root) {
|
||||
var isCommonJS = typeof module !== 'undefined' && module.exports;
|
||||
var isNode = !(typeof window !== 'undefined' && root === window);
|
||||
var setImmediate = setImmediate || function (cb) {
|
||||
setTimeout(cb, 0);
|
||||
};
|
||||
var Worker = isNode ? require(__dirname + '/Worker.js') : root.Worker;
|
||||
var URL = typeof root !== 'undefined' ? (root.URL ? root.URL : root.webkitURL) : null;
|
||||
var _supports = (isNode || root.Worker) ? true : false; // node always supports parallel
|
||||
|
||||
function extend(from, to) {
|
||||
if (!to) to = {};
|
||||
for (var i in from) {
|
||||
if (to[i] === undefined) to[i] = from[i];
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
function Operation() {
|
||||
this._callbacks = [];
|
||||
this._errCallbacks = [];
|
||||
|
||||
this._resolved = 0;
|
||||
this._result = null;
|
||||
}
|
||||
|
||||
Operation.prototype.resolve = function (err, res) {
|
||||
if (!err) {
|
||||
this._resolved = 1;
|
||||
this._result = res;
|
||||
|
||||
for (var i = 0; i < this._callbacks.length; ++i) {
|
||||
this._callbacks[i](res);
|
||||
}
|
||||
} else {
|
||||
this._resolved = 2;
|
||||
this._result = err;
|
||||
|
||||
for (var iE = 0; iE < this._errCallbacks.length; ++iE) {
|
||||
this._errCallbacks[iE](err);
|
||||
}
|
||||
}
|
||||
|
||||
this._callbacks = [];
|
||||
this._errCallbacks = [];
|
||||
};
|
||||
|
||||
Operation.prototype.then = function (cb, errCb) {
|
||||
if (this._resolved === 1) { // result
|
||||
if (cb) {
|
||||
cb(this._result);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (this._resolved === 2) { // error
|
||||
if (errCb) {
|
||||
errCb(this._result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
this._callbacks[this._callbacks.length] = cb;
|
||||
}
|
||||
|
||||
if (errCb) {
|
||||
this._errCallbacks[this._errCallbacks.length] = errCb;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
var defaults = {
|
||||
evalPath: isNode ? __dirname + '/eval.js' : null,
|
||||
maxWorkers: isNode ? require('os').cpus().length : (navigator.hardwareConcurrency || 4),
|
||||
synchronous: true,
|
||||
env: {},
|
||||
envNamespace: 'env'
|
||||
};
|
||||
|
||||
function Parallel(data, options) {
|
||||
this.data = data;
|
||||
this.options = extend(defaults, options);
|
||||
this.operation = new Operation();
|
||||
this.operation.resolve(null, this.data);
|
||||
this.requiredScripts = [];
|
||||
this.requiredFunctions = [];
|
||||
}
|
||||
|
||||
// static method
|
||||
Parallel.isSupported = function () { return _supports; }
|
||||
|
||||
Parallel.prototype.getWorkerSource = function (cb, env) {
|
||||
var that = this;
|
||||
var preStr = '';
|
||||
var i = 0;
|
||||
if (!isNode && this.requiredScripts.length !== 0) {
|
||||
preStr += 'importScripts("' + this.requiredScripts.join('","') + '");\r\n';
|
||||
}
|
||||
|
||||
for (i = 0; i < this.requiredFunctions.length; ++i) {
|
||||
if (this.requiredFunctions[i].name) {
|
||||
preStr += 'var ' + this.requiredFunctions[i].name + ' = ' + this.requiredFunctions[i].fn.toString() + ';';
|
||||
} else {
|
||||
preStr += this.requiredFunctions[i].fn.toString();
|
||||
}
|
||||
}
|
||||
|
||||
env = JSON.stringify(env || {});
|
||||
|
||||
var ns = this.options.envNamespace;
|
||||
|
||||
if (isNode) {
|
||||
return preStr + 'process.on("message", function(e) {global.' + ns + ' = ' + env + ';process.send(JSON.stringify((' + cb.toString() + ')(JSON.parse(e).data)))})';
|
||||
} else {
|
||||
return preStr + 'self.onmessage = function(e) {var global = {}; global.' + ns + ' = ' + env + ';self.postMessage((' + cb.toString() + ')(e.data))}';
|
||||
}
|
||||
};
|
||||
|
||||
Parallel.prototype.require = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 0),
|
||||
func;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
func = args[i];
|
||||
|
||||
if (typeof func === 'string') {
|
||||
this.requiredScripts.push(func);
|
||||
} else if (typeof func === 'function') {
|
||||
this.requiredFunctions.push({ fn: func });
|
||||
} else if (typeof func === 'object') {
|
||||
this.requiredFunctions.push(func);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Parallel.prototype._spawnWorker = function (cb, env) {
|
||||
var wrk;
|
||||
var src = this.getWorkerSource(cb, env);
|
||||
if (isNode) {
|
||||
wrk = new Worker(this.options.evalPath);
|
||||
wrk.postMessage(src);
|
||||
} else {
|
||||
if (Worker === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.requiredScripts.length !== 0) {
|
||||
if (this.options.evalPath !== null) {
|
||||
wrk = new Worker(this.options.evalPath);
|
||||
wrk.postMessage(src);
|
||||
} else {
|
||||
throw new Error('Can\'t use required scripts without eval.js!');
|
||||
}
|
||||
} else if (!URL) {
|
||||
throw new Error('Can\'t create a blob URL in this browser!');
|
||||
} else {
|
||||
var blob = new Blob([src], { type: 'text/javascript' });
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
wrk = new Worker(url);
|
||||
}
|
||||
} catch (e) {
|
||||
if (this.options.evalPath !== null) { // blob/url unsupported, cross-origin error
|
||||
wrk = new Worker(this.options.evalPath);
|
||||
wrk.postMessage(src);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wrk;
|
||||
};
|
||||
|
||||
Parallel.prototype.spawn = function (cb, env) {
|
||||
var that = this;
|
||||
var newOp = new Operation();
|
||||
|
||||
env = extend(this.options.env, env || {});
|
||||
|
||||
this.operation.then(function () {
|
||||
var wrk = that._spawnWorker(cb, env);
|
||||
if (wrk !== undefined) {
|
||||
wrk.onmessage = function (msg) {
|
||||
wrk.terminate();
|
||||
that.data = msg.data;
|
||||
newOp.resolve(null, that.data);
|
||||
};
|
||||
wrk.onerror = function (e) {
|
||||
wrk.terminate();
|
||||
newOp.resolve(e, null);
|
||||
};
|
||||
wrk.postMessage(that.data);
|
||||
} else if (that.options.synchronous) {
|
||||
setImmediate(function () {
|
||||
try {
|
||||
that.data = cb(that.data);
|
||||
newOp.resolve(null, that.data);
|
||||
} catch (e) {
|
||||
newOp.resolve(e, null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Error('Workers do not exist and synchronous operation not allowed!');
|
||||
}
|
||||
});
|
||||
this.operation = newOp;
|
||||
return this;
|
||||
};
|
||||
|
||||
Parallel.prototype._spawnMapWorker = function (i, cb, done, env, wrk) {
|
||||
var that = this;
|
||||
|
||||
if (!wrk) wrk = that._spawnWorker(cb, env);
|
||||
|
||||
if (wrk !== undefined) {
|
||||
wrk.onmessage = function (msg) {
|
||||
that.data[i] = msg.data;
|
||||
done(null, wrk);
|
||||
};
|
||||
wrk.onerror = function (e) {
|
||||
wrk.terminate();
|
||||
done(e);
|
||||
};
|
||||
wrk.postMessage(that.data[i]);
|
||||
} else if (that.options.synchronous) {
|
||||
setImmediate(function () {
|
||||
that.data[i] = cb(that.data[i]);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
throw new Error('Workers do not exist and synchronous operation not allowed!');
|
||||
}
|
||||
};
|
||||
|
||||
Parallel.prototype.map = function (cb, env) {
|
||||
env = extend(this.options.env, env || {});
|
||||
|
||||
if (!this.data.length) {
|
||||
return this.spawn(cb, env);
|
||||
}
|
||||
|
||||
var that = this;
|
||||
var startedOps = 0;
|
||||
var doneOps = 0;
|
||||
function done(err, wrk) {
|
||||
if (err) {
|
||||
newOp.resolve(err, null);
|
||||
} else if (++doneOps === that.data.length) {
|
||||
newOp.resolve(null, that.data);
|
||||
if (wrk) wrk.terminate();
|
||||
} else if (startedOps < that.data.length) {
|
||||
that._spawnMapWorker(startedOps++, cb, done, env, wrk);
|
||||
} else {
|
||||
if (wrk) wrk.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
var newOp = new Operation();
|
||||
this.operation.then(function () {
|
||||
for (; startedOps - doneOps < that.options.maxWorkers && startedOps < that.data.length; ++startedOps) {
|
||||
that._spawnMapWorker(startedOps, cb, done, env);
|
||||
}
|
||||
}, function (err) {
|
||||
newOp.resolve(err, null);
|
||||
});
|
||||
this.operation = newOp;
|
||||
return this;
|
||||
};
|
||||
|
||||
Parallel.prototype._spawnReduceWorker = function (data, cb, done, env, wrk) {
|
||||
var that = this;
|
||||
if (!wrk) wrk = that._spawnWorker(cb, env);
|
||||
|
||||
if (wrk !== undefined) {
|
||||
wrk.onmessage = function (msg) {
|
||||
that.data[that.data.length] = msg.data;
|
||||
done(null, wrk);
|
||||
};
|
||||
wrk.onerror = function (e) {
|
||||
wrk.terminate();
|
||||
done(e, null);
|
||||
}
|
||||
wrk.postMessage(data);
|
||||
} else if (that.options.synchronous) {
|
||||
setImmediate(function () {
|
||||
that.data[that.data.length] = cb(data);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
throw new Error('Workers do not exist and synchronous operation not allowed!');
|
||||
}
|
||||
};
|
||||
|
||||
Parallel.prototype.reduce = function (cb, env) {
|
||||
env = extend(this.options.env, env || {});
|
||||
|
||||
if (!this.data.length) {
|
||||
throw new Error('Can\'t reduce non-array data');
|
||||
}
|
||||
|
||||
var runningWorkers = 0;
|
||||
var that = this;
|
||||
function done(err, wrk) {
|
||||
--runningWorkers;
|
||||
if (err) {
|
||||
newOp.resolve(err, null);
|
||||
} else if (that.data.length === 1 && runningWorkers === 0) {
|
||||
that.data = that.data[0];
|
||||
newOp.resolve(null, that.data);
|
||||
if (wrk) wrk.terminate();
|
||||
} else if (that.data.length > 1) {
|
||||
++runningWorkers;
|
||||
that._spawnReduceWorker([that.data[0], that.data[1]], cb, done, env, wrk);
|
||||
that.data.splice(0, 2);
|
||||
} else {
|
||||
if (wrk) wrk.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
var newOp = new Operation();
|
||||
this.operation.then(function () {
|
||||
if (that.data.length === 1) {
|
||||
newOp.resolve(null, that.data[0]);
|
||||
} else {
|
||||
for (var i = 0; i < that.options.maxWorkers && i < Math.floor(that.data.length / 2) ; ++i) {
|
||||
++runningWorkers;
|
||||
that._spawnReduceWorker([that.data[i * 2], that.data[i * 2 + 1]], cb, done, env);
|
||||
}
|
||||
|
||||
that.data.splice(0, i * 2);
|
||||
}
|
||||
});
|
||||
this.operation = newOp;
|
||||
return this;
|
||||
};
|
||||
|
||||
Parallel.prototype.then = function (cb, errCb) {
|
||||
var that = this;
|
||||
var newOp = new Operation();
|
||||
errCb = typeof errCb === 'function' ? errCb : function(){};
|
||||
|
||||
this.operation.then(function () {
|
||||
var retData;
|
||||
|
||||
try {
|
||||
if (cb) {
|
||||
retData = cb(that.data);
|
||||
if (retData !== undefined) {
|
||||
that.data = retData;
|
||||
}
|
||||
}
|
||||
newOp.resolve(null, that.data);
|
||||
} catch (e) {
|
||||
if (errCb) {
|
||||
retData = errCb(e);
|
||||
if (retData !== undefined) {
|
||||
that.data = retData;
|
||||
}
|
||||
|
||||
newOp.resolve(null, that.data);
|
||||
} else {
|
||||
newOp.resolve(null, e);
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
if (errCb) {
|
||||
var retData = errCb(err);
|
||||
if (retData !== undefined) {
|
||||
that.data = retData;
|
||||
}
|
||||
|
||||
newOp.resolve(null, that.data);
|
||||
} else {
|
||||
newOp.resolve(null, err);
|
||||
}
|
||||
});
|
||||
this.operation = newOp;
|
||||
return this;
|
||||
};
|
||||
|
||||
root.Parallel = Parallel;
|
||||
})(typeof window !== 'undefined' ? window : self);
|
||||
849
public/svgnest/util/pathsegpolyfill.js
Normal file
|
|
@ -0,0 +1,849 @@
|
|||
// SVGPathSeg API polyfill
|
||||
// https://github.com/progers/pathseg
|
||||
//
|
||||
// This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from
|
||||
// SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec
|
||||
// changes which were implemented in Firefox 43 and Chrome 46.
|
||||
|
||||
(function() { "use strict";
|
||||
if (!("SVGPathSeg" in window)) {
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
|
||||
window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) {
|
||||
this.pathSegType = type;
|
||||
this.pathSegTypeAsLetter = typeAsLetter;
|
||||
this._owningPathSegList = owningPathSegList;
|
||||
}
|
||||
|
||||
window.SVGPathSeg.prototype.classname = "SVGPathSeg";
|
||||
|
||||
window.SVGPathSeg.PATHSEG_UNKNOWN = 0;
|
||||
window.SVGPathSeg.PATHSEG_CLOSEPATH = 1;
|
||||
window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
|
||||
window.SVGPathSeg.PATHSEG_MOVETO_REL = 3;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_ABS = 4;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_REL = 5;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
|
||||
window.SVGPathSeg.PATHSEG_ARC_ABS = 10;
|
||||
window.SVGPathSeg.PATHSEG_ARC_REL = 11;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
|
||||
|
||||
// Notify owning PathSegList on any changes so they can be synchronized back to the path element.
|
||||
window.SVGPathSeg.prototype._segmentChanged = function() {
|
||||
if (this._owningPathSegList)
|
||||
this._owningPathSegList.segmentChanged(this);
|
||||
}
|
||||
|
||||
window.SVGPathSegClosePath = function(owningPathSegList) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList);
|
||||
}
|
||||
window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; }
|
||||
window.SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; }
|
||||
window.SVGPathSegClosePath.prototype.clone = function() { return new window.SVGPathSegClosePath(undefined); }
|
||||
|
||||
window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegMovetoAbs.prototype.toString = function() { return "[object SVGPathSegMovetoAbs]"; }
|
||||
window.SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegMovetoAbs.prototype.clone = function() { return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegMovetoRel.prototype.toString = function() { return "[object SVGPathSegMovetoRel]"; }
|
||||
window.SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegMovetoRel.prototype.clone = function() { return new window.SVGPathSegMovetoRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoAbs.prototype.toString = function() { return "[object SVGPathSegLinetoAbs]"; }
|
||||
window.SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegLinetoAbs.prototype.clone = function() { return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoRel.prototype.toString = function() { return "[object SVGPathSegLinetoRel]"; }
|
||||
window.SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegLinetoRel.prototype.clone = function() { return new window.SVGPathSegLinetoRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicAbs]"; }
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicRel]"; }
|
||||
window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticAbs]"; }
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticRel]"; }
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._r1 = r1;
|
||||
this._r2 = r2;
|
||||
this._angle = angle;
|
||||
this._largeArcFlag = largeArcFlag;
|
||||
this._sweepFlag = sweepFlag;
|
||||
}
|
||||
window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegArcAbs.prototype.toString = function() { return "[object SVGPathSegArcAbs]"; }
|
||||
window.SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegArcAbs.prototype.clone = function() { return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._r1 = r1;
|
||||
this._r2 = r2;
|
||||
this._angle = angle;
|
||||
this._largeArcFlag = largeArcFlag;
|
||||
this._sweepFlag = sweepFlag;
|
||||
}
|
||||
window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegArcRel.prototype.toString = function() { return "[object SVGPathSegArcRel]"; }
|
||||
window.SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegArcRel.prototype.clone = function() { return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalAbs]"; }
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalRel]"; }
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalAbs]"; }
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoVerticalRel.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalRel]"; }
|
||||
window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
|
||||
window.SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalRel(undefined, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothAbs]"; }
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothRel]"; }
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothAbs]"; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothRel]"; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
// Add createSVGPathSeg* functions to window.SVGPathElement.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement.
|
||||
window.SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new window.SVGPathSegClosePath(undefined); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new window.SVGPathSegMovetoAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new window.SVGPathSegMovetoRel(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new window.SVGPathSegLinetoAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new window.SVGPathSegLinetoRel(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new window.SVGPathSegLinetoHorizontalAbs(undefined, x); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new window.SVGPathSegLinetoHorizontalRel(undefined, x); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new window.SVGPathSegLinetoVerticalAbs(undefined, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new window.SVGPathSegLinetoVerticalRel(undefined, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); }
|
||||
|
||||
if (!("getPathSegAtLength" in window.SVGPathElement.prototype)) {
|
||||
// Add getPathSegAtLength to SVGPathElement.
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength
|
||||
// This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm.
|
||||
window.SVGPathElement.prototype.getPathSegAtLength = function(distance) {
|
||||
if (distance === undefined || !isFinite(distance))
|
||||
throw "Invalid arguments.";
|
||||
|
||||
var measurementElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||
measurementElement.setAttribute("d", this.getAttribute("d"));
|
||||
var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1;
|
||||
|
||||
// If the path is empty, return 0.
|
||||
if (lastPathSegment <= 0)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
measurementElement.pathSegList.removeItem(lastPathSegment);
|
||||
if (distance > measurementElement.getTotalLength())
|
||||
break;
|
||||
lastPathSegment--;
|
||||
} while (lastPathSegment > 0);
|
||||
return lastPathSegment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for SVGPathSegList in window checks for the case of an implementation without the
|
||||
// SVGPathSegList API.
|
||||
// The second check for appendItem is specific to Firefox 59+ which removed only parts of the
|
||||
// SVGPathSegList API (e.g., appendItem). In this case we need to re-implement the entire API
|
||||
// so the polyfill data (i.e., _list) is used throughout.
|
||||
if (!("SVGPathSegList" in window) || !("appendItem" in window.SVGPathSegList.prototype)) {
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
|
||||
window.SVGPathSegList = function(pathElement) {
|
||||
this._pathElement = pathElement;
|
||||
this._list = this._parsePath(this._pathElement.getAttribute("d"));
|
||||
|
||||
// Use a MutationObserver to catch changes to the path's "d" attribute.
|
||||
this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] };
|
||||
this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this));
|
||||
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.classname = "SVGPathSegList";
|
||||
|
||||
Object.defineProperty(window.SVGPathSegList.prototype, "numberOfItems", {
|
||||
get: function() {
|
||||
this._checkPathSynchronizedToList();
|
||||
return this._list.length;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
// Add the pathSegList accessors to window.SVGPathElement.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "pathSegList", {
|
||||
get: function() {
|
||||
if (!this._pathSegList)
|
||||
this._pathSegList = new window.SVGPathSegList(this);
|
||||
return this._pathSegList;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
// FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList.
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
|
||||
// Process any pending mutations to the path element and update the list as needed.
|
||||
// This should be the first call of all public functions and is needed because
|
||||
// MutationObservers are not synchronous so we can have pending asynchronous mutations.
|
||||
window.SVGPathSegList.prototype._checkPathSynchronizedToList = function() {
|
||||
this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) {
|
||||
if (!this._pathElement)
|
||||
return;
|
||||
var hasPathMutations = false;
|
||||
mutationRecords.forEach(function(record) {
|
||||
if (record.attributeName == "d")
|
||||
hasPathMutations = true;
|
||||
});
|
||||
if (hasPathMutations)
|
||||
this._list = this._parsePath(this._pathElement.getAttribute("d"));
|
||||
}
|
||||
|
||||
// Serialize the list and update the path's 'd' attribute.
|
||||
window.SVGPathSegList.prototype._writeListToPath = function() {
|
||||
this._pathElementMutationObserver.disconnect();
|
||||
this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list));
|
||||
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
|
||||
}
|
||||
|
||||
// When a path segment changes the list needs to be synchronized back to the path element.
|
||||
window.SVGPathSegList.prototype.segmentChanged = function(pathSeg) {
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.clear = function() {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list.forEach(function(pathSeg) {
|
||||
pathSeg._owningPathSegList = null;
|
||||
});
|
||||
this._list = [];
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.initialize = function(newItem) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list = [newItem];
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype._checkValidIndex = function(index) {
|
||||
if (isNaN(index) || index < 0 || index >= this.numberOfItems)
|
||||
throw "INDEX_SIZE_ERR";
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.getItem = function(index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
return this._list[index];
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.insertItemBefore = function(newItem, index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
// Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
|
||||
if (index > this.numberOfItems)
|
||||
index = this.numberOfItems;
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._list.splice(index, 0, newItem);
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.replaceItem = function(newItem, index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._checkValidIndex(index);
|
||||
this._list[index] = newItem;
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.removeItem = function(index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
var item = this._list[index];
|
||||
this._list.splice(index, 1);
|
||||
this._writeListToPath();
|
||||
return item;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.appendItem = function(newItem) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._list.push(newItem);
|
||||
newItem._owningPathSegList = this;
|
||||
// TODO: Optimize this to just append to the existing attribute.
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList._pathSegArrayAsString = function(pathSegArray) {
|
||||
var string = "";
|
||||
var first = true;
|
||||
pathSegArray.forEach(function(pathSeg) {
|
||||
if (first) {
|
||||
first = false;
|
||||
string += pathSeg._asPathString();
|
||||
} else {
|
||||
string += " " + pathSeg._asPathString();
|
||||
}
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
// This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
|
||||
window.SVGPathSegList.prototype._parsePath = function(string) {
|
||||
if (!string || string.length == 0)
|
||||
return [];
|
||||
|
||||
var owningPathSegList = this;
|
||||
|
||||
var Builder = function() {
|
||||
this.pathSegList = [];
|
||||
}
|
||||
|
||||
Builder.prototype.appendSegment = function(pathSeg) {
|
||||
this.pathSegList.push(pathSeg);
|
||||
}
|
||||
|
||||
var Source = function(string) {
|
||||
this._string = string;
|
||||
this._currentIndex = 0;
|
||||
this._endIndex = this._string.length;
|
||||
this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
|
||||
this._skipOptionalSpaces();
|
||||
}
|
||||
|
||||
Source.prototype._isCurrentSpace = function() {
|
||||
var character = this._string[this._currentIndex];
|
||||
return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f");
|
||||
}
|
||||
|
||||
Source.prototype._skipOptionalSpaces = function() {
|
||||
while (this._currentIndex < this._endIndex && this._isCurrentSpace())
|
||||
this._currentIndex++;
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype._skipOptionalSpacesOrDelimiter = function() {
|
||||
if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",")
|
||||
return false;
|
||||
if (this._skipOptionalSpaces()) {
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") {
|
||||
this._currentIndex++;
|
||||
this._skipOptionalSpaces();
|
||||
}
|
||||
}
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype.hasMoreData = function() {
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype.peekSegmentType = function() {
|
||||
var lookahead = this._string[this._currentIndex];
|
||||
return this._pathSegTypeFromChar(lookahead);
|
||||
}
|
||||
|
||||
Source.prototype._pathSegTypeFromChar = function(lookahead) {
|
||||
switch (lookahead) {
|
||||
case "Z":
|
||||
case "z":
|
||||
return window.SVGPathSeg.PATHSEG_CLOSEPATH;
|
||||
case "M":
|
||||
return window.SVGPathSeg.PATHSEG_MOVETO_ABS;
|
||||
case "m":
|
||||
return window.SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
case "L":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
case "l":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
case "C":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
|
||||
case "c":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
|
||||
case "Q":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
|
||||
case "q":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
|
||||
case "A":
|
||||
return window.SVGPathSeg.PATHSEG_ARC_ABS;
|
||||
case "a":
|
||||
return window.SVGPathSeg.PATHSEG_ARC_REL;
|
||||
case "H":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
|
||||
case "h":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
|
||||
case "V":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
|
||||
case "v":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
|
||||
case "S":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
|
||||
case "s":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
|
||||
case "T":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
|
||||
case "t":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
|
||||
default:
|
||||
return window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
|
||||
// Check for remaining coordinates in the current command.
|
||||
if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) {
|
||||
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS)
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL)
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
return previousCommand;
|
||||
}
|
||||
return window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
|
||||
Source.prototype.initialCommandIsMoveTo = function() {
|
||||
// If the path is empty it is still valid, so return true.
|
||||
if (!this.hasMoreData())
|
||||
return true;
|
||||
var command = this.peekSegmentType();
|
||||
// Path must start with moveTo.
|
||||
return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
}
|
||||
|
||||
// Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
|
||||
Source.prototype._parseNumber = function() {
|
||||
var exponent = 0;
|
||||
var integer = 0;
|
||||
var frac = 1;
|
||||
var decimal = 0;
|
||||
var sign = 1;
|
||||
var expsign = 1;
|
||||
|
||||
var startIndex = this._currentIndex;
|
||||
|
||||
this._skipOptionalSpaces();
|
||||
|
||||
// Read the sign.
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+")
|
||||
this._currentIndex++;
|
||||
else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") {
|
||||
this._currentIndex++;
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != "."))
|
||||
// The first character of a number must be one of [0-9+-.].
|
||||
return undefined;
|
||||
|
||||
// Read the integer part, build right-to-left.
|
||||
var startIntPartIndex = this._currentIndex;
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9")
|
||||
this._currentIndex++; // Advance to first non-digit.
|
||||
|
||||
if (this._currentIndex != startIntPartIndex) {
|
||||
var scanIntPartIndex = this._currentIndex - 1;
|
||||
var multiplier = 1;
|
||||
while (scanIntPartIndex >= startIntPartIndex) {
|
||||
integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0");
|
||||
multiplier *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the decimals.
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") {
|
||||
this._currentIndex++;
|
||||
|
||||
// There must be a least one digit following the .
|
||||
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
|
||||
return undefined;
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
|
||||
frac *= 10;
|
||||
decimal += (this._string.charAt(this._currentIndex) - "0") / frac;
|
||||
this._currentIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the exponent part.
|
||||
if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) {
|
||||
this._currentIndex++;
|
||||
|
||||
// Read the sign of the exponent.
|
||||
if (this._string.charAt(this._currentIndex) == "+") {
|
||||
this._currentIndex++;
|
||||
} else if (this._string.charAt(this._currentIndex) == "-") {
|
||||
this._currentIndex++;
|
||||
expsign = -1;
|
||||
}
|
||||
|
||||
// There must be an exponent.
|
||||
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
|
||||
return undefined;
|
||||
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
|
||||
exponent *= 10;
|
||||
exponent += (this._string.charAt(this._currentIndex) - "0");
|
||||
this._currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
var number = integer + decimal;
|
||||
number *= sign;
|
||||
|
||||
if (exponent)
|
||||
number *= Math.pow(10, expsign * exponent);
|
||||
|
||||
if (startIndex == this._currentIndex)
|
||||
return undefined;
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
Source.prototype._parseArcFlag = function() {
|
||||
if (this._currentIndex >= this._endIndex)
|
||||
return undefined;
|
||||
var flag = false;
|
||||
var flagChar = this._string.charAt(this._currentIndex++);
|
||||
if (flagChar == "0")
|
||||
flag = false;
|
||||
else if (flagChar == "1")
|
||||
flag = true;
|
||||
else
|
||||
return undefined;
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
return flag;
|
||||
}
|
||||
|
||||
Source.prototype.parseSegment = function() {
|
||||
var lookahead = this._string[this._currentIndex];
|
||||
var command = this._pathSegTypeFromChar(lookahead);
|
||||
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) {
|
||||
// Possibly an implicit command. Not allowed if this is the first command.
|
||||
if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN)
|
||||
return null;
|
||||
command = this._nextCommandHelper(lookahead, this._previousCommand);
|
||||
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN)
|
||||
return null;
|
||||
} else {
|
||||
this._currentIndex++;
|
||||
}
|
||||
|
||||
this._previousCommand = command;
|
||||
|
||||
switch (command) {
|
||||
case window.SVGPathSeg.PATHSEG_MOVETO_REL:
|
||||
return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_MOVETO_ABS:
|
||||
return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_REL:
|
||||
return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_ABS:
|
||||
return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
|
||||
return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
|
||||
return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
|
||||
return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
|
||||
return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_CLOSEPATH:
|
||||
this._skipOptionalSpaces();
|
||||
return new window.SVGPathSegClosePath(owningPathSegList);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
|
||||
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
|
||||
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
|
||||
return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
|
||||
return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_ARC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
case window.SVGPathSeg.PATHSEG_ARC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
default:
|
||||
throw "Unknown path seg type."
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new Builder();
|
||||
var source = new Source(string);
|
||||
|
||||
if (!source.initialCommandIsMoveTo())
|
||||
return [];
|
||||
while (source.hasMoreData()) {
|
||||
var pathSeg = source.parseSegment();
|
||||
if (!pathSeg)
|
||||
return [];
|
||||
builder.appendSegment(pathSeg);
|
||||
}
|
||||
|
||||
return builder.pathSegList;
|
||||
}
|
||||
}
|
||||
}());
|
||||
297
public/svgnest/util/placementworker.js
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
|
||||
// jsClipper uses X/Y instead of x/y...
|
||||
function toClipperCoordinates(polygon){
|
||||
var clone = [];
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
clone.push({
|
||||
X: polygon[i].x,
|
||||
Y: polygon[i].y
|
||||
});
|
||||
}
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
function toNestCoordinates(polygon, scale){
|
||||
var clone = [];
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
clone.push({
|
||||
x: polygon[i].X/scale,
|
||||
y: polygon[i].Y/scale
|
||||
});
|
||||
}
|
||||
|
||||
return clone;
|
||||
};
|
||||
|
||||
function rotatePolygon(polygon, degrees){
|
||||
var rotated = [];
|
||||
var angle = degrees * Math.PI / 180;
|
||||
for(var i=0; i<polygon.length; i++){
|
||||
var x = polygon[i].x;
|
||||
var y = polygon[i].y;
|
||||
var x1 = x*Math.cos(angle)-y*Math.sin(angle);
|
||||
var y1 = x*Math.sin(angle)+y*Math.cos(angle);
|
||||
|
||||
rotated.push({x:x1, y:y1});
|
||||
}
|
||||
|
||||
if(polygon.children && polygon.children.length > 0){
|
||||
rotated.children = [];
|
||||
for(var j=0; j<polygon.children.length; j++){
|
||||
rotated.children.push(rotatePolygon(polygon.children[j], degrees));
|
||||
}
|
||||
}
|
||||
|
||||
return rotated;
|
||||
};
|
||||
|
||||
function PlacementWorker(binPolygon, paths, ids, rotations, config, nfpCache){
|
||||
this.binPolygon = binPolygon;
|
||||
this.paths = paths;
|
||||
this.ids = ids;
|
||||
this.rotations = rotations;
|
||||
this.config = config;
|
||||
this.nfpCache = nfpCache || {};
|
||||
|
||||
// return a placement for the paths/rotations given
|
||||
// happens inside a webworker
|
||||
this.placePaths = function(paths){
|
||||
|
||||
var self = global.env.self;
|
||||
|
||||
if(!self.binPolygon){
|
||||
return null;
|
||||
}
|
||||
|
||||
var i, j, k, m, n, path;
|
||||
|
||||
// rotate paths by given rotation
|
||||
var rotated = [];
|
||||
for(i=0; i<paths.length; i++){
|
||||
var r = rotatePolygon(paths[i], paths[i].rotation);
|
||||
r.rotation = paths[i].rotation;
|
||||
r.source = paths[i].source;
|
||||
r.id = paths[i].id;
|
||||
rotated.push(r);
|
||||
}
|
||||
|
||||
paths = rotated;
|
||||
|
||||
var allplacements = [];
|
||||
var fitness = 0;
|
||||
var binarea = Math.abs(GeometryUtil.polygonArea(self.binPolygon));
|
||||
var key, nfp;
|
||||
|
||||
while(paths.length > 0){
|
||||
|
||||
var placed = [];
|
||||
var placements = [];
|
||||
fitness += 1; // add 1 for each new bin opened (lower fitness is better)
|
||||
|
||||
for(i=0; i<paths.length; i++){
|
||||
path = paths[i];
|
||||
|
||||
// inner NFP
|
||||
key = JSON.stringify({A:-1,B:path.id,inside:true,Arotation:0,Brotation:path.rotation});
|
||||
var binNfp = self.nfpCache[key];
|
||||
|
||||
// part unplaceable, skip
|
||||
if(!binNfp || binNfp.length == 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure all necessary NFPs exist
|
||||
var error = false;
|
||||
for(j=0; j<placed.length; j++){
|
||||
key = JSON.stringify({A:placed[j].id,B:path.id,inside:false,Arotation:placed[j].rotation,Brotation:path.rotation});
|
||||
nfp = self.nfpCache[key];
|
||||
|
||||
if(!nfp){
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// part unplaceable, skip
|
||||
if(error){
|
||||
continue;
|
||||
}
|
||||
|
||||
var position = null;
|
||||
if(placed.length == 0){
|
||||
// first placement, put it on the left
|
||||
for(j=0; j<binNfp.length; j++){
|
||||
for(k=0; k<binNfp[j].length; k++){
|
||||
if(position === null || binNfp[j][k].x-path[0].x < position.x ){
|
||||
position = {
|
||||
x: binNfp[j][k].x-path[0].x,
|
||||
y: binNfp[j][k].y-path[0].y,
|
||||
id: path.id,
|
||||
rotation: path.rotation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
placements.push(position);
|
||||
placed.push(path);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var clipperBinNfp = [];
|
||||
for(j=0; j<binNfp.length; j++){
|
||||
clipperBinNfp.push(toClipperCoordinates(binNfp[j]));
|
||||
}
|
||||
|
||||
ClipperLib.JS.ScaleUpPaths(clipperBinNfp, self.config.clipperScale);
|
||||
|
||||
var clipper = new ClipperLib.Clipper();
|
||||
var combinedNfp = new ClipperLib.Paths();
|
||||
|
||||
|
||||
for(j=0; j<placed.length; j++){
|
||||
key = JSON.stringify({A:placed[j].id,B:path.id,inside:false,Arotation:placed[j].rotation,Brotation:path.rotation});
|
||||
nfp = self.nfpCache[key];
|
||||
|
||||
if(!nfp){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(k=0; k<nfp.length; k++){
|
||||
var clone = toClipperCoordinates(nfp[k]);
|
||||
for(m=0; m<clone.length; m++){
|
||||
clone[m].X += placements[j].x;
|
||||
clone[m].Y += placements[j].y;
|
||||
}
|
||||
|
||||
ClipperLib.JS.ScaleUpPath(clone, self.config.clipperScale);
|
||||
clone = ClipperLib.Clipper.CleanPolygon(clone, 0.0001*self.config.clipperScale);
|
||||
var area = Math.abs(ClipperLib.Clipper.Area(clone));
|
||||
if(clone.length > 2 && area > 0.1*self.config.clipperScale*self.config.clipperScale){
|
||||
clipper.AddPath(clone, ClipperLib.PolyType.ptSubject, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!clipper.Execute(ClipperLib.ClipType.ctUnion, combinedNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){
|
||||
continue;
|
||||
}
|
||||
|
||||
// difference with bin polygon
|
||||
var finalNfp = new ClipperLib.Paths();
|
||||
clipper = new ClipperLib.Clipper();
|
||||
|
||||
clipper.AddPaths(combinedNfp, ClipperLib.PolyType.ptClip, true);
|
||||
clipper.AddPaths(clipperBinNfp, ClipperLib.PolyType.ptSubject, true);
|
||||
if(!clipper.Execute(ClipperLib.ClipType.ctDifference, finalNfp, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero)){
|
||||
continue;
|
||||
}
|
||||
|
||||
finalNfp = ClipperLib.Clipper.CleanPolygons(finalNfp, 0.0001*self.config.clipperScale);
|
||||
|
||||
for(j=0; j<finalNfp.length; j++){
|
||||
var area = Math.abs(ClipperLib.Clipper.Area(finalNfp[j]));
|
||||
if(finalNfp[j].length < 3 || area < 0.1*self.config.clipperScale*self.config.clipperScale){
|
||||
finalNfp.splice(j,1);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
if(!finalNfp || finalNfp.length == 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
var f = [];
|
||||
for(j=0; j<finalNfp.length; j++){
|
||||
// back to normal scale
|
||||
f.push(toNestCoordinates(finalNfp[j], self.config.clipperScale));
|
||||
}
|
||||
finalNfp = f;
|
||||
|
||||
// choose placement that results in the smallest bounding box
|
||||
// could use convex hull instead, but it can create oddly shaped nests (triangles or long slivers) which are not optimal for real-world use
|
||||
// todo: generalize gravity direction
|
||||
var minwidth = null;
|
||||
var minarea = null;
|
||||
var minx = null;
|
||||
var nf, area, shiftvector;
|
||||
|
||||
for(j=0; j<finalNfp.length; j++){
|
||||
nf = finalNfp[j];
|
||||
if(Math.abs(GeometryUtil.polygonArea(nf)) < 2){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(k=0; k<nf.length; k++){
|
||||
var allpoints = [];
|
||||
for(m=0; m<placed.length; m++){
|
||||
for(n=0; n<placed[m].length; n++){
|
||||
allpoints.push({x:placed[m][n].x+placements[m].x, y: placed[m][n].y+placements[m].y});
|
||||
}
|
||||
}
|
||||
|
||||
shiftvector = {
|
||||
x: nf[k].x-path[0].x,
|
||||
y: nf[k].y-path[0].y,
|
||||
id: path.id,
|
||||
rotation: path.rotation,
|
||||
nfp: combinedNfp
|
||||
};
|
||||
|
||||
for(m=0; m<path.length; m++){
|
||||
allpoints.push({x: path[m].x+shiftvector.x, y:path[m].y+shiftvector.y});
|
||||
}
|
||||
|
||||
var rectbounds = GeometryUtil.getPolygonBounds(allpoints);
|
||||
|
||||
// weigh width more, to help compress in direction of gravity
|
||||
area = rectbounds.width*2 + rectbounds.height;
|
||||
|
||||
if(minarea === null || area < minarea || (GeometryUtil.almostEqual(minarea, area) && (minx === null || shiftvector.x < minx))){
|
||||
minarea = area;
|
||||
minwidth = rectbounds.width;
|
||||
position = shiftvector;
|
||||
minx = shiftvector.x;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(position){
|
||||
placed.push(path);
|
||||
placements.push(position);
|
||||
}
|
||||
}
|
||||
|
||||
if(minwidth){
|
||||
fitness += minwidth/binarea;
|
||||
}
|
||||
|
||||
for(i=0; i<placed.length; i++){
|
||||
var index = paths.indexOf(placed[i]);
|
||||
if(index >= 0){
|
||||
paths.splice(index,1);
|
||||
}
|
||||
}
|
||||
|
||||
if(placements && placements.length > 0){
|
||||
allplacements.push(placements);
|
||||
}
|
||||
else{
|
||||
break; // something went wrong
|
||||
}
|
||||
}
|
||||
|
||||
// there were parts that couldn't be placed
|
||||
fitness += 2*paths.length;
|
||||
|
||||
return {placements: allplacements, fitness: fitness, paths: paths, area: binarea };
|
||||
};
|
||||
|
||||
}
|
||||
(typeof window !== 'undefined' ? window : self).PlacementWorker = PlacementWorker;
|
||||
|
||||
// clipperjs uses alerts for warnings
|
||||
function alert(message) {
|
||||
console.log('alert: ', message);
|
||||
}
|
||||