add xml as import to allow roller to include in the build
This commit is contained in:
285
dist/common/browser.js
vendored
Normal file
285
dist/common/browser.js
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/* globals jQuery */
|
||||
/**
|
||||
* Browser detection.
|
||||
* @module browser
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2010 Jeff Schiller, 2010 Alexis Deveria
|
||||
*/
|
||||
|
||||
// Dependencies:
|
||||
// 1) jQuery (for $.alert())
|
||||
|
||||
import './svgpathseg.js';
|
||||
import {NS} from './namespaces.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
const supportsSVG_ = (function () {
|
||||
return Boolean(document.createElementNS && document.createElementNS(NS.SVG, 'svg').createSVGRect);
|
||||
}());
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsSvg
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsSvg = () => supportsSVG_;
|
||||
|
||||
const {userAgent} = navigator;
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
// Note: Browser sniffing should only be used if no other detection method is possible
|
||||
const isOpera_ = Boolean(window.opera);
|
||||
const isWebkit_ = userAgent.includes('AppleWebKit');
|
||||
const isGecko_ = userAgent.includes('Gecko/');
|
||||
const isIE_ = userAgent.includes('MSIE');
|
||||
const isChrome_ = userAgent.includes('Chrome/');
|
||||
const isWindows_ = userAgent.includes('Windows');
|
||||
const isMac_ = userAgent.includes('Macintosh');
|
||||
const isTouch_ = 'ontouchstart' in window;
|
||||
|
||||
const supportsSelectors_ = (function () {
|
||||
return Boolean(svg.querySelector);
|
||||
}());
|
||||
|
||||
const supportsXpath_ = (function () {
|
||||
return Boolean(document.evaluate);
|
||||
}());
|
||||
|
||||
// segList functions (for FF1.5 and 2.0)
|
||||
const supportsPathReplaceItem_ = (function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
const seglist = path.pathSegList;
|
||||
const seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.replaceItem(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
const supportsPathInsertItemBefore_ = (function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
const seglist = path.pathSegList;
|
||||
const seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.insertItemBefore(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
// text character positioning (for IE9 and now Chrome)
|
||||
const supportsGoodTextCharPos_ = (function () {
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.append(svgroot);
|
||||
svgcontent.setAttribute('x', 5);
|
||||
svgroot.append(svgcontent);
|
||||
const text = document.createElementNS(NS.SVG, 'text');
|
||||
text.textContent = 'a';
|
||||
svgcontent.append(text);
|
||||
try { // Chrome now fails here
|
||||
const pos = text.getStartPositionOfChar(0).x;
|
||||
return (pos === 0);
|
||||
} catch (err) {
|
||||
return false;
|
||||
} finally {
|
||||
svgroot.remove();
|
||||
}
|
||||
}());
|
||||
|
||||
const supportsPathBBox_ = (function () {
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.append(svgcontent);
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
|
||||
svgcontent.append(path);
|
||||
const bbox = path.getBBox();
|
||||
svgcontent.remove();
|
||||
return (bbox.height > 4 && bbox.height < 5);
|
||||
}());
|
||||
|
||||
// Support for correct bbox sizing on groups with horizontal/vertical lines
|
||||
const supportsHVLineContainerBBox_ = (function () {
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.append(svgcontent);
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,0');
|
||||
const path2 = document.createElementNS(NS.SVG, 'path');
|
||||
path2.setAttribute('d', 'M5,0 15,0');
|
||||
const g = document.createElementNS(NS.SVG, 'g');
|
||||
g.append(path, path2);
|
||||
svgcontent.append(g);
|
||||
const bbox = g.getBBox();
|
||||
svgcontent.remove();
|
||||
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
|
||||
return (bbox.width === 15);
|
||||
}());
|
||||
|
||||
const supportsEditableText_ = (function () {
|
||||
// TODO: Find better way to check support for this
|
||||
return isOpera_;
|
||||
}());
|
||||
|
||||
const supportsGoodDecimals_ = (function () {
|
||||
// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('x', 0.1);
|
||||
const crect = rect.cloneNode(false);
|
||||
const retValue = (!crect.getAttribute('x').includes(','));
|
||||
if (!retValue) {
|
||||
// Todo: i18nize or remove
|
||||
$.alert(
|
||||
'NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' +
|
||||
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.'
|
||||
);
|
||||
}
|
||||
return retValue;
|
||||
}());
|
||||
|
||||
const supportsNonScalingStroke_ = (function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
|
||||
return rect.style.vectorEffect === 'non-scaling-stroke';
|
||||
}());
|
||||
|
||||
let supportsNativeSVGTransformLists_ = (function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
const rxform = rect.transform.baseVal;
|
||||
const t1 = svg.createSVGTransform();
|
||||
rxform.appendItem(t1);
|
||||
const r1 = rxform.getItem(0);
|
||||
const isSVGTransform = (o) => {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/SVGTransform
|
||||
return o && typeof o === 'object' && typeof o.setMatrix === 'function' && 'angle' in o;
|
||||
};
|
||||
return isSVGTransform(r1) && isSVGTransform(t1) &&
|
||||
r1.type === t1.type && r1.angle === t1.angle &&
|
||||
r1.matrix.a === t1.matrix.a &&
|
||||
r1.matrix.b === t1.matrix.b &&
|
||||
r1.matrix.c === t1.matrix.c &&
|
||||
r1.matrix.d === t1.matrix.d &&
|
||||
r1.matrix.e === t1.matrix.e &&
|
||||
r1.matrix.f === t1.matrix.f;
|
||||
}());
|
||||
|
||||
// Public API
|
||||
|
||||
/**
|
||||
* @function module:browser.isOpera
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isOpera = () => isOpera_;
|
||||
/**
|
||||
* @function module:browser.isWebkit
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isWebkit = () => isWebkit_;
|
||||
/**
|
||||
* @function module:browser.isGecko
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isGecko = () => isGecko_;
|
||||
/**
|
||||
* @function module:browser.isIE
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isIE = () => isIE_;
|
||||
/**
|
||||
* @function module:browser.isChrome
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isChrome = () => isChrome_;
|
||||
/**
|
||||
* @function module:browser.isWindows
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isWindows = () => isWindows_;
|
||||
/**
|
||||
* @function module:browser.isMac
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isMac = () => isMac_;
|
||||
/**
|
||||
* @function module:browser.isTouch
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isTouch = () => isTouch_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsSelectors
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsSelectors = () => supportsSelectors_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsXpath
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsXpath = () => supportsXpath_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsPathReplaceItem
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsPathReplaceItem = () => supportsPathReplaceItem_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsPathInsertItemBefore
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsPathBBox
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsPathBBox = () => supportsPathBBox_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsHVLineContainerBBox
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsHVLineContainerBBox = () => supportsHVLineContainerBBox_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsGoodTextCharPos
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsEditableText
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsEditableText = () => supportsEditableText_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsGoodDecimals
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsGoodDecimals = () => supportsGoodDecimals_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsNonScalingStroke
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsNonScalingStroke = () => supportsNonScalingStroke_;
|
||||
|
||||
/**
|
||||
* @function module:browser.supportsNativeTransformLists
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_;
|
||||
|
||||
/**
|
||||
* Set `supportsNativeSVGTransformLists_` to `false` (for unit testing).
|
||||
* @function module:browser.disableSupportsNativeTransformLists
|
||||
* @returns {void}
|
||||
*/
|
||||
export const disableSupportsNativeTransformLists = () => {
|
||||
supportsNativeSVGTransformLists_ = false;
|
||||
};
|
||||
79
dist/common/jQuery.attr.js
vendored
Normal file
79
dist/common/jQuery.attr.js
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* A jQuery module to work with SVG attributes.
|
||||
* @module jQueryAttr
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* This fixes `$(...).attr()` to work as expected with SVG elements.
|
||||
* Does not currently use `*AttributeNS()` since we rarely need that.
|
||||
* Adds {@link external:jQuery.fn.attr}.
|
||||
* See {@link https://api.jquery.com/attr/} for basic documentation of `.attr()`.
|
||||
*
|
||||
* Additional functionality:
|
||||
* - When getting attributes, a string that's a number is returned as type number.
|
||||
* - If an array is supplied as the first parameter, multiple values are returned
|
||||
* as an object with values for each given attribute.
|
||||
* @function module:jQueryAttr.jQueryAttr
|
||||
* @param {external:jQuery} $ The jQuery object to which to add the plug-in
|
||||
* @returns {external:jQuery}
|
||||
*/
|
||||
export default function jQueryPluginSVG ($) {
|
||||
const proxied = $.fn.attr,
|
||||
svgns = 'http://www.w3.org/2000/svg';
|
||||
/**
|
||||
* @typedef {PlainObject<string, string|Float>} module:jQueryAttr.Attributes
|
||||
*/
|
||||
/**
|
||||
* @function external:jQuery.fn.attr
|
||||
* @param {string|string[]|PlainObject<string, string>} key
|
||||
* @param {string} value
|
||||
* @returns {external:jQuery|module:jQueryAttr.Attributes}
|
||||
*/
|
||||
$.fn.attr = function (key, value) {
|
||||
const len = this.length;
|
||||
if (!len) { return proxied.call(this, key, value); }
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const elem = this[i];
|
||||
// set/get SVG attribute
|
||||
if (elem.namespaceURI === svgns) {
|
||||
// Setting attribute
|
||||
if (value !== undefined) {
|
||||
elem.setAttribute(key, value);
|
||||
} else if (Array.isArray(key)) {
|
||||
// Getting attributes from array
|
||||
const obj = {};
|
||||
let j = key.length;
|
||||
|
||||
while (j--) {
|
||||
const aname = key[j];
|
||||
let attr = elem.getAttribute(aname);
|
||||
// This returns a number when appropriate
|
||||
if (attr || attr === '0') {
|
||||
attr = isNaN(attr) ? attr : (attr - 0);
|
||||
}
|
||||
obj[aname] = attr;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (typeof key === 'object') {
|
||||
// Setting attributes from object
|
||||
for (const [name, val] of Object.entries(key)) {
|
||||
elem.setAttribute(name, val);
|
||||
}
|
||||
// Getting attribute
|
||||
} else {
|
||||
let attr = elem.getAttribute(key);
|
||||
if (attr || attr === '0') {
|
||||
attr = isNaN(attr) ? attr : (attr - 0);
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
} else {
|
||||
return proxied.call(this, key, value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
return $;
|
||||
}
|
||||
222
dist/common/layer.js
vendored
Normal file
222
dist/common/layer.js
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/* globals jQuery */
|
||||
/**
|
||||
* Provides tools for the layer concept.
|
||||
* @module layer
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2011 Jeff Schiller, 2016 Flint O'Brien
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
import {toXml, walkTree, isNullish} from './utilities.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
/**
|
||||
* This class encapsulates the concept of a layer in the drawing. It can be constructed with
|
||||
* an existing group element or, with three parameters, will create a new layer group element.
|
||||
*
|
||||
* @example
|
||||
* const l1 = new Layer('name', group); // Use the existing group for this layer.
|
||||
* const l2 = new Layer('name', group, svgElem); // Create a new group and add it to the DOM after group.
|
||||
* const l3 = new Layer('name', null, svgElem); // Create a new group and add it to the DOM as the last layer.
|
||||
* @memberof module:layer
|
||||
*/
|
||||
class Layer {
|
||||
/**
|
||||
* @param {string} name - Layer name
|
||||
* @param {SVGGElement|null} group - An existing SVG group element or null.
|
||||
* If group and no svgElem, use group for this layer.
|
||||
* If group and svgElem, create a new group element and insert it in the DOM after group.
|
||||
* If no group and svgElem, create a new group element and insert it in the DOM as the last layer.
|
||||
* @param {SVGGElement} [svgElem] - The SVG DOM element. If defined, use this to add
|
||||
* a new layer to the document.
|
||||
*/
|
||||
constructor (name, group, svgElem) {
|
||||
this.name_ = name;
|
||||
this.group_ = svgElem ? null : group;
|
||||
|
||||
if (svgElem) {
|
||||
// Create a group element with title and add it to the DOM.
|
||||
const svgdoc = svgElem.ownerDocument;
|
||||
this.group_ = svgdoc.createElementNS(NS.SVG, 'g');
|
||||
const layerTitle = svgdoc.createElementNS(NS.SVG, 'title');
|
||||
layerTitle.textContent = name;
|
||||
this.group_.append(layerTitle);
|
||||
if (group) {
|
||||
$(group).after(this.group_);
|
||||
} else {
|
||||
svgElem.append(this.group_);
|
||||
}
|
||||
}
|
||||
|
||||
addLayerClass(this.group_);
|
||||
walkTree(this.group_, function (e) {
|
||||
e.setAttribute('style', 'pointer-events:inherit');
|
||||
});
|
||||
|
||||
this.group_.setAttribute('style', svgElem ? 'pointer-events:all' : 'pointer-events:none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layer's name.
|
||||
* @returns {string} The layer name
|
||||
*/
|
||||
getName () {
|
||||
return this.name_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group element for this layer.
|
||||
* @returns {SVGGElement} The layer SVG group
|
||||
*/
|
||||
getGroup () {
|
||||
return this.group_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Active this layer so it takes pointer events.
|
||||
* @returns {void}
|
||||
*/
|
||||
activate () {
|
||||
this.group_.setAttribute('style', 'pointer-events:all');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactive this layer so it does NOT take pointer events.
|
||||
* @returns {void}
|
||||
*/
|
||||
deactivate () {
|
||||
this.group_.setAttribute('style', 'pointer-events:none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this layer visible or hidden based on 'visible' parameter.
|
||||
* @param {boolean} visible - If true, make visible; otherwise, hide it.
|
||||
* @returns {void}
|
||||
*/
|
||||
setVisible (visible) {
|
||||
const expected = visible === undefined || visible ? 'inline' : 'none';
|
||||
const oldDisplay = this.group_.getAttribute('display');
|
||||
if (oldDisplay !== expected) {
|
||||
this.group_.setAttribute('display', expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this layer visible?
|
||||
* @returns {boolean} True if visible.
|
||||
*/
|
||||
isVisible () {
|
||||
return this.group_.getAttribute('display') !== 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layer opacity.
|
||||
* @returns {Float} Opacity value.
|
||||
*/
|
||||
getOpacity () {
|
||||
const opacity = this.group_.getAttribute('opacity');
|
||||
if (isNullish(opacity)) {
|
||||
return 1;
|
||||
}
|
||||
return Number.parseFloat(opacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0,
|
||||
* nothing happens.
|
||||
* @param {Float} opacity - A float value in the range 0.0-1.0
|
||||
* @returns {void}
|
||||
*/
|
||||
setOpacity (opacity) {
|
||||
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
|
||||
this.group_.setAttribute('opacity', opacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append children to this layer.
|
||||
* @param {SVGGElement} children - The children to append to this layer.
|
||||
* @returns {void}
|
||||
*/
|
||||
appendChildren (children) {
|
||||
for (const child of children) {
|
||||
this.group_.append(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {SVGTitleElement|null}
|
||||
*/
|
||||
getTitleElement () {
|
||||
const len = this.group_.childNodes.length;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const child = this.group_.childNodes.item(i);
|
||||
if (child && child.tagName === 'title') {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this layer.
|
||||
* @param {string} name - The new name.
|
||||
* @param {module:history.HistoryRecordingService} hrService - History recording service
|
||||
* @returns {string|null} The new name if changed; otherwise, null.
|
||||
*/
|
||||
setName (name, hrService) {
|
||||
const previousName = this.name_;
|
||||
name = toXml(name);
|
||||
// now change the underlying title element contents
|
||||
const title = this.getTitleElement();
|
||||
if (title) {
|
||||
$(title).empty();
|
||||
title.textContent = name;
|
||||
this.name_ = name;
|
||||
if (hrService) {
|
||||
hrService.changeElement(title, {'#text': previousName});
|
||||
}
|
||||
return this.name_;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this layer's group from the DOM. No more functions on group can be called after this.
|
||||
* @returns {SVGGElement} The layer SVG group that was just removed.
|
||||
*/
|
||||
removeGroup () {
|
||||
const group = this.group_;
|
||||
this.group_.remove();
|
||||
this.group_ = undefined;
|
||||
return group;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @property {string} CLASS_NAME - class attribute assigned to all layer groups.
|
||||
*/
|
||||
Layer.CLASS_NAME = 'layer';
|
||||
|
||||
/**
|
||||
* @property {RegExp} CLASS_REGEX - Used to test presence of class Layer.CLASS_NAME
|
||||
*/
|
||||
Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)');
|
||||
|
||||
/**
|
||||
* Add class `Layer.CLASS_NAME` to the element (usually `class='layer'`).
|
||||
*
|
||||
* @param {SVGGElement} elem - The SVG element to update
|
||||
* @returns {void}
|
||||
*/
|
||||
function addLayerClass (elem) {
|
||||
const classes = elem.getAttribute('class');
|
||||
if (isNullish(classes) || !classes.length) {
|
||||
elem.setAttribute('class', Layer.CLASS_NAME);
|
||||
} else if (!Layer.CLASS_REGEX.test(classes)) {
|
||||
elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
export default Layer;
|
||||
222
dist/common/math.js
vendored
Normal file
222
dist/common/math.js
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Mathematical utilities.
|
||||
* @module math
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} module:math.AngleCoord45
|
||||
* @property {Float} x - The angle-snapped x value
|
||||
* @property {Float} y - The angle-snapped y value
|
||||
* @property {Integer} a - The angle at which to snap
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} module:math.XYObject
|
||||
* @property {Float} x
|
||||
* @property {Float} y
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
|
||||
// Constants
|
||||
const NEAR_ZERO = 1e-14;
|
||||
|
||||
// Throw away SVGSVGElement used for creating matrices/transforms.
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
/**
|
||||
* A (hopefully) quicker function to transform a point by a matrix
|
||||
* (this function avoids any DOM calls and just does the math).
|
||||
* @function module:math.transformPoint
|
||||
* @param {Float} x - Float representing the x coordinate
|
||||
* @param {Float} y - Float representing the y coordinate
|
||||
* @param {SVGMatrix} m - Matrix object to transform the point with
|
||||
* @returns {module:math.XYObject} An x, y object representing the transformed point
|
||||
*/
|
||||
export const transformPoint = function (x, y, m) {
|
||||
return {x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f};
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to check if the matrix performs no actual transform
|
||||
* (i.e. exists for identity purposes).
|
||||
* @function module:math.isIdentity
|
||||
* @param {SVGMatrix} m - The matrix object to check
|
||||
* @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0
|
||||
*/
|
||||
export const isIdentity = function (m) {
|
||||
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function tries to return a `SVGMatrix` that is the multiplication `m1 * m2`.
|
||||
* We also round to zero when it's near zero.
|
||||
* @function module:math.matrixMultiply
|
||||
* @param {...SVGMatrix} args - Matrix objects to multiply
|
||||
* @returns {SVGMatrix} The matrix object resulting from the calculation
|
||||
*/
|
||||
export const matrixMultiply = function (...args) {
|
||||
const m = args.reduceRight((prev, m1) => {
|
||||
return m1.multiply(prev);
|
||||
});
|
||||
|
||||
if (Math.abs(m.a) < NEAR_ZERO) { m.a = 0; }
|
||||
if (Math.abs(m.b) < NEAR_ZERO) { m.b = 0; }
|
||||
if (Math.abs(m.c) < NEAR_ZERO) { m.c = 0; }
|
||||
if (Math.abs(m.d) < NEAR_ZERO) { m.d = 0; }
|
||||
if (Math.abs(m.e) < NEAR_ZERO) { m.e = 0; }
|
||||
if (Math.abs(m.f) < NEAR_ZERO) { m.f = 0; }
|
||||
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* See if the given transformlist includes a non-indentity matrix transform.
|
||||
* @function module:math.hasMatrixTransform
|
||||
* @param {SVGTransformList} [tlist] - The transformlist to check
|
||||
* @returns {boolean} Whether or not a matrix transform was found
|
||||
*/
|
||||
export const hasMatrixTransform = function (tlist) {
|
||||
if (!tlist) { return false; }
|
||||
let num = tlist.numberOfItems;
|
||||
while (num--) {
|
||||
const xform = tlist.getItem(num);
|
||||
if (xform.type === 1 && !isIdentity(xform.matrix)) { return true; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} module:math.TransformedBox An object with the following values
|
||||
* @property {module:math.XYObject} tl - The top left coordinate
|
||||
* @property {module:math.XYObject} tr - The top right coordinate
|
||||
* @property {module:math.XYObject} bl - The bottom left coordinate
|
||||
* @property {module:math.XYObject} br - The bottom right coordinate
|
||||
* @property {PlainObject} aabox - Object with the following values:
|
||||
* @property {Float} aabox.x - Float with the axis-aligned x coordinate
|
||||
* @property {Float} aabox.y - Float with the axis-aligned y coordinate
|
||||
* @property {Float} aabox.width - Float with the axis-aligned width coordinate
|
||||
* @property {Float} aabox.height - Float with the axis-aligned height coordinate
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transforms a rectangle based on the given matrix.
|
||||
* @function module:math.transformBox
|
||||
* @param {Float} l - Float with the box's left coordinate
|
||||
* @param {Float} t - Float with the box's top coordinate
|
||||
* @param {Float} w - Float with the box width
|
||||
* @param {Float} h - Float with the box height
|
||||
* @param {SVGMatrix} m - Matrix object to transform the box by
|
||||
* @returns {module:math.TransformedBox}
|
||||
*/
|
||||
export const transformBox = function (l, t, w, h, m) {
|
||||
const tl = transformPoint(l, t, m),
|
||||
tr = transformPoint((l + w), t, m),
|
||||
bl = transformPoint(l, (t + h), m),
|
||||
br = transformPoint((l + w), (t + h), m),
|
||||
|
||||
minx = Math.min(tl.x, tr.x, bl.x, br.x),
|
||||
maxx = Math.max(tl.x, tr.x, bl.x, br.x),
|
||||
miny = Math.min(tl.y, tr.y, bl.y, br.y),
|
||||
maxy = Math.max(tl.y, tr.y, bl.y, br.y);
|
||||
|
||||
return {
|
||||
tl,
|
||||
tr,
|
||||
bl,
|
||||
br,
|
||||
aabox: {
|
||||
x: minx,
|
||||
y: miny,
|
||||
width: (maxx - minx),
|
||||
height: (maxy - miny)
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This returns a single matrix Transform for a given Transform List
|
||||
* (this is the equivalent of `SVGTransformList.consolidate()` but unlike
|
||||
* that method, this one does not modify the actual `SVGTransformList`).
|
||||
* This function is very liberal with its `min`, `max` arguments.
|
||||
* @function module:math.transformListToTransform
|
||||
* @param {SVGTransformList} tlist - The transformlist object
|
||||
* @param {Integer} [min=0] - Optional integer indicating start transform position
|
||||
* @param {Integer} [max] - Optional integer indicating end transform position;
|
||||
* defaults to one less than the tlist's `numberOfItems`
|
||||
* @returns {SVGTransform} A single matrix transform object
|
||||
*/
|
||||
export const transformListToTransform = function (tlist, min, max) {
|
||||
if (!tlist) {
|
||||
// Or should tlist = null have been prevented before this?
|
||||
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix());
|
||||
}
|
||||
min = min || 0;
|
||||
max = max || (tlist.numberOfItems - 1);
|
||||
min = Number.parseInt(min);
|
||||
max = Number.parseInt(max);
|
||||
if (min > max) { const temp = max; max = min; min = temp; }
|
||||
let m = svg.createSVGMatrix();
|
||||
for (let i = min; i <= max; ++i) {
|
||||
// if our indices are out of range, just use a harmless identity matrix
|
||||
const mtom = (i >= 0 && i < tlist.numberOfItems
|
||||
? tlist.getItem(i).matrix
|
||||
: svg.createSVGMatrix());
|
||||
m = matrixMultiply(m, mtom);
|
||||
}
|
||||
return svg.createSVGTransformFromMatrix(m);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the matrix object for a given element.
|
||||
* @function module:math.getMatrix
|
||||
* @param {Element} elem - The DOM element to check
|
||||
* @returns {SVGMatrix} The matrix object associated with the element's transformlist
|
||||
*/
|
||||
export const getMatrix = function (elem) {
|
||||
const tlist = getTransformList(elem);
|
||||
return transformListToTransform(tlist).matrix;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a 45 degree angle coordinate associated with the two given
|
||||
* coordinates.
|
||||
* @function module:math.snapToAngle
|
||||
* @param {Integer} x1 - First coordinate's x value
|
||||
* @param {Integer} y1 - First coordinate's y value
|
||||
* @param {Integer} x2 - Second coordinate's x value
|
||||
* @param {Integer} y2 - Second coordinate's y value
|
||||
* @returns {module:math.AngleCoord45}
|
||||
*/
|
||||
export const snapToAngle = function (x1, y1, x2, y2) {
|
||||
const snap = Math.PI / 4; // 45 degrees
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
const angle = Math.atan2(dy, dx);
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
const snapangle = Math.round(angle / snap) * snap;
|
||||
|
||||
return {
|
||||
x: x1 + dist * Math.cos(snapangle),
|
||||
y: y1 + dist * Math.sin(snapangle),
|
||||
a: snapangle
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if two rectangles (BBoxes objects) intersect each other.
|
||||
* @function module:math.rectsIntersect
|
||||
* @param {SVGRect} r1 - The first BBox-like object
|
||||
* @param {SVGRect} r2 - The second BBox-like object
|
||||
* @returns {boolean} True if rectangles intersect
|
||||
*/
|
||||
export const rectsIntersect = function (r1, r2) {
|
||||
return r2.x < (r1.x + r1.width) &&
|
||||
(r2.x + r2.width) > r1.x &&
|
||||
r2.y < (r1.y + r1.height) &&
|
||||
(r2.y + r2.height) > r1.y;
|
||||
};
|
||||
33
dist/common/namespaces.js
vendored
Normal file
33
dist/common/namespaces.js
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Namespaces or tools therefor.
|
||||
* @module namespaces
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common namepaces constants in alpha order.
|
||||
* @enum {string}
|
||||
* @type {PlainObject}
|
||||
* @memberof module:namespaces
|
||||
*/
|
||||
export const NS = {
|
||||
HTML: 'http://www.w3.org/1999/xhtml',
|
||||
MATH: 'http://www.w3.org/1998/Math/MathML',
|
||||
SE: 'http://svg-edit.googlecode.com',
|
||||
SVG: 'http://www.w3.org/2000/svg',
|
||||
XLINK: 'http://www.w3.org/1999/xlink',
|
||||
XML: 'http://www.w3.org/XML/1998/namespace',
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/' // see http://www.w3.org/TR/REC-xml-names/#xmlReserved
|
||||
};
|
||||
|
||||
/**
|
||||
* @function module:namespaces.getReverseNS
|
||||
* @returns {string} The NS with key values switched and lowercase
|
||||
*/
|
||||
export const getReverseNS = function () {
|
||||
const reverseNS = {};
|
||||
Object.entries(NS).forEach(([name, URI]) => {
|
||||
reverseNS[URI] = name.toLowerCase();
|
||||
});
|
||||
return reverseNS;
|
||||
};
|
||||
972
dist/common/svgpathseg.js
vendored
Normal file
972
dist/common/svgpathseg.js
vendored
Normal file
@@ -0,0 +1,972 @@
|
||||
/* eslint-disable import/unambiguous, max-len */
|
||||
/* globals SVGPathSeg, SVGPathSegMovetoRel, SVGPathSegMovetoAbs,
|
||||
SVGPathSegMovetoRel, SVGPathSegLinetoRel, SVGPathSegLinetoAbs,
|
||||
SVGPathSegLinetoHorizontalRel, SVGPathSegLinetoHorizontalAbs,
|
||||
SVGPathSegLinetoVerticalRel, SVGPathSegLinetoVerticalAbs,
|
||||
SVGPathSegClosePath, SVGPathSegCurvetoCubicRel,
|
||||
SVGPathSegCurvetoCubicAbs, SVGPathSegCurvetoCubicSmoothRel,
|
||||
SVGPathSegCurvetoCubicSmoothAbs, SVGPathSegCurvetoQuadraticRel,
|
||||
SVGPathSegCurvetoQuadraticAbs, SVGPathSegCurvetoQuadraticSmoothRel,
|
||||
SVGPathSegCurvetoQuadraticSmoothAbs, SVGPathSegArcRel, SVGPathSegArcAbs */
|
||||
/**
|
||||
* 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 ({@link 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.
|
||||
*/
|
||||
/* eslint-disable no-shadow, class-methods-use-this, jsdoc/require-jsdoc */
|
||||
// Linting: We avoid `no-shadow` as ESLint thinks these are still available globals
|
||||
// Linting: We avoid `class-methods-use-this` as this is a polyfill that must
|
||||
// follow the conventions
|
||||
(() => {
|
||||
if (!('SVGPathSeg' in window)) {
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
|
||||
class SVGPathSeg {
|
||||
constructor (type, typeAsLetter, owningPathSegList) {
|
||||
this.pathSegType = type;
|
||||
this.pathSegTypeAsLetter = typeAsLetter;
|
||||
this._owningPathSegList = owningPathSegList;
|
||||
}
|
||||
// Notify owning PathSegList on any changes so they can be synchronized back to the path element.
|
||||
_segmentChanged () {
|
||||
if (this._owningPathSegList) {
|
||||
this._owningPathSegList.segmentChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
SVGPathSeg.prototype.classname = 'SVGPathSeg';
|
||||
|
||||
SVGPathSeg.PATHSEG_UNKNOWN = 0;
|
||||
SVGPathSeg.PATHSEG_CLOSEPATH = 1;
|
||||
SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
|
||||
SVGPathSeg.PATHSEG_MOVETO_REL = 3;
|
||||
SVGPathSeg.PATHSEG_LINETO_ABS = 4;
|
||||
SVGPathSeg.PATHSEG_LINETO_REL = 5;
|
||||
SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
|
||||
SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
|
||||
SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
|
||||
SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
|
||||
SVGPathSeg.PATHSEG_ARC_ABS = 10;
|
||||
SVGPathSeg.PATHSEG_ARC_REL = 11;
|
||||
SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
|
||||
SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
|
||||
SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
|
||||
SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
|
||||
SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
|
||||
SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
|
||||
SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
|
||||
SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
|
||||
|
||||
class SVGPathSegClosePath extends SVGPathSeg {
|
||||
constructor (owningPathSegList) {
|
||||
super(SVGPathSeg.PATHSEG_CLOSEPATH, 'z', owningPathSegList);
|
||||
}
|
||||
toString () { return '[object SVGPathSegClosePath]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter; }
|
||||
clone () { return new SVGPathSegClosePath(undefined); }
|
||||
}
|
||||
|
||||
class SVGPathSegMovetoAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_MOVETO_ABS, 'M', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegMovetoAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegMovetoAbs(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegMovetoAbs.prototype, {
|
||||
x: {
|
||||
get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true
|
||||
},
|
||||
y: {
|
||||
get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true
|
||||
}
|
||||
});
|
||||
|
||||
class SVGPathSegMovetoRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_MOVETO_REL, 'm', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegMovetoRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegMovetoRel(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegMovetoRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegLinetoAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_ABS, 'L', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegLinetoAbs(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegLinetoAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegLinetoRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_REL, 'l', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegLinetoRel(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegLinetoRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoCubicAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
super(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;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoCubicAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoCubicAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x1: {get () { return this._x1; }, set (x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true},
|
||||
y1: {get () { return this._y1; }, set (y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true},
|
||||
x2: {get () { return this._x2; }, set (x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true},
|
||||
y2: {get () { return this._y2; }, set (y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoCubicRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
super(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;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoCubicRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoCubicRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x1: {get () { return this._x1; }, set (x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true},
|
||||
y1: {get () { return this._y1; }, set (y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true},
|
||||
x2: {get () { return this._x2; }, set (x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true},
|
||||
y2: {get () { return this._y2; }, set (y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoQuadraticAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x1, y1) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, 'Q', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoQuadraticAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoQuadraticAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x1: {get () { return this._x1; }, set (x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true},
|
||||
y1: {get () { return this._y1; }, set (y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoQuadraticRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x1, y1) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, 'q', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoQuadraticRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoQuadraticRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x1: {get () { return this._x1; }, set (x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true},
|
||||
y1: {get () { return this._y1; }, set (y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegArcAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
super(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;
|
||||
}
|
||||
toString () { return '[object SVGPathSegArcAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegArcAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
r1: {get () { return this._r1; }, set (r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true},
|
||||
r2: {get () { return this._r2; }, set (r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true},
|
||||
angle: {get () { return this._angle; }, set (angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true},
|
||||
largeArcFlag: {get () { return this._largeArcFlag; }, set (largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true},
|
||||
sweepFlag: {get () { return this._sweepFlag; }, set (sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegArcRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
super(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;
|
||||
}
|
||||
toString () { return '[object SVGPathSegArcRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegArcRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
r1: {get () { return this._r1; }, set (r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true},
|
||||
r2: {get () { return this._r2; }, set (r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true},
|
||||
angle: {get () { return this._angle; }, set (angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true},
|
||||
largeArcFlag: {get () { return this._largeArcFlag; }, set (largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true},
|
||||
sweepFlag: {get () { return this._sweepFlag; }, set (sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegLinetoHorizontalAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, 'H', owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoHorizontalAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x; }
|
||||
clone () { return new SVGPathSegLinetoHorizontalAbs(undefined, this._x); }
|
||||
}
|
||||
Object.defineProperty(SVGPathSegLinetoHorizontalAbs.prototype, 'x', {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true});
|
||||
|
||||
class SVGPathSegLinetoHorizontalRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, 'h', owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoHorizontalRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x; }
|
||||
clone () { return new SVGPathSegLinetoHorizontalRel(undefined, this._x); }
|
||||
}
|
||||
Object.defineProperty(SVGPathSegLinetoHorizontalRel.prototype, 'x', {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true});
|
||||
|
||||
class SVGPathSegLinetoVerticalAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, y) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, 'V', owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoVerticalAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegLinetoVerticalAbs(undefined, this._y); }
|
||||
}
|
||||
Object.defineProperty(SVGPathSegLinetoVerticalAbs.prototype, 'y', {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true});
|
||||
|
||||
class SVGPathSegLinetoVerticalRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, y) {
|
||||
super(SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, 'v', owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegLinetoVerticalRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegLinetoVerticalRel(undefined, this._y); }
|
||||
}
|
||||
Object.defineProperty(SVGPathSegLinetoVerticalRel.prototype, 'y', {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true});
|
||||
|
||||
class SVGPathSegCurvetoCubicSmoothAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x2, y2) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, 'S', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoCubicSmoothAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoCubicSmoothAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x2: {get () { return this._x2; }, set (x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true},
|
||||
y2: {get () { return this._y2; }, set (y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoCubicSmoothRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y, x2, y2) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, 's', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoCubicSmoothRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoCubicSmoothRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true},
|
||||
x2: {get () { return this._x2; }, set (x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true},
|
||||
y2: {get () { return this._y2; }, set (y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoQuadraticSmoothAbs extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, 'T', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoQuadraticSmoothAbs]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
class SVGPathSegCurvetoQuadraticSmoothRel extends SVGPathSeg {
|
||||
constructor (owningPathSegList, x, y) {
|
||||
super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, 't', owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
toString () { return '[object SVGPathSegCurvetoQuadraticSmoothRel]'; }
|
||||
_asPathString () { return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; }
|
||||
clone () { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); }
|
||||
}
|
||||
Object.defineProperties(SVGPathSegCurvetoQuadraticSmoothRel.prototype, {
|
||||
x: {get () { return this._x; }, set (x) { this._x = x; this._segmentChanged(); }, enumerable: true},
|
||||
y: {get () { return this._y; }, set (y) { this._y = y; this._segmentChanged(); }, enumerable: true}
|
||||
});
|
||||
|
||||
// Add createSVGPathSeg* functions to SVGPathElement.
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathElement.
|
||||
SVGPathElement.prototype.createSVGPathSegClosePath = function () { return new SVGPathSegClosePath(undefined); };
|
||||
SVGPathElement.prototype.createSVGPathSegMovetoAbs = function (x, y) { return new SVGPathSegMovetoAbs(undefined, x, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegMovetoRel = function (x, y) { return new SVGPathSegMovetoRel(undefined, x, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoAbs = function (x, y) { return new SVGPathSegLinetoAbs(undefined, x, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoRel = function (x, y) { return new SVGPathSegLinetoRel(undefined, x, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function (x, y, x1, y1, x2, y2) { return new SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function (x, y, x1, y1, x2, y2) { return new SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function (x, y, x1, y1) { return new SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function (x, y, x1, y1) { return new SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); };
|
||||
SVGPathElement.prototype.createSVGPathSegArcAbs = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); };
|
||||
SVGPathElement.prototype.createSVGPathSegArcRel = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function (x) { return new SVGPathSegLinetoHorizontalAbs(undefined, x); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function (x) { return new SVGPathSegLinetoHorizontalRel(undefined, x); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function (y) { return new SVGPathSegLinetoVerticalAbs(undefined, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function (y) { return new SVGPathSegLinetoVerticalRel(undefined, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function (x, y, x2, y2) { return new SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function (x, y, x2, y2) { return new SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function (x, y) { return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); };
|
||||
SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function (x, y) { return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); };
|
||||
|
||||
if (!('getPathSegAtLength' in 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.
|
||||
SVGPathElement.prototype.getPathSegAtLength = function (distance) {
|
||||
if (distance === undefined || !isFinite(distance)) {
|
||||
throw new Error('Invalid arguments.');
|
||||
}
|
||||
|
||||
const measurementElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
measurementElement.setAttribute('d', this.getAttribute('d'));
|
||||
let 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;
|
||||
};
|
||||
}
|
||||
|
||||
window.SVGPathSeg = SVGPathSeg;
|
||||
window.SVGPathSegClosePath = SVGPathSegClosePath;
|
||||
window.SVGPathSegMovetoAbs = SVGPathSegMovetoAbs;
|
||||
window.SVGPathSegMovetoRel = SVGPathSegMovetoRel;
|
||||
window.SVGPathSegLinetoAbs = SVGPathSegLinetoAbs;
|
||||
window.SVGPathSegLinetoRel = SVGPathSegLinetoRel;
|
||||
window.SVGPathSegCurvetoCubicAbs = SVGPathSegCurvetoCubicAbs;
|
||||
window.SVGPathSegCurvetoCubicRel = SVGPathSegCurvetoCubicRel;
|
||||
window.SVGPathSegCurvetoQuadraticAbs = SVGPathSegCurvetoQuadraticAbs;
|
||||
window.SVGPathSegCurvetoQuadraticRel = SVGPathSegCurvetoQuadraticRel;
|
||||
window.SVGPathSegArcAbs = SVGPathSegArcAbs;
|
||||
window.SVGPathSegArcRel = SVGPathSegArcRel;
|
||||
window.SVGPathSegLinetoHorizontalAbs = SVGPathSegLinetoHorizontalAbs;
|
||||
window.SVGPathSegLinetoHorizontalRel = SVGPathSegLinetoHorizontalRel;
|
||||
window.SVGPathSegLinetoVerticalAbs = SVGPathSegLinetoVerticalAbs;
|
||||
window.SVGPathSegLinetoVerticalRel = SVGPathSegLinetoVerticalRel;
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs = SVGPathSegCurvetoCubicSmoothAbs;
|
||||
window.SVGPathSegCurvetoCubicSmoothRel = SVGPathSegCurvetoCubicSmoothRel;
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs = SVGPathSegCurvetoQuadraticSmoothAbs;
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel = SVGPathSegCurvetoQuadraticSmoothRel;
|
||||
}
|
||||
|
||||
// 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: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
|
||||
class SVGPathSegList {
|
||||
constructor (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);
|
||||
}
|
||||
// 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.
|
||||
_checkPathSynchronizedToList () {
|
||||
this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
|
||||
}
|
||||
|
||||
_updateListFromPathMutations (mutationRecords) {
|
||||
if (!this._pathElement) {
|
||||
return;
|
||||
}
|
||||
let hasPathMutations = false;
|
||||
mutationRecords.forEach((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.
|
||||
_writeListToPath () {
|
||||
this._pathElementMutationObserver.disconnect();
|
||||
this._pathElement.setAttribute('d', 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.
|
||||
segmentChanged (pathSeg) {
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
clear () {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list.forEach((pathSeg) => {
|
||||
pathSeg._owningPathSegList = null;
|
||||
});
|
||||
this._list = [];
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
initialize (newItem) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list = [newItem];
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
_checkValidIndex (index) {
|
||||
if (isNaN(index) || index < 0 || index >= this.numberOfItems) {
|
||||
throw new Error('INDEX_SIZE_ERR');
|
||||
}
|
||||
}
|
||||
|
||||
getItem (index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
return this._list[index];
|
||||
}
|
||||
|
||||
insertItemBefore (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;
|
||||
}
|
||||
|
||||
replaceItem (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;
|
||||
}
|
||||
|
||||
removeItem (index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
const item = this._list[index];
|
||||
this._list.splice(index, 1);
|
||||
this._writeListToPath();
|
||||
return item;
|
||||
}
|
||||
|
||||
appendItem (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;
|
||||
}
|
||||
|
||||
// This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
|
||||
_parsePath (string) {
|
||||
if (!string || !string.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const owningPathSegList = this;
|
||||
|
||||
class Builder {
|
||||
constructor () {
|
||||
this.pathSegList = [];
|
||||
}
|
||||
appendSegment (pathSeg) {
|
||||
this.pathSegList.push(pathSeg);
|
||||
}
|
||||
}
|
||||
|
||||
class Source {
|
||||
constructor (string) {
|
||||
this._string = string;
|
||||
this._currentIndex = 0;
|
||||
this._endIndex = this._string.length;
|
||||
this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
|
||||
this._skipOptionalSpaces();
|
||||
}
|
||||
_isCurrentSpace () {
|
||||
const character = this._string[this._currentIndex];
|
||||
return character <= ' ' && (character === ' ' || character === '\n' || character === '\t' || character === '\r' || character === '\f');
|
||||
}
|
||||
|
||||
_skipOptionalSpaces () {
|
||||
while (this._currentIndex < this._endIndex && this._isCurrentSpace()) {
|
||||
this._currentIndex++;
|
||||
}
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
_skipOptionalSpacesOrDelimiter () {
|
||||
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;
|
||||
}
|
||||
|
||||
hasMoreData () {
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
peekSegmentType () {
|
||||
const lookahead = this._string[this._currentIndex];
|
||||
return this._pathSegTypeFromChar(lookahead);
|
||||
}
|
||||
|
||||
_pathSegTypeFromChar (lookahead) {
|
||||
switch (lookahead) {
|
||||
case 'Z':
|
||||
case 'z':
|
||||
return SVGPathSeg.PATHSEG_CLOSEPATH;
|
||||
case 'M':
|
||||
return SVGPathSeg.PATHSEG_MOVETO_ABS;
|
||||
case 'm':
|
||||
return SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
case 'L':
|
||||
return SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
case 'l':
|
||||
return SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
case 'C':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
|
||||
case 'c':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
|
||||
case 'Q':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
|
||||
case 'q':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
|
||||
case 'A':
|
||||
return SVGPathSeg.PATHSEG_ARC_ABS;
|
||||
case 'a':
|
||||
return SVGPathSeg.PATHSEG_ARC_REL;
|
||||
case 'H':
|
||||
return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
|
||||
case 'h':
|
||||
return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
|
||||
case 'V':
|
||||
return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
|
||||
case 'v':
|
||||
return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
|
||||
case 'S':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
|
||||
case 's':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
|
||||
case 'T':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
|
||||
case 't':
|
||||
return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
|
||||
default:
|
||||
return SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
_nextCommandHelper (lookahead, previousCommand) {
|
||||
// Check for remaining coordinates in the current command.
|
||||
if ((lookahead === '+' || lookahead === '-' || lookahead === '.' || (lookahead >= '0' && lookahead <= '9')) && previousCommand !== SVGPathSeg.PATHSEG_CLOSEPATH) {
|
||||
if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_ABS) {
|
||||
return SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
}
|
||||
if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_REL) {
|
||||
return SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
}
|
||||
return previousCommand;
|
||||
}
|
||||
return SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
|
||||
initialCommandIsMoveTo () {
|
||||
// If the path is empty it is still valid, so return true.
|
||||
if (!this.hasMoreData()) {
|
||||
return true;
|
||||
}
|
||||
const command = this.peekSegmentType();
|
||||
// Path must start with moveTo.
|
||||
return command === SVGPathSeg.PATHSEG_MOVETO_ABS || command === SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
}
|
||||
|
||||
// Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
|
||||
_parseNumber () {
|
||||
let exponent = 0;
|
||||
let integer = 0;
|
||||
let frac = 1;
|
||||
let decimal = 0;
|
||||
let sign = 1;
|
||||
let expsign = 1;
|
||||
|
||||
const 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.
|
||||
const 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) {
|
||||
let scanIntPartIndex = this._currentIndex - 1;
|
||||
let 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++;
|
||||
}
|
||||
}
|
||||
|
||||
let number = integer + decimal;
|
||||
number *= sign;
|
||||
|
||||
if (exponent) {
|
||||
number *= 10 ** (expsign * exponent);
|
||||
}
|
||||
|
||||
if (startIndex === this._currentIndex) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
_parseArcFlag () {
|
||||
if (this._currentIndex >= this._endIndex) {
|
||||
return undefined;
|
||||
}
|
||||
let flag = false;
|
||||
const flagChar = this._string.charAt(this._currentIndex++);
|
||||
if (flagChar === '0') {
|
||||
flag = false;
|
||||
} else if (flagChar === '1') {
|
||||
flag = true;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
return flag;
|
||||
}
|
||||
|
||||
parseSegment () {
|
||||
const lookahead = this._string[this._currentIndex];
|
||||
let command = this._pathSegTypeFromChar(lookahead);
|
||||
if (command === SVGPathSeg.PATHSEG_UNKNOWN) {
|
||||
// Possibly an implicit command. Not allowed if this is the first command.
|
||||
if (this._previousCommand === SVGPathSeg.PATHSEG_UNKNOWN) {
|
||||
return null;
|
||||
}
|
||||
command = this._nextCommandHelper(lookahead, this._previousCommand);
|
||||
if (command === SVGPathSeg.PATHSEG_UNKNOWN) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
this._currentIndex++;
|
||||
}
|
||||
|
||||
this._previousCommand = command;
|
||||
|
||||
switch (command) {
|
||||
case SVGPathSeg.PATHSEG_MOVETO_REL:
|
||||
return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_MOVETO_ABS:
|
||||
return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_REL:
|
||||
return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_ABS:
|
||||
return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
|
||||
return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
|
||||
return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
|
||||
return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
|
||||
return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_CLOSEPATH:
|
||||
this._skipOptionalSpaces();
|
||||
return new SVGPathSegClosePath(owningPathSegList);
|
||||
case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: {
|
||||
const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: {
|
||||
const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
} case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
|
||||
return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
|
||||
return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case SVGPathSeg.PATHSEG_ARC_REL: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
} case SVGPathSeg.PATHSEG_ARC_ABS: {
|
||||
const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
} default:
|
||||
throw new Error('Unknown path seg type.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const builder = new Builder();
|
||||
const source = new Source(string);
|
||||
|
||||
if (!source.initialCommandIsMoveTo()) {
|
||||
return [];
|
||||
}
|
||||
while (source.hasMoreData()) {
|
||||
const pathSeg = source.parseSegment();
|
||||
if (!pathSeg) {
|
||||
return [];
|
||||
}
|
||||
builder.appendSegment(pathSeg);
|
||||
}
|
||||
|
||||
return builder.pathSegList;
|
||||
}
|
||||
|
||||
// STATIC
|
||||
static _pathSegArrayAsString (pathSegArray) {
|
||||
let string = '';
|
||||
let first = true;
|
||||
pathSegArray.forEach((pathSeg) => {
|
||||
if (first) {
|
||||
first = false;
|
||||
string += pathSeg._asPathString();
|
||||
} else {
|
||||
string += ' ' + pathSeg._asPathString();
|
||||
}
|
||||
});
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
SVGPathSegList.prototype.classname = 'SVGPathSegList';
|
||||
|
||||
Object.defineProperty(SVGPathSegList.prototype, 'numberOfItems', {
|
||||
get () {
|
||||
this._checkPathSynchronizedToList();
|
||||
return this._list.length;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
// Add the pathSegList accessors to SVGPathElement.
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
|
||||
Object.defineProperties(SVGPathElement.prototype, {
|
||||
pathSegList: {
|
||||
get () {
|
||||
if (!this._pathSegList) {
|
||||
this._pathSegList = new SVGPathSegList(this);
|
||||
}
|
||||
return this._pathSegList;
|
||||
},
|
||||
enumerable: true
|
||||
},
|
||||
// TODO: The following are not implemented and simply return SVGPathElement.pathSegList.
|
||||
normalizedPathSegList: {get () { return this.pathSegList; }, enumerable: true},
|
||||
animatedPathSegList: {get () { return this.pathSegList; }, enumerable: true},
|
||||
animatedNormalizedPathSegList: {get () { return this.pathSegList; }, enumerable: true}
|
||||
});
|
||||
window.SVGPathSegList = SVGPathSegList;
|
||||
}
|
||||
})();
|
||||
397
dist/common/svgtransformlist.js
vendored
Normal file
397
dist/common/svgtransformlist.js
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
/**
|
||||
* Partial polyfill of `SVGTransformList`
|
||||
* @module SVGTransformList
|
||||
*
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
import {supportsNativeTransformLists} from './browser.js';
|
||||
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
/**
|
||||
* Helper function to convert `SVGTransform` to a string.
|
||||
* @param {SVGTransform} xform
|
||||
* @returns {string}
|
||||
*/
|
||||
function transformToString (xform) {
|
||||
const m = xform.matrix;
|
||||
let text = '';
|
||||
switch (xform.type) {
|
||||
case 1: // MATRIX
|
||||
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
|
||||
break;
|
||||
case 2: // TRANSLATE
|
||||
text = 'translate(' + m.e + ',' + m.f + ')';
|
||||
break;
|
||||
case 3: // SCALE
|
||||
if (m.a === m.d) {
|
||||
text = 'scale(' + m.a + ')';
|
||||
} else {
|
||||
text = 'scale(' + m.a + ',' + m.d + ')';
|
||||
}
|
||||
break;
|
||||
case 4: { // ROTATE
|
||||
let cx = 0;
|
||||
let cy = 0;
|
||||
// this prevents divide by zero
|
||||
if (xform.angle !== 0) {
|
||||
const K = 1 - m.a;
|
||||
cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
|
||||
cx = (m.e - m.b * cy) / K;
|
||||
}
|
||||
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of SVGTransformList objects.
|
||||
*/
|
||||
let listMap_ = {};
|
||||
|
||||
/**
|
||||
* @interface module:SVGTransformList.SVGEditTransformList
|
||||
* @property {Integer} numberOfItems unsigned long
|
||||
*/
|
||||
/**
|
||||
* @function module:SVGTransformList.SVGEditTransformList#clear
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* @function module:SVGTransformList.SVGEditTransformList#initialize
|
||||
* @param {SVGTransform} newItem
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
|
||||
* @function module:SVGTransformList.SVGEditTransformList#getItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
|
||||
* @function module:SVGTransformList.SVGEditTransformList#insertItemBefore
|
||||
* @param {SVGTransform} newItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
|
||||
* @function module:SVGTransformList.SVGEditTransformList#replaceItem
|
||||
* @param {SVGTransform} newItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
|
||||
* @function module:SVGTransformList.SVGEditTransformList#removeItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* @function module:SVGTransformList.SVGEditTransformList#appendItem
|
||||
* @param {SVGTransform} newItem
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* NOT IMPLEMENTED.
|
||||
* @ignore
|
||||
* @function module:SVGTransformList.SVGEditTransformList#createSVGTransformFromMatrix
|
||||
* @param {SVGMatrix} matrix
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
/**
|
||||
* NOT IMPLEMENTED.
|
||||
* @ignore
|
||||
* @function module:SVGTransformList.SVGEditTransformList#consolidate
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
|
||||
/**
|
||||
* SVGTransformList implementation for Webkit.
|
||||
* These methods do not currently raise any exceptions.
|
||||
* These methods also do not check that transforms are being inserted. This is basically
|
||||
* implementing as much of SVGTransformList that we need to get the job done.
|
||||
* @implements {module:SVGTransformList.SVGEditTransformList}
|
||||
*/
|
||||
export class SVGTransformList { // eslint-disable-line no-shadow
|
||||
/**
|
||||
* @param {Element} elem
|
||||
* @returns {SVGTransformList}
|
||||
*/
|
||||
constructor (elem) {
|
||||
this._elem = elem || null;
|
||||
this._xforms = [];
|
||||
// TODO: how do we capture the undo-ability in the changed transform list?
|
||||
this._update = function () {
|
||||
let tstr = '';
|
||||
// /* const concatMatrix = */ svgroot.createSVGMatrix();
|
||||
for (let i = 0; i < this.numberOfItems; ++i) {
|
||||
const xform = this._list.getItem(i);
|
||||
tstr += transformToString(xform) + ' ';
|
||||
}
|
||||
this._elem.setAttribute('transform', tstr);
|
||||
};
|
||||
this._list = this;
|
||||
this._init = function () {
|
||||
// Transform attribute parser
|
||||
let str = this._elem.getAttribute('transform');
|
||||
if (!str) { return; }
|
||||
|
||||
// TODO: Add skew support in future
|
||||
const re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
|
||||
// const re = /\s*(?<xform>(?:scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
|
||||
let m = true;
|
||||
while (m) {
|
||||
m = str.match(re);
|
||||
str = str.replace(re, '');
|
||||
if (m && m[1]) {
|
||||
const x = m[1];
|
||||
const bits = x.split(/\s*\(/);
|
||||
const name = bits[0];
|
||||
const valBits = bits[1].match(/\s*(.*?)\s*\)/);
|
||||
valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -');
|
||||
const valArr = valBits[1].split(/[, ]+/);
|
||||
const letters = 'abcdef'.split('');
|
||||
/*
|
||||
if (m && m.groups.xform) {
|
||||
const x = m.groups.xform;
|
||||
const [name, bits] = x.split(/\s*\(/);
|
||||
const valBits = bits.match(/\s*(?<nonWhitespace>.*?)\s*\)/);
|
||||
valBits.groups.nonWhitespace = valBits.groups.nonWhitespace.replace(
|
||||
/(?<digit>\d)-/g, '$<digit> -'
|
||||
);
|
||||
const valArr = valBits.groups.nonWhitespace.split(/[, ]+/);
|
||||
const letters = [...'abcdef'];
|
||||
*/
|
||||
const mtx = svgroot.createSVGMatrix();
|
||||
Object.values(valArr).forEach(function (item, i) {
|
||||
valArr[i] = Number.parseFloat(item);
|
||||
if (name === 'matrix') {
|
||||
mtx[letters[i]] = valArr[i];
|
||||
}
|
||||
});
|
||||
const xform = svgroot.createSVGTransform();
|
||||
const fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1);
|
||||
const values = name === 'matrix' ? [mtx] : valArr;
|
||||
|
||||
if (name === 'scale' && values.length === 1) {
|
||||
values.push(values[0]);
|
||||
} else if (name === 'translate' && values.length === 1) {
|
||||
values.push(0);
|
||||
} else if (name === 'rotate' && values.length === 1) {
|
||||
values.push(0, 0);
|
||||
}
|
||||
xform[fname](...values);
|
||||
this._list.appendItem(xform);
|
||||
}
|
||||
}
|
||||
};
|
||||
this._removeFromOtherLists = function (item) {
|
||||
if (item) {
|
||||
// Check if this transform is already in a transformlist, and
|
||||
// remove it if so.
|
||||
Object.values(listMap_).some((tl) => {
|
||||
for (let i = 0, len = tl._xforms.length; i < len; ++i) {
|
||||
if (tl._xforms[i] === item) {
|
||||
tl.removeItem(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.numberOfItems = 0;
|
||||
}
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
clear () {
|
||||
this.numberOfItems = 0;
|
||||
this._xforms = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SVGTransform} newItem
|
||||
* @returns {void}
|
||||
*/
|
||||
initialize (newItem) {
|
||||
this.numberOfItems = 1;
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms = [newItem];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Integer} index unsigned long
|
||||
* @throws {Error}
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
getItem (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
return this._xforms[index];
|
||||
}
|
||||
const err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SVGTransform} newItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
insertItemBefore (newItem, index) {
|
||||
let retValue = null;
|
||||
if (index >= 0) {
|
||||
if (index < this.numberOfItems) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
const newxforms = new Array(this.numberOfItems + 1);
|
||||
// TODO: use array copying and slicing
|
||||
let i;
|
||||
for (i = 0; i < index; ++i) {
|
||||
newxforms[i] = this._xforms[i];
|
||||
}
|
||||
newxforms[i] = newItem;
|
||||
for (let j = i + 1; i < this.numberOfItems; ++j, ++i) {
|
||||
newxforms[j] = this._xforms[i];
|
||||
}
|
||||
this.numberOfItems++;
|
||||
this._xforms = newxforms;
|
||||
retValue = newItem;
|
||||
this._list._update();
|
||||
} else {
|
||||
retValue = this._list.appendItem(newItem);
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SVGTransform} newItem
|
||||
* @param {Integer} index unsigned long
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
replaceItem (newItem, index) {
|
||||
let retValue = null;
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms[index] = newItem;
|
||||
retValue = newItem;
|
||||
this._list._update();
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Integer} index unsigned long
|
||||
* @throws {Error}
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
removeItem (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
const retValue = this._xforms[index];
|
||||
const newxforms = new Array(this.numberOfItems - 1);
|
||||
let i;
|
||||
for (i = 0; i < index; ++i) {
|
||||
newxforms[i] = this._xforms[i];
|
||||
}
|
||||
for (let j = i; j < this.numberOfItems - 1; ++j, ++i) {
|
||||
newxforms[j] = this._xforms[i + 1];
|
||||
}
|
||||
this.numberOfItems--;
|
||||
this._xforms = newxforms;
|
||||
this._list._update();
|
||||
return retValue;
|
||||
}
|
||||
const err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SVGTransform} newItem
|
||||
* @returns {SVGTransform}
|
||||
*/
|
||||
appendItem (newItem) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms.push(newItem);
|
||||
this.numberOfItems++;
|
||||
this._list._update();
|
||||
return newItem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @function module:SVGTransformList.resetListMap
|
||||
* @returns {void}
|
||||
*/
|
||||
export const resetListMap = function () {
|
||||
listMap_ = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes transforms of the given element from the map.
|
||||
* @function module:SVGTransformList.removeElementFromListMap
|
||||
* @param {Element} elem - a DOM Element
|
||||
* @returns {void}
|
||||
*/
|
||||
export let removeElementFromListMap = function (elem) { // eslint-disable-line import/no-mutable-exports
|
||||
if (elem.id && listMap_[elem.id]) {
|
||||
delete listMap_[elem.id];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object that behaves like a `SVGTransformList` for the given DOM element.
|
||||
* @function module:SVGTransformList.getTransformList
|
||||
* @param {Element} elem - DOM element to get a transformlist from
|
||||
* @todo The polyfill should have `SVGAnimatedTransformList` and this should use it
|
||||
* @returns {SVGAnimatedTransformList|SVGTransformList}
|
||||
*/
|
||||
export const getTransformList = function (elem) {
|
||||
if (!supportsNativeTransformLists()) {
|
||||
const id = elem.id || 'temp';
|
||||
let t = listMap_[id];
|
||||
if (!t || id === 'temp') {
|
||||
listMap_[id] = new SVGTransformList(elem);
|
||||
listMap_[id]._init();
|
||||
t = listMap_[id];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
if (elem.transform) {
|
||||
return elem.transform.baseVal;
|
||||
}
|
||||
if (elem.gradientTransform) {
|
||||
return elem.gradientTransform.baseVal;
|
||||
}
|
||||
if (elem.patternTransform) {
|
||||
return elem.patternTransform.baseVal;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @callback module:SVGTransformList.removeElementFromListMap
|
||||
* @param {Element} elem
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* Replace `removeElementFromListMap` for unit-testing.
|
||||
* @function module:SVGTransformList.changeRemoveElementFromListMap
|
||||
* @param {module:SVGTransformList.removeElementFromListMap} cb Passed a single argument `elem`
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
export const changeRemoveElementFromListMap = function (cb) { // eslint-disable-line promise/prefer-await-to-callbacks
|
||||
removeElementFromListMap = cb;
|
||||
};
|
||||
313
dist/common/units.js
vendored
Normal file
313
dist/common/units.js
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Tools for working with units.
|
||||
* @module units
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
|
||||
const wAttrs = ['x', 'x1', 'cx', 'rx', 'width'];
|
||||
const hAttrs = ['y', 'y1', 'cy', 'ry', 'height'];
|
||||
const unitAttrs = ['r', 'radius', ...wAttrs, ...hAttrs];
|
||||
// unused
|
||||
/*
|
||||
const unitNumMap = {
|
||||
'%': 2,
|
||||
em: 3,
|
||||
ex: 4,
|
||||
px: 5,
|
||||
cm: 6,
|
||||
mm: 7,
|
||||
in: 8,
|
||||
pt: 9,
|
||||
pc: 10
|
||||
};
|
||||
*/
|
||||
// Container of elements.
|
||||
let elementContainer_;
|
||||
|
||||
// Stores mapping of unit type to user coordinates.
|
||||
let typeMap_ = {};
|
||||
|
||||
/**
|
||||
* @interface module:units.ElementContainer
|
||||
*/
|
||||
/**
|
||||
* @function module:units.ElementContainer#getBaseUnit
|
||||
* @returns {string} The base unit type of the container ('em')
|
||||
*/
|
||||
/**
|
||||
* @function module:units.ElementContainer#getElement
|
||||
* @returns {?Element} An element in the container given an id
|
||||
*/
|
||||
/**
|
||||
* @function module:units.ElementContainer#getHeight
|
||||
* @returns {Float} The container's height
|
||||
*/
|
||||
/**
|
||||
* @function module:units.ElementContainer#getWidth
|
||||
* @returns {Float} The container's width
|
||||
*/
|
||||
/**
|
||||
* @function module:units.ElementContainer#getRoundDigits
|
||||
* @returns {Integer} The number of digits number should be rounded to
|
||||
*/
|
||||
|
||||
/* eslint-disable jsdoc/valid-types */
|
||||
/**
|
||||
* @typedef {PlainObject} module:units.TypeMap
|
||||
* @property {Float} em
|
||||
* @property {Float} ex
|
||||
* @property {Float} in
|
||||
* @property {Float} cm
|
||||
* @property {Float} mm
|
||||
* @property {Float} pt
|
||||
* @property {Float} pc
|
||||
* @property {Integer} px
|
||||
* @property {0} %
|
||||
*/
|
||||
/* eslint-enable jsdoc/valid-types */
|
||||
|
||||
/**
|
||||
* Initializes this module.
|
||||
*
|
||||
* @function module:units.init
|
||||
* @param {module:units.ElementContainer} elementContainer - An object implementing the ElementContainer interface.
|
||||
* @returns {void}
|
||||
*/
|
||||
export const init = function (elementContainer) {
|
||||
elementContainer_ = elementContainer;
|
||||
|
||||
// Get correct em/ex values by creating a temporary SVG.
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
document.body.append(svg);
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('width', '1em');
|
||||
rect.setAttribute('height', '1ex');
|
||||
rect.setAttribute('x', '1in');
|
||||
svg.append(rect);
|
||||
const bb = rect.getBBox();
|
||||
svg.remove();
|
||||
|
||||
const inch = bb.x;
|
||||
typeMap_ = {
|
||||
em: bb.width,
|
||||
ex: bb.height,
|
||||
in: inch,
|
||||
cm: inch / 2.54,
|
||||
mm: inch / 25.4,
|
||||
pt: inch / 72,
|
||||
pc: inch / 6,
|
||||
px: 1,
|
||||
'%': 0
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Group: Unit conversion functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @function module:units.getTypeMap
|
||||
* @returns {module:units.TypeMap} The unit object with values for each unit
|
||||
*/
|
||||
export const getTypeMap = function () {
|
||||
return typeMap_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {GenericArray} module:units.CompareNumbers
|
||||
* @property {Integer} length 2
|
||||
* @property {Float} 0
|
||||
* @property {Float} 1
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rounds a given value to a float with number of digits defined in
|
||||
* `round_digits` of `saveOptions`
|
||||
*
|
||||
* @function module:units.shortFloat
|
||||
* @param {string|Float|module:units.CompareNumbers} val - The value (or Array of two numbers) to be rounded
|
||||
* @returns {Float|string} If a string/number was given, returns a Float. If an array, return a string
|
||||
* with comma-separated floats
|
||||
*/
|
||||
export const shortFloat = function (val) {
|
||||
const digits = elementContainer_.getRoundDigits();
|
||||
if (!isNaN(val)) {
|
||||
return Number(Number(val).toFixed(digits));
|
||||
}
|
||||
if (Array.isArray(val)) {
|
||||
return shortFloat(val[0]) + ',' + shortFloat(val[1]);
|
||||
}
|
||||
return Number.parseFloat(val).toFixed(digits) - 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the number to given unit or baseUnit.
|
||||
* @function module:units.convertUnit
|
||||
* @param {string|Float} val
|
||||
* @param {"em"|"ex"|"in"|"cm"|"mm"|"pt"|"pc"|"px"|"%"} [unit]
|
||||
* @returns {Float}
|
||||
*/
|
||||
export const convertUnit = function (val, unit) {
|
||||
unit = unit || elementContainer_.getBaseUnit();
|
||||
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
|
||||
// const val = baseVal.valueInSpecifiedUnits;
|
||||
// baseVal.convertToSpecifiedUnits(1);
|
||||
return shortFloat(val / typeMap_[unit]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets an element's attribute based on the unit in its current value.
|
||||
*
|
||||
* @function module:units.setUnitAttr
|
||||
* @param {Element} elem - DOM element to be changed
|
||||
* @param {string} attr - Name of the attribute associated with the value
|
||||
* @param {string} val - Attribute value to convert
|
||||
* @returns {void}
|
||||
*/
|
||||
export const setUnitAttr = function (elem, attr, val) {
|
||||
// if (!isNaN(val)) {
|
||||
// New value is a number, so check currently used unit
|
||||
// const oldVal = elem.getAttribute(attr);
|
||||
|
||||
// Enable this for alternate mode
|
||||
// if (oldVal !== null && (isNaN(oldVal) || elementContainer_.getBaseUnit() !== 'px')) {
|
||||
// // Old value was a number, so get unit, then convert
|
||||
// let unit;
|
||||
// if (oldVal.substr(-1) === '%') {
|
||||
// const res = getResolution();
|
||||
// unit = '%';
|
||||
// val *= 100;
|
||||
// if (wAttrs.includes(attr)) {
|
||||
// val = val / res.w;
|
||||
// } else if (hAttrs.includes(attr)) {
|
||||
// val = val / res.h;
|
||||
// } else {
|
||||
// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2);
|
||||
// }
|
||||
// } else {
|
||||
// if (elementContainer_.getBaseUnit() !== 'px') {
|
||||
// unit = elementContainer_.getBaseUnit();
|
||||
// } else {
|
||||
// unit = oldVal.substr(-2);
|
||||
// }
|
||||
// val = val / typeMap_[unit];
|
||||
// }
|
||||
//
|
||||
// val += unit;
|
||||
// }
|
||||
// }
|
||||
elem.setAttribute(attr, val);
|
||||
};
|
||||
|
||||
const attrsToConvert = {
|
||||
line: ['x1', 'x2', 'y1', 'y2'],
|
||||
circle: ['cx', 'cy', 'r'],
|
||||
ellipse: ['cx', 'cy', 'rx', 'ry'],
|
||||
foreignObject: ['x', 'y', 'width', 'height'],
|
||||
rect: ['x', 'y', 'width', 'height'],
|
||||
image: ['x', 'y', 'width', 'height'],
|
||||
use: ['x', 'y', 'width', 'height'],
|
||||
text: ['x', 'y']
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts all applicable attributes to the configured baseUnit.
|
||||
* @function module:units.convertAttrs
|
||||
* @param {Element} element - A DOM element whose attributes should be converted
|
||||
* @returns {void}
|
||||
*/
|
||||
export const convertAttrs = function (element) {
|
||||
const elName = element.tagName;
|
||||
const unit = elementContainer_.getBaseUnit();
|
||||
const attrs = attrsToConvert[elName];
|
||||
if (!attrs) { return; }
|
||||
|
||||
const len = attrs.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const attr = attrs[i];
|
||||
const cur = element.getAttribute(attr);
|
||||
if (cur) {
|
||||
if (!isNaN(cur)) {
|
||||
element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
|
||||
}
|
||||
// else {
|
||||
// Convert existing?
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts given values to numbers. Attributes must be supplied in
|
||||
* case a percentage is given.
|
||||
*
|
||||
* @function module:units.convertToNum
|
||||
* @param {string} attr - Name of the attribute associated with the value
|
||||
* @param {string} val - Attribute value to convert
|
||||
* @returns {Float} The converted number
|
||||
*/
|
||||
export const convertToNum = function (attr, val) {
|
||||
// Return a number if that's what it already is
|
||||
if (!isNaN(val)) { return val - 0; }
|
||||
if (val.substr(-1) === '%') {
|
||||
// Deal with percentage, depends on attribute
|
||||
const num = val.substr(0, val.length - 1) / 100;
|
||||
const width = elementContainer_.getWidth();
|
||||
const height = elementContainer_.getHeight();
|
||||
|
||||
if (wAttrs.includes(attr)) {
|
||||
return num * width;
|
||||
}
|
||||
if (hAttrs.includes(attr)) {
|
||||
return num * height;
|
||||
}
|
||||
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2);
|
||||
}
|
||||
const unit = val.substr(-2);
|
||||
const num = val.substr(0, val.length - 2);
|
||||
// Note that this multiplication turns the string into a number
|
||||
return num * typeMap_[unit];
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an attribute's value is in a valid format.
|
||||
* @function module:units.isValidUnit
|
||||
* @param {string} attr - The name of the attribute associated with the value
|
||||
* @param {string} val - The attribute value to check
|
||||
* @param {Element} selectedElement
|
||||
* @returns {boolean} Whether the unit is valid
|
||||
*/
|
||||
export const isValidUnit = function (attr, val, selectedElement) {
|
||||
if (unitAttrs.includes(attr)) {
|
||||
// True if it's just a number
|
||||
if (!isNaN(val)) {
|
||||
return true;
|
||||
}
|
||||
// Not a number, check if it has a valid unit
|
||||
val = val.toLowerCase();
|
||||
return Object.keys(typeMap_).some((unit) => {
|
||||
const re = new RegExp('^-?[\\d\\.]+' + unit + '$');
|
||||
return re.test(val);
|
||||
});
|
||||
}
|
||||
if (attr === 'id') {
|
||||
// if we're trying to change the id, make sure it's not already present in the doc
|
||||
// and the id value is valid.
|
||||
|
||||
let result = false;
|
||||
// because getElem() can throw an exception in the case of an invalid id
|
||||
// (according to https://www.w3.org/TR/xml-id/ IDs must be a NCName)
|
||||
// we wrap it in an exception and only return true if the ID was valid and
|
||||
// not already present
|
||||
try {
|
||||
const elem = elementContainer_.getElement(val);
|
||||
result = (!elem || elem === selectedElement);
|
||||
} catch (e) {}
|
||||
return result;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
1363
dist/common/utilities.js
vendored
Normal file
1363
dist/common/utilities.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
54
dist/editor/browser-not-supported.html
vendored
Normal file
54
dist/editor/browser-not-supported.html
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1"/>
|
||||
<link rel="icon" type="image/png" href="images/logo.png"/>
|
||||
<link rel="stylesheet" href="svg-editor.css"/>
|
||||
<title>Browser does not support SVG | SVG-edit</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
p {
|
||||
font-size: 0.8em;
|
||||
font-family: Verdana, Helvetica, Arial;
|
||||
color: #000;
|
||||
padding: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
#logo {
|
||||
float: left;
|
||||
padding: 10px;
|
||||
}
|
||||
#caniuse {
|
||||
position: absolute;
|
||||
top: 7em;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#caniuse > iframe {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img id="logo" src="images/logo.png" width="48" height="48" alt="SVG-edit logo" />
|
||||
<p>Sorry, but your browser does not support SVG. Below is a list of
|
||||
alternate browsers and versions that support SVG and SVG-edit
|
||||
(from <a href="https://caniuse.com/#cats=SVG">caniuse.com</a>).
|
||||
</p>
|
||||
<p>Try the latest version of
|
||||
<a href="https://www.getfirefox.com">Firefox</a>,
|
||||
<a href="https://www.google.com/chrome/">Chrome</a>,
|
||||
<a href="https://www.apple.com/safari/">Safari</a>,
|
||||
<a href="https://www.opera.com/download">Opera</a> or
|
||||
<a href="https://support.microsoft.com/en-us/help/17621/internet-explorer-downloads">Internet Explorer</a>.
|
||||
</p>
|
||||
<div id="caniuse">
|
||||
<iframe src="https://caniuse.com/#cats=SVG"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
17
dist/editor/embedapi.html
vendored
Normal file
17
dist/editor/embedapi.html
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Embed API</title>
|
||||
<link rel="icon" type="image/png" href="images/logo.png"/>
|
||||
<script src="jquery.min.js"></script>
|
||||
<script type="module" src="embedapi-dom.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="load">Load example</button>
|
||||
<button id="save">Save data</button>
|
||||
<button id="exportPNG">Export data to PNG</button>
|
||||
<button id="exportPDF">Export data to PDF</button>
|
||||
<br/>
|
||||
</body>
|
||||
</html>
|
||||
395
dist/editor/embedapi.js
vendored
Normal file
395
dist/editor/embedapi.js
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* Handles underlying communication between the embedding window and the
|
||||
* editor frame.
|
||||
* @module EmbeddedSVGEdit
|
||||
*/
|
||||
|
||||
let cbid = 0;
|
||||
|
||||
/**
|
||||
* @callback module:EmbeddedSVGEdit.CallbackSetter
|
||||
* @param {GenericCallback} newCallback Callback to be stored (signature dependent on function)
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* @callback module:EmbeddedSVGEdit.CallbackSetGetter
|
||||
* @param {...any} args Signature dependent on the function
|
||||
* @returns {module:EmbeddedSVGEdit.CallbackSetter}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} funcName
|
||||
* @returns {module:EmbeddedSVGEdit.CallbackSetGetter}
|
||||
*/
|
||||
function getCallbackSetter (funcName) {
|
||||
return function (...args) {
|
||||
const that = this, // New callback
|
||||
callbackID = this.send(funcName, args, function () { /* */ }); // The callback (currently it's nothing, but will be set later)
|
||||
|
||||
return function (newCallback) {
|
||||
that.callbacks[callbackID] = newCallback; // Set callback
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Having this separate from messageListener allows us to
|
||||
* avoid using JSON parsing (and its limitations) in the case
|
||||
* of same domain control.
|
||||
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
|
||||
* @param {PlainObject} data
|
||||
* @param {JSON} data.result
|
||||
* @param {string} data.error
|
||||
* @param {Integer} data.id
|
||||
* @returns {void}
|
||||
*/
|
||||
function addCallback (t, {result, error, id: callbackID}) {
|
||||
if (typeof callbackID === 'number' && t.callbacks[callbackID]) {
|
||||
// These should be safe both because we check `cbid` is numeric and
|
||||
// because the calls are from trusted origins
|
||||
if (result) {
|
||||
t.callbacks[callbackID](result); // lgtm [js/unvalidated-dynamic-method-call]
|
||||
} else {
|
||||
t.callbacks[callbackID](error, 'error'); // lgtm [js/unvalidated-dynamic-method-call]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Event} e
|
||||
* @returns {void}
|
||||
*/
|
||||
function messageListener (e) {
|
||||
// We accept and post strings as opposed to objects for the sake of IE9 support; this
|
||||
// will most likely be changed in the future
|
||||
if (!e.data || !['string', 'object'].includes(typeof e.data)) {
|
||||
return;
|
||||
}
|
||||
const {allowedOrigins} = this,
|
||||
data = typeof e.data === 'object' ? e.data : JSON.parse(e.data);
|
||||
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
|
||||
e.source !== this.frame.contentWindow ||
|
||||
(!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin))
|
||||
) {
|
||||
// eslint-disable-next-line no-console -- Info for developers
|
||||
console.error(
|
||||
`The origin ${e.origin} was not whitelisted as an origin from ` +
|
||||
`which responses may be received by this ${window.origin} script.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
addCallback(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback module:EmbeddedSVGEdit.MessageListener
|
||||
* @param {MessageEvent} e
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
|
||||
* @returns {module:EmbeddedSVGEdit.MessageListener} Event listener
|
||||
*/
|
||||
function getMessageListener (t) {
|
||||
return function (e) {
|
||||
messageListener.call(t, e);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedded SVG-edit API.
|
||||
* General usage:
|
||||
* - Have an iframe somewhere pointing to a version of svg-edit > r1000.
|
||||
* @example
|
||||
// Initialize the magic with:
|
||||
const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
|
||||
|
||||
// Pass functions in this format:
|
||||
svgCanvas.setSvgString('string');
|
||||
|
||||
// Or if a callback is needed:
|
||||
svgCanvas.setSvgString('string')(function (data, error) {
|
||||
if (error) {
|
||||
// There was an error
|
||||
} else {
|
||||
// Handle data
|
||||
}
|
||||
});
|
||||
|
||||
// Everything is done with the same API as the real svg-edit,
|
||||
// and all documentation is unchanged.
|
||||
|
||||
// However, this file depends on the postMessage API which
|
||||
// can only support JSON-serializable arguments and
|
||||
// return values, so, for example, arguments whose value is
|
||||
// 'undefined', a function, a non-finite number, or a built-in
|
||||
// object like Date(), RegExp(), etc. will most likely not behave
|
||||
// as expected. In such a case one may need to host
|
||||
// the SVG editor on the same domain and reference the
|
||||
// JavaScript methods on the frame itself.
|
||||
|
||||
// The only other difference is when handling returns:
|
||||
// the callback notation is used instead.
|
||||
const blah = new EmbeddedSVGEdit(window.frames.svgedit);
|
||||
blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {
|
||||
a: 'tree', b: 6, c: 9
|
||||
})(function () { console.log('GET DATA', args); });
|
||||
*
|
||||
* @memberof module:EmbeddedSVGEdit
|
||||
*/
|
||||
class EmbeddedSVGEdit {
|
||||
/**
|
||||
* @param {HTMLIFrameElement} frame
|
||||
* @param {string[]} [allowedOrigins=[]] Array of origins from which incoming
|
||||
* messages will be allowed when same origin is not used; defaults to none.
|
||||
* If supplied, it should probably be the same as svgEditor's allowedOrigins
|
||||
*/
|
||||
constructor (frame, allowedOrigins) {
|
||||
const that = this;
|
||||
this.allowedOrigins = allowedOrigins || [];
|
||||
// Initialize communication
|
||||
this.frame = frame;
|
||||
this.callbacks = {};
|
||||
// List of functions extracted with this:
|
||||
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
|
||||
|
||||
// for (const i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
|
||||
// const functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
|
||||
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
|
||||
// 'moveSelectedToLayer', 'clear'];
|
||||
|
||||
// Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
|
||||
// const {svgCanvas} = frame.contentWindow;
|
||||
// const l = [];
|
||||
// for (const i in svgCanvas) { if (typeof svgCanvas[i] === 'function') { l.push(i);} };
|
||||
// alert("['" + l.join("', '") + "']");
|
||||
// Run in svgedit itself
|
||||
const functions = [
|
||||
'addExtension',
|
||||
'addSVGElementFromJson',
|
||||
'addToSelection',
|
||||
'alignSelectedElements',
|
||||
'assignAttributes',
|
||||
'bind',
|
||||
'call',
|
||||
'changeSelectedAttribute',
|
||||
'cleanupElement',
|
||||
'clear',
|
||||
'clearSelection',
|
||||
'clearSvgContentElement',
|
||||
'cloneLayer',
|
||||
'cloneSelectedElements',
|
||||
'convertGradients',
|
||||
'convertToGroup',
|
||||
'convertToNum',
|
||||
'convertToPath',
|
||||
'copySelectedElements',
|
||||
'createLayer',
|
||||
'cutSelectedElements',
|
||||
'cycleElement',
|
||||
'deleteCurrentLayer',
|
||||
'deleteSelectedElements',
|
||||
'embedImage',
|
||||
'exportPDF',
|
||||
'findDefs',
|
||||
'getBBox',
|
||||
'getBlur',
|
||||
'getBold',
|
||||
'getColor',
|
||||
'getContentElem',
|
||||
'getCurrentDrawing',
|
||||
'getDocumentTitle',
|
||||
'getEditorNS',
|
||||
'getElem',
|
||||
'getFillOpacity',
|
||||
'getFontColor',
|
||||
'getFontFamily',
|
||||
'getFontSize',
|
||||
'getHref',
|
||||
'getId',
|
||||
'getIntersectionList',
|
||||
'getItalic',
|
||||
'getMode',
|
||||
'getMouseTarget',
|
||||
'getNextId',
|
||||
'getOffset',
|
||||
'getOpacity',
|
||||
'getPaintOpacity',
|
||||
'getPrivateMethods',
|
||||
'getRefElem',
|
||||
'getResolution',
|
||||
'getRootElem',
|
||||
'getRotationAngle',
|
||||
'getSelectedElems',
|
||||
'getStrokeOpacity',
|
||||
'getStrokeWidth',
|
||||
'getStrokedBBox',
|
||||
'getStyle',
|
||||
'getSvgString',
|
||||
'getText',
|
||||
'getTitle',
|
||||
'getTransformList',
|
||||
'getUIStrings',
|
||||
'getUrlFromAttr',
|
||||
'getVersion',
|
||||
'getVisibleElements',
|
||||
'getVisibleElementsAndBBoxes',
|
||||
'getZoom',
|
||||
'groupSelectedElements',
|
||||
'groupSvgElem',
|
||||
'hasMatrixTransform',
|
||||
'identifyLayers',
|
||||
'importSvgString',
|
||||
'leaveContext',
|
||||
'linkControlPoints',
|
||||
'makeHyperlink',
|
||||
'matrixMultiply',
|
||||
'mergeAllLayers',
|
||||
'mergeLayer',
|
||||
'moveSelectedElements',
|
||||
'moveSelectedToLayer',
|
||||
'moveToBottomSelectedElement',
|
||||
'moveToTopSelectedElement',
|
||||
'moveUpDownSelected',
|
||||
'open',
|
||||
'pasteElements',
|
||||
'prepareSvg',
|
||||
'pushGroupProperties',
|
||||
'randomizeIds',
|
||||
'rasterExport',
|
||||
'ready',
|
||||
'recalculateAllSelectedDimensions',
|
||||
'recalculateDimensions',
|
||||
'remapElement',
|
||||
'removeFromSelection',
|
||||
'removeHyperlink',
|
||||
'removeUnusedDefElems',
|
||||
'renameCurrentLayer',
|
||||
'round',
|
||||
'runExtensions',
|
||||
'sanitizeSvg',
|
||||
'save',
|
||||
'selectAllInCurrentLayer',
|
||||
'selectOnly',
|
||||
'setBBoxZoom',
|
||||
'setBackground',
|
||||
'setBlur',
|
||||
'setBlurNoUndo',
|
||||
'setBlurOffsets',
|
||||
'setBold',
|
||||
'setColor',
|
||||
'setConfig',
|
||||
'setContext',
|
||||
'setCurrentLayer',
|
||||
'setCurrentLayerPosition',
|
||||
'setDocumentTitle',
|
||||
'setFillPaint',
|
||||
'setFontColor',
|
||||
'setFontFamily',
|
||||
'setFontSize',
|
||||
'setGoodImage',
|
||||
'setGradient',
|
||||
'setGroupTitle',
|
||||
'setHref',
|
||||
'setIdPrefix',
|
||||
'setImageURL',
|
||||
'setItalic',
|
||||
'setLayerVisibility',
|
||||
'setLinkURL',
|
||||
'setMode',
|
||||
'setOpacity',
|
||||
'setPaint',
|
||||
'setPaintOpacity',
|
||||
'setRectRadius',
|
||||
'setResolution',
|
||||
'setRotationAngle',
|
||||
'setSegType',
|
||||
'setStrokeAttr',
|
||||
'setStrokePaint',
|
||||
'setStrokeWidth',
|
||||
'setSvgString',
|
||||
'setTextContent',
|
||||
'setUiStrings',
|
||||
'setUseData',
|
||||
'setZoom',
|
||||
'svgCanvasToString',
|
||||
'svgToString',
|
||||
'transformListToTransform',
|
||||
'ungroupSelectedElement',
|
||||
'uniquifyElems',
|
||||
'updateCanvas',
|
||||
'zoomChanged'
|
||||
];
|
||||
|
||||
// TODO: rewrite the following, it's pretty scary.
|
||||
for (const func of functions) {
|
||||
this[func] = getCallbackSetter(func);
|
||||
}
|
||||
|
||||
// Older IE may need a polyfill for addEventListener, but so it would for SVG
|
||||
window.addEventListener('message', getMessageListener(this));
|
||||
window.addEventListener('keydown', (e) => {
|
||||
const {type, key} = e;
|
||||
if (key === 'Backspace') {
|
||||
e.preventDefault();
|
||||
const keyboardEvent = new KeyboardEvent(type, {key});
|
||||
that.frame.contentDocument.dispatchEvent(keyboardEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {ArgumentsArray} args Signature dependent on function
|
||||
* @param {GenericCallback} callback (This may be better than a promise in case adding an event.)
|
||||
* @returns {Integer}
|
||||
*/
|
||||
send (name, args, callback) { // eslint-disable-line promise/prefer-await-to-callbacks
|
||||
const that = this;
|
||||
cbid++;
|
||||
|
||||
this.callbacks[cbid] = callback;
|
||||
setTimeout((function (callbackID) {
|
||||
return function () { // Delay for the callback to be set in case its synchronous
|
||||
/*
|
||||
* Todo: Handle non-JSON arguments and return values (undefined,
|
||||
* nonfinite numbers, functions, and built-in objects like Date,
|
||||
* RegExp), etc.? Allow promises instead of callbacks? Review
|
||||
* SVG-Edit functions for whether JSON-able parameters can be
|
||||
* made compatile with all API functionality
|
||||
*/
|
||||
// We accept and post strings for the sake of IE9 support
|
||||
let sameOriginWithGlobal = false;
|
||||
try {
|
||||
sameOriginWithGlobal = window.location.origin === that.frame.contentWindow.location.origin &&
|
||||
that.frame.contentWindow.svgEditor.canvas;
|
||||
} catch (err) {}
|
||||
|
||||
if (sameOriginWithGlobal) {
|
||||
// Although we do not really need this API if we are working same
|
||||
// domain, it could allow us to write in a way that would work
|
||||
// cross-domain as well, assuming we stick to the argument limitations
|
||||
// of the current JSON-based communication API (e.g., not passing
|
||||
// callbacks). We might be able to address these shortcomings; see
|
||||
// the todo elsewhere in this file.
|
||||
const message = {id: callbackID},
|
||||
{svgEditor: {canvas: svgCanvas}} = that.frame.contentWindow;
|
||||
try {
|
||||
message.result = svgCanvas[name](...args);
|
||||
} catch (err) {
|
||||
message.error = err.message;
|
||||
}
|
||||
addCallback(that, message);
|
||||
} else { // Requires the ext-xdomain-messaging.js extension
|
||||
that.frame.contentWindow.postMessage(JSON.stringify({
|
||||
namespace: 'svgCanvas', id: callbackID, name, args
|
||||
}), '*');
|
||||
}
|
||||
};
|
||||
}(cbid)), 0);
|
||||
|
||||
return cbid;
|
||||
}
|
||||
}
|
||||
|
||||
export default EmbeddedSVGEdit;
|
||||
2006
dist/editor/extensions/ext-arrows.js
vendored
Normal file
2006
dist/editor/extensions/ext-arrows.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-arrows.js.map
vendored
Normal file
1
dist/editor/extensions/ext-arrows.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
4090
dist/editor/extensions/ext-closepath.js
vendored
Normal file
4090
dist/editor/extensions/ext-closepath.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-closepath.js.map
vendored
Normal file
1
dist/editor/extensions/ext-closepath.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2300
dist/editor/extensions/ext-connector.js
vendored
Normal file
2300
dist/editor/extensions/ext-connector.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-connector.js.map
vendored
Normal file
1
dist/editor/extensions/ext-connector.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1804
dist/editor/extensions/ext-eyedropper.js
vendored
Normal file
1804
dist/editor/extensions/ext-eyedropper.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-eyedropper.js.map
vendored
Normal file
1
dist/editor/extensions/ext-eyedropper.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1965
dist/editor/extensions/ext-foreignobject.js
vendored
Normal file
1965
dist/editor/extensions/ext-foreignobject.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-foreignobject.js.map
vendored
Normal file
1
dist/editor/extensions/ext-foreignobject.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1824
dist/editor/extensions/ext-grid.js
vendored
Normal file
1824
dist/editor/extensions/ext-grid.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-grid.js.map
vendored
Normal file
1
dist/editor/extensions/ext-grid.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1757
dist/editor/extensions/ext-helloworld.js
vendored
Normal file
1757
dist/editor/extensions/ext-helloworld.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-helloworld.js.map
vendored
Normal file
1
dist/editor/extensions/ext-helloworld.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2170
dist/editor/extensions/ext-imagelib.js
vendored
Normal file
2170
dist/editor/extensions/ext-imagelib.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-imagelib.js.map
vendored
Normal file
1
dist/editor/extensions/ext-imagelib.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
14
dist/editor/extensions/ext-imagelib.xml
vendored
Normal file
14
dist/editor/extensions/ext-imagelib.xml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="tool_imagelib">
|
||||
<svg width="201" height="211" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m2.75,49.51761l56.56,-46.26761c12.73,8.25 25.71001,7 46.44,0.75l-56.03999,47.23944l-22.72002,25.01056l-24.23999,-26.73239z" id="svg_2" stroke-width="7"/>
|
||||
<path fill="#a03333" stroke="#3f3f3f" d="m3.75,203.25002c14.33301,7 30.66699,7 46,0l0,-152.00002c-14.66699,8 -32.33301,8 -47,0l1,152.00002zm45.75,-152.25002l56.25,-46.75l0,151l-56,48.00002m-47.25,-154.25002l57.25,-46.5" id="svg_1" stroke-width="7" stroke-linecap="round"/>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m49.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_5"/>
|
||||
<path fill="#2f8e2f" stroke="#3f3f3f" d="m50.75,202.25c14.33301,7 30.66699,7.04253 46,0.04253l0,-151.04253c-14.66699,8 -32.33301,8 -47,0l1,151zm45.75,-151.25l56.25,-46.75l0,144.01219l-56,51.98782m-47.25,-151.25002l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_6"/>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m95.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_10"/>
|
||||
<path fill="#336393" stroke="#3f3f3f" d="m96.75,200.29445c14.33301,7 30.66699,7 46,0l0,-149.04445c-14.66699,8 -32.33301,8 -47,0l1,149.04445zm45.75,-149.29445l56.25,-46.75l0,148.04445l-56,48m-47.25,-151.29445l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_11"/>
|
||||
</g>
|
||||
</svg>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
21
dist/editor/extensions/ext-locale/arrows/en.js
vendored
Normal file
21
dist/editor/extensions/ext-locale/arrows/en.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
var en = {
|
||||
name: 'Arrows',
|
||||
langList: [
|
||||
{id: 'arrow_none', textContent: 'No arrow'}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Select arrow type',
|
||||
options: {
|
||||
none: 'No arrow',
|
||||
end: '---->',
|
||||
start: '<----',
|
||||
both: '<--->',
|
||||
mid: '-->--',
|
||||
mid_bk: '--<--'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
21
dist/editor/extensions/ext-locale/arrows/fr.js
vendored
Normal file
21
dist/editor/extensions/ext-locale/arrows/fr.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
var fr = {
|
||||
name: 'Arrows',
|
||||
langList: [
|
||||
{id: 'arrow_none', textContent: 'Sans flèche'}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Select arrow type',
|
||||
options: {
|
||||
none: 'No arrow',
|
||||
end: '---->',
|
||||
start: '<----',
|
||||
both: '<--->',
|
||||
mid: '-->--',
|
||||
mid_bk: '--<--'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default fr;
|
||||
21
dist/editor/extensions/ext-locale/arrows/zh_CN.js
vendored
Normal file
21
dist/editor/extensions/ext-locale/arrows/zh_CN.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
var zhCN = {
|
||||
name: '箭头',
|
||||
langList: [
|
||||
{id: 'arrow_none', textContent: '无箭头'}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: '选择箭头类型',
|
||||
options: {
|
||||
none: '无箭头',
|
||||
end: '---->',
|
||||
start: '<----',
|
||||
both: '<--->',
|
||||
mid: '-->--',
|
||||
mid_bk: '--<--'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
13
dist/editor/extensions/ext-locale/closepath/en.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/closepath/en.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var en = {
|
||||
name: 'ClosePath',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Open path'
|
||||
},
|
||||
{
|
||||
title: 'Close path'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
13
dist/editor/extensions/ext-locale/closepath/zh_CN.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/closepath/zh_CN.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var zhCN = {
|
||||
name: '闭合路径',
|
||||
buttons: [
|
||||
{
|
||||
title: '打开路径'
|
||||
},
|
||||
{
|
||||
title: '关闭路径'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
13
dist/editor/extensions/ext-locale/connector/en.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/connector/en.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var en = {
|
||||
name: 'Connector',
|
||||
langList: [
|
||||
{id: 'mode_connect', title: 'Connect two objects'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
title: 'Connect two objects'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
13
dist/editor/extensions/ext-locale/connector/fr.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/connector/fr.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var fr = {
|
||||
name: 'Connector',
|
||||
langList: [
|
||||
{id: 'mode_connect', title: 'Connecter deux objets'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
title: 'Connect two objects'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default fr;
|
||||
13
dist/editor/extensions/ext-locale/connector/zh_CN.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/connector/zh_CN.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var zhCN = {
|
||||
name: '连接器',
|
||||
langList: [
|
||||
{id: 'mode_connect', title: '连接两个对象'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
title: '连接两个对象'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
11
dist/editor/extensions/ext-locale/eyedropper/en.js
vendored
Normal file
11
dist/editor/extensions/ext-locale/eyedropper/en.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
var en = {
|
||||
name: 'eyedropper',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Eye Dropper Tool',
|
||||
key: 'I'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
11
dist/editor/extensions/ext-locale/eyedropper/zh_CN.js
vendored
Normal file
11
dist/editor/extensions/ext-locale/eyedropper/zh_CN.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
var zhCN = {
|
||||
name: '滴管',
|
||||
buttons: [
|
||||
{
|
||||
title: '滴管工具',
|
||||
key: 'I'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
27
dist/editor/extensions/ext-locale/foreignobject/en.js
vendored
Normal file
27
dist/editor/extensions/ext-locale/foreignobject/en.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
var en = {
|
||||
name: 'foreignObject',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Foreign Object Tool'
|
||||
},
|
||||
{
|
||||
title: 'Edit ForeignObject Content'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: "Change foreignObject's width",
|
||||
label: 'w'
|
||||
},
|
||||
{
|
||||
title: "Change foreignObject's height",
|
||||
label: 'h'
|
||||
},
|
||||
{
|
||||
title: "Change foreignObject's font size",
|
||||
label: 'font-size'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
27
dist/editor/extensions/ext-locale/foreignobject/zh_CN.js
vendored
Normal file
27
dist/editor/extensions/ext-locale/foreignobject/zh_CN.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
var zhCN = {
|
||||
name: '外部对象',
|
||||
buttons: [
|
||||
{
|
||||
title: '外部对象工具'
|
||||
},
|
||||
{
|
||||
title: '编辑外部对象内容'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: '改变外部对象宽度',
|
||||
label: 'w'
|
||||
},
|
||||
{
|
||||
title: '改变外部对象高度',
|
||||
label: 'h'
|
||||
},
|
||||
{
|
||||
title: '改变外部对象文字大小',
|
||||
label: '文字大小'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
10
dist/editor/extensions/ext-locale/grid/en.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/grid/en.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var en = {
|
||||
name: 'View Grid',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Show/Hide Grid'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
10
dist/editor/extensions/ext-locale/grid/zh_CN.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/grid/zh_CN.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var zhCN = {
|
||||
name: '网格视图',
|
||||
buttons: [
|
||||
{
|
||||
title: '显示/隐藏网格'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
11
dist/editor/extensions/ext-locale/helloworld/en.js
vendored
Normal file
11
dist/editor/extensions/ext-locale/helloworld/en.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
var en = {
|
||||
name: 'Hello World',
|
||||
text: 'Hello World!\n\nYou clicked here: {x}, {y}',
|
||||
buttons: [
|
||||
{
|
||||
title: "Say 'Hello World'"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
11
dist/editor/extensions/ext-locale/helloworld/zh_CN.js
vendored
Normal file
11
dist/editor/extensions/ext-locale/helloworld/zh_CN.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
var zhCN = {
|
||||
name: 'Hello World',
|
||||
text: 'Hello World!\n\n 请点击: {x}, {y}',
|
||||
buttons: [
|
||||
{
|
||||
title: "输出 'Hello World'"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/de.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/de.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var de = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Bilder-Bibliothek'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default de;
|
||||
40
dist/editor/extensions/ext-locale/imagelib/en.js
vendored
Normal file
40
dist/editor/extensions/ext-locale/imagelib/en.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
var en = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Image library'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
// The site is no longer using our API, and they have added an
|
||||
// `X-Frame-Options` header which prevents our usage cross-origin:
|
||||
// Getting messages like this in console:
|
||||
// Refused to display 'https://openclipart.org/detail/307176/sign-bike' in a frame
|
||||
// because it set 'X-Frame-Options' to 'sameorigin'.
|
||||
// url: 'https://openclipart.org/svgedit',
|
||||
// However, they do have a custom API which we are using here:
|
||||
/*
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: '{path}imagelib/openclipart{modularVersion}.html',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/fr.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/fr.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var fr = {
|
||||
select_lib: "Choisir une bibliothèque d'images",
|
||||
show_list: 'show_list',
|
||||
import_single: 'import_single',
|
||||
import_multi: 'import_multi',
|
||||
open: 'open',
|
||||
buttons: [
|
||||
{
|
||||
title: "Bibliothèque d'images"
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default fr;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/pl.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/pl.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var pl = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Biblioteka obrazów'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default pl;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/pt_BR.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/pt_BR.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var ptBR = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Biblioteca de Imagens'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default ptBR;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/ro.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/ro.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var ro = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Bibliotecă de Imagini'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default ro;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/sk.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/sk.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var sk = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Knižnica obrázkov'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default sk;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/sl.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/sl.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var sl = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Knjižnica slik'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default sl;
|
||||
35
dist/editor/extensions/ext-locale/imagelib/zh_CN.js
vendored
Normal file
35
dist/editor/extensions/ext-locale/imagelib/zh_CN.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var zhCN = {
|
||||
select_lib: 'Select an image library',
|
||||
show_list: 'Show library list',
|
||||
import_single: 'Import single',
|
||||
import_multi: 'Import multiple',
|
||||
open: 'Open as new document',
|
||||
buttons: [
|
||||
{
|
||||
title: '图像库'
|
||||
}
|
||||
],
|
||||
imgLibs: [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: '{path}imagelib/index{modularVersion}.html',
|
||||
description: 'Demonstration library for SVG-edit on this server'
|
||||
},
|
||||
{
|
||||
name: 'IAN Symbol Libraries',
|
||||
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
|
||||
description: 'Free library of illustrations'
|
||||
}
|
||||
/*
|
||||
// See message in "en" locale for further details
|
||||
,
|
||||
{
|
||||
name: 'Openclipart',
|
||||
url: 'https://openclipart.org/svgedit',
|
||||
description: 'Share and Use Images. Over 100,000 Public Domain SVG Images and Growing.'
|
||||
}
|
||||
*/
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
48
dist/editor/extensions/ext-locale/markers/en.js
vendored
Normal file
48
dist/editor/extensions/ext-locale/markers/en.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
var en = {
|
||||
name: 'Markers',
|
||||
langList: [
|
||||
{id: 'nomarker', title: 'No Marker'},
|
||||
{id: 'leftarrow', title: 'Left Arrow'},
|
||||
{id: 'rightarrow', title: 'Right Arrow'},
|
||||
{id: 'textmarker', title: 'Text Marker'},
|
||||
{id: 'forwardslash', title: 'Forward Slash'},
|
||||
{id: 'reverseslash', title: 'Reverse Slash'},
|
||||
{id: 'verticalslash', title: 'Vertical Slash'},
|
||||
{id: 'box', title: 'Box'},
|
||||
{id: 'star', title: 'Star'},
|
||||
{id: 'xmark', title: 'X'},
|
||||
{id: 'triangle', title: 'Triangle'},
|
||||
{id: 'mcircle', title: 'Circle'},
|
||||
{id: 'leftarrow_o', title: 'Open Left Arrow'},
|
||||
{id: 'rightarrow_o', title: 'Open Right Arrow'},
|
||||
{id: 'box_o', title: 'Open Box'},
|
||||
{id: 'star_o', title: 'Open Star'},
|
||||
{id: 'triangle_o', title: 'Open Triangle'},
|
||||
{id: 'mcircle_o', title: 'Open Circle'}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Start marker',
|
||||
label: 's'
|
||||
},
|
||||
{
|
||||
title: 'Select start marker type'
|
||||
},
|
||||
{
|
||||
title: 'Middle marker',
|
||||
label: 'm'
|
||||
},
|
||||
{
|
||||
title: 'Select mid marker type'
|
||||
},
|
||||
{
|
||||
title: 'End marker',
|
||||
label: 'e'
|
||||
},
|
||||
{
|
||||
title: 'Select end marker type'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
48
dist/editor/extensions/ext-locale/markers/zh_CN.js
vendored
Normal file
48
dist/editor/extensions/ext-locale/markers/zh_CN.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
var zhCN = {
|
||||
name: '标记',
|
||||
langList: [
|
||||
{id: 'nomarker', title: '无标记'},
|
||||
{id: 'leftarrow', title: '左箭头'},
|
||||
{id: 'rightarrow', title: '右箭头'},
|
||||
{id: 'textmarker', title: '文本'},
|
||||
{id: 'forwardslash', title: '斜杠'},
|
||||
{id: 'reverseslash', title: '反斜杠'},
|
||||
{id: 'verticalslash', title: '垂直线'},
|
||||
{id: 'box', title: '方块'},
|
||||
{id: 'star', title: '星形'},
|
||||
{id: 'xmark', title: 'X'},
|
||||
{id: 'triangle', title: '三角形'},
|
||||
{id: 'mcircle', title: '圆形'},
|
||||
{id: 'leftarrow_o', title: '左箭头(空心)'},
|
||||
{id: 'rightarrow_o', title: '右箭头(空心)'},
|
||||
{id: 'box_o', title: '方块(空心)'},
|
||||
{id: 'star_o', title: '星形(空心)'},
|
||||
{id: 'triangle_o', title: '三角形(空心)'},
|
||||
{id: 'mcircle_o', title: '圆形(空心)'}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: '起始标记',
|
||||
label: 's'
|
||||
},
|
||||
{
|
||||
title: '选择起始标记类型'
|
||||
},
|
||||
{
|
||||
title: '中段标记',
|
||||
label: 'm'
|
||||
},
|
||||
{
|
||||
title: '选择中段标记类型'
|
||||
},
|
||||
{
|
||||
title: '末端标记',
|
||||
label: 'e'
|
||||
},
|
||||
{
|
||||
title: '选择末端标记类型'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
10
dist/editor/extensions/ext-locale/mathjax/en.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/mathjax/en.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var en = {
|
||||
name: 'MathJax',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Add Mathematics'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
10
dist/editor/extensions/ext-locale/mathjax/zh_CN.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/mathjax/zh_CN.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var zhCN = {
|
||||
name: '数学',
|
||||
buttons: [
|
||||
{
|
||||
title: '添加数学计算'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
10
dist/editor/extensions/ext-locale/panning/en.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/panning/en.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var en = {
|
||||
name: 'Extension Panning',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Panning'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
10
dist/editor/extensions/ext-locale/panning/zh_CN.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/panning/zh_CN.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var zhCN = {
|
||||
name: '移动',
|
||||
buttons: [
|
||||
{
|
||||
title: '移动'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
42
dist/editor/extensions/ext-locale/placemark/en.js
vendored
Normal file
42
dist/editor/extensions/ext-locale/placemark/en.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
var en = {
|
||||
name: 'placemark',
|
||||
langList: [
|
||||
{id: 'nomarker', title: 'No Marker'},
|
||||
{id: 'leftarrow', title: 'Left Arrow'},
|
||||
{id: 'rightarrow', title: 'Right Arrow'},
|
||||
{id: 'forwardslash', title: 'Forward Slash'},
|
||||
{id: 'reverseslash', title: 'Reverse Slash'},
|
||||
{id: 'verticalslash', title: 'Vertical Slash'},
|
||||
{id: 'box', title: 'Box'},
|
||||
{id: 'star', title: 'Star'},
|
||||
{id: 'xmark', title: 'X'},
|
||||
{id: 'triangle', title: 'Triangle'},
|
||||
{id: 'mcircle', title: 'Circle'},
|
||||
{id: 'leftarrow_o', title: 'Open Left Arrow'},
|
||||
{id: 'rightarrow_o', title: 'Open Right Arrow'},
|
||||
{id: 'box_o', title: 'Open Box'},
|
||||
{id: 'star_o', title: 'Open Star'},
|
||||
{id: 'triangle_o', title: 'Open Triangle'},
|
||||
{id: 'mcircle_o', title: 'Open Circle'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
title: 'Placemark Tool'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Select Place marker type'
|
||||
},
|
||||
{
|
||||
title: 'Text on separated with ; ',
|
||||
label: 'Text'
|
||||
},
|
||||
{
|
||||
title: 'Font for text',
|
||||
label: ''
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
16
dist/editor/extensions/ext-locale/polygon/en.js
vendored
Normal file
16
dist/editor/extensions/ext-locale/polygon/en.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var en = {
|
||||
name: 'polygon',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Polygon Tool'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Number of Sides',
|
||||
label: 'sides'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
16
dist/editor/extensions/ext-locale/polygon/zh_CN.js
vendored
Normal file
16
dist/editor/extensions/ext-locale/polygon/zh_CN.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var zhCN = {
|
||||
name: '多边形',
|
||||
buttons: [
|
||||
{
|
||||
title: '多边形工具'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: '边数',
|
||||
label: '边数'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
6
dist/editor/extensions/ext-locale/server_moinsave/en.js
vendored
Normal file
6
dist/editor/extensions/ext-locale/server_moinsave/en.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var en = {
|
||||
saved: 'Saved! Return to Item View!',
|
||||
hiddenframe: 'Moinsave frame to store hidden values'
|
||||
};
|
||||
|
||||
export default en;
|
||||
6
dist/editor/extensions/ext-locale/server_moinsave/zh_CN.js
vendored
Normal file
6
dist/editor/extensions/ext-locale/server_moinsave/zh_CN.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var zhCN = {
|
||||
saved: '已保存! 返回视图!',
|
||||
hiddenframe: 'Moinsave frame to store hidden values'
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
6
dist/editor/extensions/ext-locale/server_opensave/en.js
vendored
Normal file
6
dist/editor/extensions/ext-locale/server_opensave/en.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var en = {
|
||||
uploading: 'Uploading...',
|
||||
hiddenframe: 'Opensave frame to store hidden values'
|
||||
};
|
||||
|
||||
export default en;
|
||||
6
dist/editor/extensions/ext-locale/server_opensave/zh_CN.js
vendored
Normal file
6
dist/editor/extensions/ext-locale/server_opensave/zh_CN.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var zhCN = {
|
||||
uploading: '正在上传...',
|
||||
hiddenframe: 'Opensave frame to store hidden values'
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
26
dist/editor/extensions/ext-locale/shapes/en.js
vendored
Normal file
26
dist/editor/extensions/ext-locale/shapes/en.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
var en = {
|
||||
loading: 'Loading...',
|
||||
categories: {
|
||||
basic: 'Basic',
|
||||
object: 'Objects',
|
||||
symbol: 'Symbols',
|
||||
arrow: 'Arrows',
|
||||
flowchart: 'Flowchart',
|
||||
animal: 'Animals',
|
||||
game: 'Cards & Chess',
|
||||
dialog_balloon: 'Dialog balloons',
|
||||
electronics: 'Electronics',
|
||||
math: 'Mathematical',
|
||||
music: 'Music',
|
||||
misc: 'Miscellaneous',
|
||||
raphael_1: 'raphaeljs.com set 1',
|
||||
raphael_2: 'raphaeljs.com set 2'
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
title: 'Shape library'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
26
dist/editor/extensions/ext-locale/shapes/fr.js
vendored
Normal file
26
dist/editor/extensions/ext-locale/shapes/fr.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
var fr = {
|
||||
loading: 'Loading...',
|
||||
categories: {
|
||||
basic: 'Basic',
|
||||
object: 'Objects',
|
||||
symbol: 'Symbols',
|
||||
arrow: 'Arrows',
|
||||
flowchart: 'Flowchart',
|
||||
animal: 'Animals',
|
||||
game: 'Cards & Chess',
|
||||
dialog_balloon: 'Dialog balloons',
|
||||
electronics: 'Electronics',
|
||||
math: 'Mathematical',
|
||||
music: 'Music',
|
||||
misc: 'Miscellaneous',
|
||||
raphael_1: 'raphaeljs.com set 1',
|
||||
raphael_2: 'raphaeljs.com set 2'
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
title: "Bibliothèque d'images"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default fr;
|
||||
26
dist/editor/extensions/ext-locale/shapes/zh_CN.js
vendored
Normal file
26
dist/editor/extensions/ext-locale/shapes/zh_CN.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
var zhCN = {
|
||||
loading: '正在加载...',
|
||||
categories: {
|
||||
basic: '基本',
|
||||
object: '对象',
|
||||
symbol: '符号',
|
||||
arrow: '箭头',
|
||||
flowchart: '工作流',
|
||||
animal: '动物',
|
||||
game: '棋牌',
|
||||
dialog_balloon: '会话框',
|
||||
electronics: '电子',
|
||||
math: '数学',
|
||||
music: '音乐',
|
||||
misc: '其他',
|
||||
raphael_1: 'raphaeljs.com 集合 1',
|
||||
raphael_2: 'raphaeljs.com 集合 2'
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
title: '图元库'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
24
dist/editor/extensions/ext-locale/star/en.js
vendored
Normal file
24
dist/editor/extensions/ext-locale/star/en.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var en = {
|
||||
name: 'star',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Star Tool'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: 'Number of Sides',
|
||||
label: 'points'
|
||||
},
|
||||
{
|
||||
title: 'Pointiness',
|
||||
label: 'Pointiness'
|
||||
},
|
||||
{
|
||||
title: 'Twists the star',
|
||||
label: 'Radial Shift'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
24
dist/editor/extensions/ext-locale/star/zh_CN.js
vendored
Normal file
24
dist/editor/extensions/ext-locale/star/zh_CN.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var zhCN = {
|
||||
name: '星形',
|
||||
buttons: [
|
||||
{
|
||||
title: '星形工具'
|
||||
}
|
||||
],
|
||||
contextTools: [
|
||||
{
|
||||
title: '顶点',
|
||||
label: '顶点'
|
||||
},
|
||||
{
|
||||
title: '钝度',
|
||||
label: '钝度'
|
||||
},
|
||||
{
|
||||
title: '径向',
|
||||
label: '径向'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
16
dist/editor/extensions/ext-locale/storage/de.js
vendored
Normal file
16
dist/editor/extensions/ext-locale/storage/de.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var de = {
|
||||
message: 'Standardmäßig kann SVG-Edit Ihre Editor-Einstellungen ' +
|
||||
'und die SVG-Inhalte lokal auf Ihrem Gerät abspeichern. So brauchen Sie ' +
|
||||
'nicht jedes Mal die SVG neu laden. Falls Sie aus Datenschutzgründen ' +
|
||||
'dies nicht wollen, ' +
|
||||
'können Sie die Standardeinstellung im Folgenden ändern.',
|
||||
storagePrefsAndContent: 'Store preferences and SVG content locally',
|
||||
storagePrefsOnly: 'Only store preferences locally',
|
||||
storagePrefs: 'Store preferences locally',
|
||||
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
|
||||
storageNoPrefs: 'Do not store my preferences locally',
|
||||
rememberLabel: 'Remember this choice?',
|
||||
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
|
||||
};
|
||||
|
||||
export default de;
|
||||
16
dist/editor/extensions/ext-locale/storage/en.js
vendored
Normal file
16
dist/editor/extensions/ext-locale/storage/en.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var en = {
|
||||
message: 'By default and where supported, SVG-Edit can store your editor ' +
|
||||
'preferences and SVG content locally on your machine so you do not ' +
|
||||
'need to add these back each time you load SVG-Edit. If, for privacy ' +
|
||||
'reasons, you do not wish to store this information on your machine, ' +
|
||||
'you can change away from the default option below.',
|
||||
storagePrefsAndContent: 'Store preferences and SVG content locally',
|
||||
storagePrefsOnly: 'Only store preferences locally',
|
||||
storagePrefs: 'Store preferences locally',
|
||||
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
|
||||
storageNoPrefs: 'Do not store my preferences locally',
|
||||
rememberLabel: 'Remember this choice?',
|
||||
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
|
||||
};
|
||||
|
||||
export default en;
|
||||
16
dist/editor/extensions/ext-locale/storage/fr.js
vendored
Normal file
16
dist/editor/extensions/ext-locale/storage/fr.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var fr = {
|
||||
message: "Par défaut et si supporté, SVG-Edit peut stocker les préférences de l'éditeur " +
|
||||
"et le contenu SVG localement sur votre machine de sorte que vous n'ayez pas besoin de les " +
|
||||
'rajouter chaque fois que vous chargez SVG-Edit. Si, pour des raisons de confidentialité, ' +
|
||||
'vous ne souhaitez pas stocker ces données sur votre machine, vous pouvez changer ce ' +
|
||||
'comportement ci-dessous.',
|
||||
storagePrefsAndContent: 'Store preferences and SVG content locally',
|
||||
storagePrefsOnly: 'Only store preferences locally',
|
||||
storagePrefs: 'Store preferences locally',
|
||||
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
|
||||
storageNoPrefs: 'Do not store my preferences locally',
|
||||
rememberLabel: 'Remember this choice?',
|
||||
rememberTooltip: "Si vous choisissez de désactiver le stockage en mémorisant le choix, l'URL va changer afin que la question ne vous soit plus reposée."
|
||||
};
|
||||
|
||||
export default fr;
|
||||
13
dist/editor/extensions/ext-locale/storage/zh_CN.js
vendored
Normal file
13
dist/editor/extensions/ext-locale/storage/zh_CN.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var zhCN = {
|
||||
message: '默认情况下, SVG-Edit 在本地保存配置参数和画布内容. 如果基于隐私考虑, ' +
|
||||
'您可以勾选以下选项修改配置.',
|
||||
storagePrefsAndContent: '本地存储配置参数和SVG图',
|
||||
storagePrefsOnly: '本地只存储配置参数',
|
||||
storagePrefs: '本地存储配置参数',
|
||||
storageNoPrefsOrContent: '本地不保存配置参数和SVG图',
|
||||
storageNoPrefs: '本地不保存配置参数',
|
||||
rememberLabel: '记住选择?',
|
||||
rememberTooltip: '如果您勾选记住选择,将不再弹出本窗口.'
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
10
dist/editor/extensions/ext-locale/webappfind/en.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/webappfind/en.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var en = {
|
||||
name: 'WebAppFind',
|
||||
buttons: [
|
||||
{
|
||||
title: 'Save Image back to Disk'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default en;
|
||||
10
dist/editor/extensions/ext-locale/webappfind/zh_CN.js
vendored
Normal file
10
dist/editor/extensions/ext-locale/webappfind/zh_CN.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var zhCN = {
|
||||
name: 'WebAppFind',
|
||||
buttons: [
|
||||
{
|
||||
title: '保存图片到磁盘'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default zhCN;
|
||||
2343
dist/editor/extensions/ext-markers.js
vendored
Normal file
2343
dist/editor/extensions/ext-markers.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-markers.js.map
vendored
Normal file
1
dist/editor/extensions/ext-markers.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1914
dist/editor/extensions/ext-mathjax.js
vendored
Normal file
1914
dist/editor/extensions/ext-mathjax.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-mathjax.js.map
vendored
Normal file
1
dist/editor/extensions/ext-mathjax.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
149
dist/editor/extensions/ext-overview_window.js
vendored
Normal file
149
dist/editor/extensions/ext-overview_window.js
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file ext-overview_window.js
|
||||
*
|
||||
* @license MIT
|
||||
*
|
||||
* @copyright 2013 James Sacksteder
|
||||
*
|
||||
*/
|
||||
var extOverview_window = {
|
||||
name: 'overview_window',
|
||||
init: function init(_ref) {
|
||||
var $ = _ref.$,
|
||||
isChrome = _ref.isChrome,
|
||||
isIE = _ref.isIE;
|
||||
var overviewWindowGlobals = {}; // Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and
|
||||
// https://code.google.com/p/chromium/issues/detail?id=565120.
|
||||
|
||||
if (isChrome()) {
|
||||
var verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
|
||||
var chromeVersion = Number.parseInt(navigator.userAgent.substring(verIndex));
|
||||
|
||||
if (chromeVersion < 49) {
|
||||
return undefined;
|
||||
}
|
||||
} // Define and insert the base html element.
|
||||
|
||||
|
||||
var propsWindowHtml = '<div id="overview_window_content_pane" style="width:100%; ' + 'word-wrap:break-word; display:inline-block; margin-top:20px;">' + '<div id="overview_window_content" style="position:relative; ' + 'left:12px; top:0px;">' + '<div style="background-color:#A0A0A0; display:inline-block; ' + 'overflow:visible;">' + '<svg id="overviewMiniView" width="150" height="100" x="0" ' + 'y="0" viewBox="0 0 4800 3600" ' + 'xmlns="http://www.w3.org/2000/svg" ' + 'xmlns:xlink="http://www.w3.org/1999/xlink">' + '<use x="0" y="0" xlink:href="#svgroot"> </use>' + '</svg>' + '<div id="overview_window_view_box" style="min-width:50px; ' + 'min-height:50px; position:absolute; top:30px; left:30px; ' + 'z-index:5; background-color:rgba(255,0,102,0.3);">' + '</div>' + '</div>' + '</div>' + '</div>';
|
||||
$('#sidepanels').append(propsWindowHtml); // Define dynamic animation of the view box.
|
||||
|
||||
var updateViewBox = function updateViewBox() {
|
||||
var portHeight = Number.parseFloat($('#workarea').css('height'));
|
||||
var portWidth = Number.parseFloat($('#workarea').css('width'));
|
||||
var portX = $('#workarea').scrollLeft();
|
||||
var portY = $('#workarea').scrollTop();
|
||||
var windowWidth = Number.parseFloat($('#svgcanvas').css('width'));
|
||||
var windowHeight = Number.parseFloat($('#svgcanvas').css('height'));
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
var viewBoxX = portX / windowWidth * overviewWidth;
|
||||
var viewBoxY = portY / windowHeight * overviewHeight;
|
||||
var viewBoxWidth = portWidth / windowWidth * overviewWidth;
|
||||
var viewBoxHeight = portHeight / windowHeight * overviewHeight;
|
||||
$('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
|
||||
$('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
|
||||
$('#overview_window_view_box').css('top', viewBoxY + 'px');
|
||||
$('#overview_window_view_box').css('left', viewBoxX + 'px');
|
||||
};
|
||||
|
||||
$('#workarea').scroll(function () {
|
||||
if (!overviewWindowGlobals.viewBoxDragging) {
|
||||
updateViewBox();
|
||||
}
|
||||
});
|
||||
$('#workarea').resize(updateViewBox);
|
||||
updateViewBox(); // Compensate for changes in zoom and canvas size.
|
||||
|
||||
var updateViewDimensions = function updateViewDimensions() {
|
||||
var viewWidth = $('#svgroot').attr('width');
|
||||
var viewHeight = $('#svgroot').attr('height');
|
||||
var viewX = 640;
|
||||
var viewY = 480;
|
||||
|
||||
if (isIE()) {
|
||||
// This has only been tested with Firefox 10 and IE 9 (without chrome frame).
|
||||
// I am not sure if if is Firefox or IE that is being non compliant here.
|
||||
// Either way the one that is noncompliant may become more compliant later.
|
||||
// TAG:HACK
|
||||
// TAG:VERSION_DEPENDENT
|
||||
// TAG:BROWSER_SNIFFING
|
||||
viewX = 0;
|
||||
viewY = 0;
|
||||
}
|
||||
|
||||
var svgWidthOld = $('#overviewMiniView').attr('width');
|
||||
var svgHeightNew = viewHeight / viewWidth * svgWidthOld;
|
||||
$('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
|
||||
$('#overviewMiniView').attr('height', svgHeightNew);
|
||||
updateViewBox();
|
||||
};
|
||||
|
||||
updateViewDimensions(); // Set up the overview window as a controller for the view port.
|
||||
|
||||
overviewWindowGlobals.viewBoxDragging = false;
|
||||
|
||||
var updateViewPortFromViewBox = function updateViewPortFromViewBox() {
|
||||
var windowWidth = Number.parseFloat($('#svgcanvas').css('width'));
|
||||
var windowHeight = Number.parseFloat($('#svgcanvas').css('height'));
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
var viewBoxX = Number.parseFloat($('#overview_window_view_box').css('left'));
|
||||
var viewBoxY = Number.parseFloat($('#overview_window_view_box').css('top'));
|
||||
var portX = viewBoxX / overviewWidth * windowWidth;
|
||||
var portY = viewBoxY / overviewHeight * windowHeight;
|
||||
$('#workarea').scrollLeft(portX);
|
||||
$('#workarea').scrollTop(portY);
|
||||
};
|
||||
|
||||
$('#overview_window_view_box').draggable({
|
||||
containment: 'parent',
|
||||
drag: updateViewPortFromViewBox,
|
||||
start: function start() {
|
||||
overviewWindowGlobals.viewBoxDragging = true;
|
||||
},
|
||||
stop: function stop() {
|
||||
overviewWindowGlobals.viewBoxDragging = false;
|
||||
}
|
||||
});
|
||||
$('#overviewMiniView').click(function (evt) {
|
||||
// Firefox doesn't support evt.offsetX and evt.offsetY.
|
||||
var mouseX = evt.offsetX || evt.originalEvent.layerX;
|
||||
var mouseY = evt.offsetY || evt.originalEvent.layerY;
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
var viewBoxWidth = Number.parseFloat($('#overview_window_view_box').css('min-width'));
|
||||
var viewBoxHeight = Number.parseFloat($('#overview_window_view_box').css('min-height'));
|
||||
var viewBoxX = mouseX - 0.5 * viewBoxWidth;
|
||||
var viewBoxY = mouseY - 0.5 * viewBoxHeight; // deal with constraints
|
||||
|
||||
if (viewBoxX < 0) {
|
||||
viewBoxX = 0;
|
||||
}
|
||||
|
||||
if (viewBoxY < 0) {
|
||||
viewBoxY = 0;
|
||||
}
|
||||
|
||||
if (viewBoxX + viewBoxWidth > overviewWidth) {
|
||||
viewBoxX = overviewWidth - viewBoxWidth;
|
||||
}
|
||||
|
||||
if (viewBoxY + viewBoxHeight > overviewHeight) {
|
||||
viewBoxY = overviewHeight - viewBoxHeight;
|
||||
}
|
||||
|
||||
$('#overview_window_view_box').css('top', viewBoxY + 'px');
|
||||
$('#overview_window_view_box').css('left', viewBoxX + 'px');
|
||||
updateViewPortFromViewBox();
|
||||
});
|
||||
return {
|
||||
name: 'overview window',
|
||||
canvasUpdated: updateViewDimensions,
|
||||
workareaResized: updateViewBox
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default extOverview_window;
|
||||
//# sourceMappingURL=ext-overview_window.js.map
|
||||
1
dist/editor/extensions/ext-overview_window.js.map
vendored
Normal file
1
dist/editor/extensions/ext-overview_window.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1720
dist/editor/extensions/ext-panning.js
vendored
Normal file
1720
dist/editor/extensions/ext-panning.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-panning.js.map
vendored
Normal file
1
dist/editor/extensions/ext-panning.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ext-panning.js","sources":["../../../src/editor/extensions/ext-panning.xml","../../../src/editor/extensions/ext-panning.js"],"sourcesContent":["export default \"ext-panning.xml\"","/**\n * @file ext-panning.js\n *\n * @license MIT\n *\n * @copyright 2013 Luis Aguirre\n *\n */\n/*\n This is a very basic SVG-Edit extension to let tablet/mobile devices pan without problem\n*/\n\nimport './ext-panning.xml';\n\nexport default {\n name: 'panning',\n async init ({importLocale}) {\n const strings = await importLocale();\n const svgEditor = this;\n const svgCanvas = svgEditor.canvas;\n const buttons = [{\n id: 'ext-panning',\n icon: svgEditor.curConfig.extIconsPath + 'panning.png',\n type: 'mode',\n events: {\n click () {\n svgCanvas.setMode('ext-panning');\n }\n }\n }];\n return {\n name: strings.name,\n svgicons: svgEditor.curConfig.extIconsPath + 'ext-panning.xml',\n buttons: strings.buttons.map((button, i) => {\n return Object.assign(buttons[i], button);\n }),\n mouseDown () {\n if (svgCanvas.getMode() === 'ext-panning') {\n svgEditor.setPanning(true);\n return {started: true};\n }\n return undefined;\n },\n mouseUp () {\n if (svgCanvas.getMode() === 'ext-panning') {\n svgEditor.setPanning(false);\n return {\n keep: false,\n element: null\n };\n }\n return undefined;\n }\n };\n }\n};\n"],"names":["name","init","importLocale","strings","svgEditor","svgCanvas","canvas","buttons","id","icon","curConfig","extIconsPath","type","events","click","setMode","svgicons","map","button","i","Object","assign","mouseDown","getMode","setPanning","started","undefined","mouseUp","keep","element"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAAe;;ACcf,mBAAe;AACbA,EAAAA,IAAI,EAAE,SADO;AAEPC,EAAAA,IAFO,sBAEe;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAfC,cAAAA,YAAe,QAAfA,YAAe;AAAA;AAAA,qBACJA,YAAY,EADR;;AAAA;AACpBC,cAAAA,OADoB;AAEpBC,cAAAA,SAFoB,GAER,KAFQ;AAGpBC,cAAAA,SAHoB,GAGRD,SAAS,CAACE,MAHF;AAIpBC,cAAAA,OAJoB,GAIV,CAAC;AACfC,gBAAAA,EAAE,EAAE,aADW;AAEfC,gBAAAA,IAAI,EAAEL,SAAS,CAACM,SAAV,CAAoBC,YAApB,GAAmC,aAF1B;AAGfC,gBAAAA,IAAI,EAAE,MAHS;AAIfC,gBAAAA,MAAM,EAAE;AACNC,kBAAAA,KADM,mBACG;AACPT,oBAAAA,SAAS,CAACU,OAAV,CAAkB,aAAlB;AACD;AAHK;AAJO,eAAD,CAJU;AAAA,+CAcnB;AACLf,gBAAAA,IAAI,EAAEG,OAAO,CAACH,IADT;AAELgB,gBAAAA,QAAQ,EAAEZ,SAAS,CAACM,SAAV,CAAoBC,YAApB,GAAmC,iBAFxC;AAGLJ,gBAAAA,OAAO,EAAEJ,OAAO,CAACI,OAAR,CAAgBU,GAAhB,CAAoB,UAACC,MAAD,EAASC,CAAT,EAAe;AAC1C,yBAAOC,MAAM,CAACC,MAAP,CAAcd,OAAO,CAACY,CAAD,CAArB,EAA0BD,MAA1B,CAAP;AACD,iBAFQ,CAHJ;AAMLI,gBAAAA,SANK,uBAMQ;AACX,sBAAIjB,SAAS,CAACkB,OAAV,OAAwB,aAA5B,EAA2C;AACzCnB,oBAAAA,SAAS,CAACoB,UAAV,CAAqB,IAArB;AACA,2BAAO;AAACC,sBAAAA,OAAO,EAAE;AAAV,qBAAP;AACD;;AACD,yBAAOC,SAAP;AACD,iBAZI;AAaLC,gBAAAA,OAbK,qBAaM;AACT,sBAAItB,SAAS,CAACkB,OAAV,OAAwB,aAA5B,EAA2C;AACzCnB,oBAAAA,SAAS,CAACoB,UAAV,CAAqB,KAArB;AACA,2BAAO;AACLI,sBAAAA,IAAI,EAAE,KADD;AAELC,sBAAAA,OAAO,EAAE;AAFJ,qBAAP;AAID;;AACD,yBAAOH,SAAP;AACD;AAtBI,eAdmB;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsC3B;AAxCY,CAAf;;;;"}
|
||||
6
dist/editor/extensions/ext-panning.xml
vendored
Normal file
6
dist/editor/extensions/ext-panning.xml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ext-panning">
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
|
||||
<path d="m8.00038,150.84583l51.60005,-51.78485l0,25.89205l26.28711,0l35.45559,-0.20444l-0.72941,-24.34613l0.93304,-37.61812l-25.79949,0l51.5997,-51.78508l51.60047,51.78508l-25.80024,0l0,33.87256l1.13677,26.21891l21.45996,2.07722l39.3497,0l0,-25.89205l51.60043,51.78485l-51.60043,51.78563l0,-25.89281l-38.41666,-0.93639l-20.52692,0.20445l-3.00285,42.13754l0,20.76308l25.80024,0l-51.60047,51.78561l-51.5997,-51.78561l25.79949,0l0,-20.76308l0.72941,-41.20115l-41.98688,-0.20445l-20.68886,0l0,25.89281l-51.60005,-51.78563z" fill="#b2b2b2" id="svg_1" stroke="#000000" stroke-width="10"/> </svg>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 789 B |
35
dist/editor/extensions/ext-php_savefile.js
vendored
Normal file
35
dist/editor/extensions/ext-php_savefile.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// TODO: Might add support for "exportImage" custom
|
||||
// handler as in "ext-server_opensave.js" (and in savefile.php)
|
||||
var extPhp_savefile = {
|
||||
name: 'php_savefile',
|
||||
init: function init(_ref) {
|
||||
var $ = _ref.$;
|
||||
var svgEditor = this;
|
||||
var extPath = svgEditor.curConfig.extPath,
|
||||
svgCanvas = svgEditor.canvas;
|
||||
/**
|
||||
* Get file name out of SVGEdit document title.
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
function getFileNameFromTitle() {
|
||||
var title = svgCanvas.getDocumentTitle();
|
||||
return title.trim();
|
||||
}
|
||||
|
||||
var saveSvgAction = extPath + 'savefile.php';
|
||||
svgEditor.setCustomHandlers({
|
||||
save: function save(win, data) {
|
||||
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
|
||||
filename = getFileNameFromTitle();
|
||||
$.post(saveSvgAction, {
|
||||
output_svg: svg,
|
||||
filename: filename
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default extPhp_savefile;
|
||||
//# sourceMappingURL=ext-php_savefile.js.map
|
||||
1
dist/editor/extensions/ext-php_savefile.js.map
vendored
Normal file
1
dist/editor/extensions/ext-php_savefile.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ext-php_savefile.js","sources":["../../../src/editor/extensions/ext-php_savefile.js"],"sourcesContent":["// TODO: Might add support for \"exportImage\" custom\n// handler as in \"ext-server_opensave.js\" (and in savefile.php)\n\nexport default {\n name: 'php_savefile',\n init ({$}) {\n const svgEditor = this;\n const {\n curConfig: {extPath},\n canvas: svgCanvas\n } = svgEditor;\n /**\n * Get file name out of SVGEdit document title.\n * @returns {string}\n */\n function getFileNameFromTitle () {\n const title = svgCanvas.getDocumentTitle();\n return title.trim();\n }\n const saveSvgAction = extPath + 'savefile.php';\n svgEditor.setCustomHandlers({\n save (win, data) {\n const svg = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n' + data,\n filename = getFileNameFromTitle();\n\n $.post(saveSvgAction, {output_svg: svg, filename});\n }\n });\n }\n};\n"],"names":["name","init","$","svgEditor","extPath","curConfig","svgCanvas","canvas","getFileNameFromTitle","title","getDocumentTitle","trim","saveSvgAction","setCustomHandlers","save","win","data","svg","filename","post","output_svg"],"mappings":"AAAA;AACA;AAEA,sBAAe;AACbA,EAAAA,IAAI,EAAE,cADO;AAEbC,EAAAA,IAFa,sBAEF;AAAA,QAAJC,CAAI,QAAJA,CAAI;AACT,QAAMC,SAAS,GAAG,IAAlB;AADS,QAGKC,OAHL,GAKLD,SALK,CAGPE,SAHO,CAGKD,OAHL;AAAA,QAICE,SAJD,GAKLH,SALK,CAIPI,MAJO;AAMT;;;;;AAIA,aAASC,oBAAT,GAAiC;AAC/B,UAAMC,KAAK,GAAGH,SAAS,CAACI,gBAAV,EAAd;AACA,aAAOD,KAAK,CAACE,IAAN,EAAP;AACD;;AACD,QAAMC,aAAa,GAAGR,OAAO,GAAG,cAAhC;AACAD,IAAAA,SAAS,CAACU,iBAAV,CAA4B;AAC1BC,MAAAA,IAD0B,gBACpBC,GADoB,EACfC,IADe,EACT;AACf,YAAMC,GAAG,GAAG,6CAA6CD,IAAzD;AAAA,YACEE,QAAQ,GAAGV,oBAAoB,EADjC;AAGAN,QAAAA,CAAC,CAACiB,IAAF,CAAOP,aAAP,EAAsB;AAACQ,UAAAA,UAAU,EAAEH,GAAb;AAAkBC,UAAAA,QAAQ,EAARA;AAAlB,SAAtB;AACD;AANyB,KAA5B;AAQD;AAzBY,CAAf;;;;"}
|
||||
2276
dist/editor/extensions/ext-placemark.js
vendored
Normal file
2276
dist/editor/extensions/ext-placemark.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-placemark.js.map
vendored
Normal file
1
dist/editor/extensions/ext-placemark.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1928
dist/editor/extensions/ext-polygon.js
vendored
Normal file
1928
dist/editor/extensions/ext-polygon.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-polygon.js.map
vendored
Normal file
1
dist/editor/extensions/ext-polygon.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
6626
dist/editor/extensions/ext-server_moinsave.js
vendored
Normal file
6626
dist/editor/extensions/ext-server_moinsave.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-server_moinsave.js.map
vendored
Normal file
1
dist/editor/extensions/ext-server_moinsave.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
6874
dist/editor/extensions/ext-server_opensave.js
vendored
Normal file
6874
dist/editor/extensions/ext-server_opensave.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-server_opensave.js.map
vendored
Normal file
1
dist/editor/extensions/ext-server_opensave.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1987
dist/editor/extensions/ext-shapes.js
vendored
Normal file
1987
dist/editor/extensions/ext-shapes.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/editor/extensions/ext-shapes.js.map
vendored
Normal file
1
dist/editor/extensions/ext-shapes.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
10
dist/editor/extensions/ext-shapes.xml
vendored
Normal file
10
dist/editor/extensions/ext-shapes.xml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="tool_shapelib">
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
|
||||
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,194.72501l0,0c0,-10.30901 35.8172,-18.666 80,-18.666c44.18298,0 80,8.35699 80,18.666l0,74.66699c0,10.30899 -35.81702,18.66699 -80,18.66699c-44.1828,0 -80,-8.358 -80,-18.66699l0,-74.66699z"/>
|
||||
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,114.608l0,0c0,-10.309 35.8172,-18.6668 80,-18.6668c44.18298,0 80,8.3578 80,18.6668l0,74.66699c0,10.30901 -35.81702,18.666 -80,18.666c-44.1828,0 -80,-8.35699 -80,-18.666l0,-74.66699z"/>
|
||||
<path fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m70,33.6667l0,0c0,-10.3094 35.8172,-18.6667 80,-18.6667c44.18298,0 80,8.3573 80,18.6667l0,74.6663c0,10.31 -35.81702,18.667 -80,18.667c-44.1828,0 -80,-8.357 -80,-18.667l0,-74.6663z"/>
|
||||
<path id="svg_1" fill="#c0c0c0" stroke-linejoin="round" stroke-width="14" stroke="#202020" fill-rule="nonzero" d="m230,32.33334c0,10.30931 -35.81726,18.66666 -80,18.66666c-44.1828,0 -80,-8.35735 -80,-18.66666"/>
|
||||
</svg>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user