merging textpath

master
Mark MacKay 2021-05-27 19:30:49 -05:00
parent d1941d7dde
commit 187ce276d2
14 changed files with 1251 additions and 629 deletions

View File

@ -16,6 +16,14 @@
overflow: hidden;
}
.draginput.button {
text-align: center;
color: #999;
padding-top: 10px;
box-sizing: border-box;
cursor: pointer;
}
.draginput .caret {
border: solid transparent 5px;
border-top-color: var(--z9);

8
src/css/fve.css Normal file
View File

@ -0,0 +1,8 @@
/*
#tool_save,
#tool_source,
#tool_export,
#tool_wireframe + .separator {
display: none;
}
*/

Binary file not shown.

View File

@ -1,4 +1,4 @@
<svg viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<path d="M-.1 16.1L16 .04V16.1H-.1z" fill="#ccc"></path>
<path d="M0 16.1V.1l16 16H0z" fill="#666"></path>
<svg width="16" height="15" viewBox="0 0 16 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 0H11L8 6V0H4V15H8V9.5L11 15H16L11.517 7.49007L16 0Z" fill="#1EB5E8"></path>
<path d="M0 0H4H8V3H4V6H8V9H4V15H0V9V6V3V0Z" fill="white"></path>
</svg>

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 261 B

View File

@ -6,9 +6,9 @@
<link rel="icon" href="images/favicon.svg" sizes="any" type="image/svg+xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<title>Method Draw Vector Editor</title>
<title>Fujikohsan Vector Editor</title>
<meta charset="utf-8">
<meta name="description" content="Method Draw is an open source SVG editor for the web, you can use it online without signing up.">
<meta name="description" content="Fujikohsan Vector Editor">
<!-- build:css all.css -->
<link rel="stylesheet" href="css/base.css" type="text/css"/>
@ -28,6 +28,7 @@
<link rel="stylesheet" href="css/keyboard.css" type="text/css"/>
<link rel="stylesheet" href="css/dialog.css" type="text/css"/>
<link rel="stylesheet" href="css/method-draw.css" type="text/css"/>
<link rel="stylesheet" href="css/fve.css" type="text/css"/>
<link rel="stylesheet" href="css/app.css" type="text/css"/>
<link rel="stylesheet" href="css/tools.css" type="text/css"/>
<link rel="stylesheet" href="css/button.css" type="text/css"/>
@ -55,9 +56,9 @@
<div id="menu_bar">
<a class="menu">
<div class="menu_title" id="logo">
<svg viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<path d="M-.1 16.1L16 .04V16.1H-.1z" fill="var(--z12)"></path>
<path d="M0 16.1V.1l16 16H0z" fill="var(--z6)"></path>
<svg width="16" height="15" viewBox="0 0 16 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 0H11L8 6V0H4V15H8V9.5L11 15H16L11.517 7.49007L16 0Z" fill="#1EB5E8"></path>
<path d="M0 0H4H8V3H4V6H8V9H4V15H0V9V6V3V0Z" fill="white"></path>
</svg>
</div>
<div class="menu_list">
@ -122,7 +123,7 @@
<div class="menu_item push_button_pressed" id="tool_rulers">View Rulers <span class="shortcut">⇧R</span></div>
<div class="menu_item" id="tool_wireframe">View Wireframe</div>
<div class="separator"></div>
<div class="menu_item" id="tool_source" data-action="source">Source... <span class="shortcut">⌘U</span></div>
<div class="menu_item" id="tool_source" data-action="source">View Source... <span class="shortcut">⌘U</span></div>
</div>
</div>
</div>
@ -362,7 +363,7 @@
<div class="toolset draginput twocol" id="tool_font_family">
<!-- Font family -->
<span>Font</span>
<div id="preview_font" style="font-family: sans-serif">sans-serif</div>
<div id="preview_font"></div>
<div class="caret"></div>
<input id="font_family" data-title="Change Font Family" size="12" type="hidden" />
<select id="font_family_dropdown">
@ -549,9 +550,12 @@
</svg>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="tool_button" id="tool_text_on_path" title="Place text on path">Place text on path</div>
</div>
<div id="stroke_panel" class="context_panel">
@ -735,6 +739,7 @@
<script type="text/javascript" src="js/lib/jquery.jgraduate.js"></script>
<script type="text/javascript" src="js/lib/jquery.contextMenu.js"></script>
<script type="text/javascript" src="js/lib/jquery-ui-1.8.17.custom.min.js"></script>
<script type="text/javascript" src="js/lib/css.min.js"></script>
<script type="text/javascript" src="js/jquery.attr.js"></script>
<script type="text/javascript" src="js/lib/jquery-draginput.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
@ -765,6 +770,7 @@
<script type="text/javascript" src="js/Import.js"></script>
<script type="text/javascript" src="js/PaintBox.js"></script>
<script type="text/javascript" src="js/Palette.js"></script>
<script type="text/javascript" src="js/Textonpath.js"></script>
<script type="text/javascript" src="js/Zoom.js"></script>
<script type="text/javascript" src="js/Modal.js"></script>
<script type="text/javascript" src="js/ContextMenu.js"></script>
@ -775,7 +781,6 @@
<script type="text/javascript" src="js/lib/jpicker.min.js"></script>
<script type="text/javascript" src="js/lib/mousewheel.js"></script>
<script type="text/javascript" src="js/eyedropper.js"></script>
<!--<script type="text/javascript" src="js/grid.js"></script>-->
<script type="text/javascript" src="js/lib/requestanimationframe.js"></script>
<script type="text/javascript" src="js/lib/taphold.js"></script>
<script type="text/javascript" src="js/lib/filesaver.js"></script>

View File

@ -33,12 +33,12 @@ MD.Panel = function(){
$('#text_x') .dragInput({ min: null, max: null, step: 1, callback: editor.changeAttribute, cursor: false });
$('#image_y') .dragInput({ min: null, max: null, step: 1, callback: editor.changeAttribute, cursor: false });
$('#rect_rx') .dragInput({ min: 0, max: 100, step: 1, callback: editor.changeAttribute, cursor: true });
$('#stroke_width') .dragInput({ min: 0, max: 99, step: 1, callback: editor.changeAttribute, cursor: true, smallStep: 0.1, start: 1.5 });
$('#stroke_width') .dragInput({ min: 0, max: 99, step: 1, callback: editor.changeAttribute, cursor: true, smallStep: 0.1, start: 1.5 });
$('#angle') .dragInput({ min: -180, max: 180, step: 1, callback: editor.changeRotationAngle, cursor: false, dragAdjust: 0.5 });
$('#font_size') .dragInput({ min: 1, max: 250, step: 1, callback: editor.text.changeFontSize, cursor: true, stepfunc: editor.stepFontSize, dragAdjust: .15 });
$('#font_size') .dragInput({ min: 1, max: 250, step: 1, callback: editor.text.changeFontSize, cursor: true, stepfunc: editor.stepFontSize, dragAdjust: .15 });
$('#group_opacity').dragInput({ min: 0, max: 100, step: 5, callback: editor.changeAttribute, cursor: true, start: 100 });
$('#blur') .dragInput({ min: 0, max: 10, step: .1, callback: editor.changeBlur, cursor: true, start: 0 });
$('#textPath_offset').dragInput({ min: 0, max: null, step: 1, callback: editor.text.setTextPathAttr,cursor: true, start: 0 });
// Align
@ -82,7 +82,6 @@ MD.Panel = function(){
svgCanvas.pathActions.opencloseSubPath();
});
function show(elem) {
$('.context_panel').hide();
if (elem === "canvas") return $('#canvas_panel').show();
@ -100,8 +99,42 @@ MD.Panel = function(){
$.fn.dragInput.updateCursor($('#blur')[0])
}
function pathEditContext(){
$('.context_panel').hide();
$('#path_node_panel').show();
$('#stroke_panel').hide();
var point = svgCanvas.pathActions.getNodePoint();
$('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button');
$('#tool_node_delete').toggleClass('disabled', !svgCanvas.pathActions.canDeleteNodes);
if(point) {
var seg_type = $('#seg_type');
point.x = svgedit.units.convertUnit(point.x);
point.y = svgedit.units.convertUnit(point.y);
$('#path_node_x').val(Math.round(point.x));
$('#path_node_y').val(Math.round(point.y));
if(point.type) {
seg_type.val(point.type).removeAttr('disabled');
$("#seg_type_label").html(point.type === 4 ? "Straight" : "Curve")
} else {
seg_type.val(4).attr('disabled','disabled');
}
}
$("#panels").removeClass("multiselected")
$("#stroke_panel").hide();
$("#canvas_panel").hide();
return;
}
function canPutTextOnPath(elems) {
if (elems.length !== 2) return false;
const text = elems.find(elem => elem.tagName === "text");
const path = elems.find(elem => ["ellipse", "circle", "line", "polyline", "polygon", "rect", "path"].indexOf(elem.tagName) > -1);
return (!!text && !!path);
}
function updateContextPanel(elems) {
if (!elems) elems = editor.selected;
if (!elems) elems = editor.selected;
var elem = elems[0] || editor.selected[0];
const isNode = svgCanvas.pathActions.getNodePoint()
// If element has just been deleted, consider it null
@ -122,7 +155,9 @@ MD.Panel = function(){
if (multiselected) {
const multi = elems.filter(Boolean);
elem = (svgCanvas.elementsAreSame(multi)) ? multi[0] : null
if (elem) $("#panels").addClass("multiselected")
if (elem) $("#panels").addClass("multiselected");
const canTextPath = canPutTextOnPath(multi);
$("#tool_text_on_path").toggle(canTextPath);
}
if (!elem && !multiselected) {
@ -132,6 +167,7 @@ MD.Panel = function(){
}
if (elem !== null) {
$("#stroke_panel").show();
var elname = elem.nodeName;
var angle = svgCanvas.getRotationAngle(elem);
@ -151,8 +187,10 @@ MD.Panel = function(){
y = bb.y;
}
}
x = svgedit.units.convertUnit(x);
y = svgedit.units.convertUnit(y);
$("#" + elname +"_x").val(Math.round(x))
$("#" + elname +"_y").val(Math.round(y))
if (elname === "polyline") {
@ -222,10 +260,18 @@ MD.Panel = function(){
if(el_name === "rect") $("#cornerRadiusLabel").show()
else $("#cornerRadiusLabel").hide()
$.each(cur_panel, function(i, item) {
var attrVal = elem.getAttribute(item);
cur_panel.forEach((item, i) => {
var attrVal = elem.getAttribute(item);
//update the draginput cursors
var name_item = document.getElementById(el_name + '_' + item);
// find a textPath to put correct x and y
if (el_name === "text") {
const textPath = elem.querySelector("textPath");
if (textPath) {
var bb = elem.getBBox();
if (bb) attrVal = bb[item];
}
}
name_item.value = Math.round(attrVal) || 0;
if (name_item.getAttribute("data-cursor") === "true") {
$.fn.dragInput.updateCursor(name_item );
@ -233,7 +279,7 @@ MD.Panel = function(){
});
if(el_name === 'text') {
var font_family = elem.getAttribute("font-family") || "serif";
var font_family = elem.getAttribute("font-family") || "default";
var cleanFontFamily = font_family.split(",")[0].replace(/'/g, "");
var select = document.getElementById("font_family_dropdown");
$('#text_panel').css("display", "inline");
@ -246,6 +292,9 @@ MD.Panel = function(){
$('#font_size').val(elem.getAttribute("font-size"));
$('#text').val(elem.textContent);
$('#preview_font').text(cleanFontFamily).css('font-family', font_family);
const textPath = elem.querySelector("textPath");
document.getElementById("text_panel").classList.toggle("text-path", textPath);
$("#textPath_offset").val(textPath ? textPath.getAttribute("startOffset") : 0);
} // text
else if(el_name === 'image') {
const url = svgCanvas.getHref(elem)
@ -289,7 +338,7 @@ MD.Panel = function(){
if ( (elem && !isNode) || multiselected) {
// update the selected elements' layer
$('#selLayerNames').removeAttr('disabled').val(currentLayerName);
$('#selLayerNames').removeAttr('disabled').val(svgCanvas.getCurrentDrawing().getCurrentLayerName());
// Enable regular menu options
$("#cmenu_canvas").enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back');

View File

@ -1,5 +1,27 @@
MD.Text = function(){
function placeTextOnPath(){
const elems = editor.selected;
const needsConversion = elems.find(elem => ["ellipse", "circle", "line", "polyline", "polygon", "rect"].indexOf(elem.tagName) > -1);
if (needsConversion) {
const path = svgCanvas.convertToPath(needsConversion);
const text = elems.find(elem => elem.tagName === "text");
svgCanvas.addToSelection([path, text]);
}
const text = svgCanvas.textPath();
svgCanvas.clearSelection();
svgCanvas.addToSelection([text]);
editor.selectedChanged(window, [text]);
}
function releaseTextOnPath(){
const text = svgCanvas.releaseTextPath();
const selector = svgCanvas.selectorManager.requestSelector(text);
selector.resize();
editor.selectedChanged(window, [text]);
}
function setBold(){
if ($(this).hasClass("disabled")) return;
svgCanvas.setBold( !svgCanvas.getBold() );
@ -16,6 +38,9 @@ MD.Text = function(){
svgCanvas.setFontFamily(this.value);
});
$('#tool_text_on_path').click(placeTextOnPath);
$('#tool_release_text_on_path').click(releaseTextOnPath);
$("#tool_bold").on("click", setBold);
$("#tool_italic").on("click", setItalic);
@ -43,8 +68,8 @@ MD.Text = function(){
document.fonts.onloadingdone = function (fontFaceSetEvent) {
const els = svgCanvas.getSelectedElems();
els.forEach(el => {
var selector = svgCanvas.selectorManager.requestSelector(el);
selector.resize();
var selector = svgCanvas.selectorManager.requestSelector(el);
selector.resize();
})
};
@ -67,8 +92,15 @@ MD.Text = function(){
svgCanvas.setFontSize($("#font_size").val());
}
function setTextPathAttr(a, val){
svgCanvas.setTextPathAttr('startOffset', val);
var elems = svgCanvas.getSelectedElems();
svgCanvas.selectorManager.requestSelector(elems[0]).reset(elems[0]);
}
this.setBold = setBold;
this.setItalic = setItalic;
this.changeFontSize = changeFontSize;
this.setTextPathAttr = setTextPathAttr;
}

3
src/js/Textonpath.js Normal file
View File

@ -0,0 +1,3 @@
MD.TextOnPath = function(){
console.log("hi")
}

32
src/js/exportHandler.js Normal file
View File

@ -0,0 +1,32 @@
function exportHandler(window, data) {
var issues = data.issues;
if(!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
}
var c = $('#export_canvas')[0];
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
canvg(c, data.svg, {renderCallback: function() {
var datauri = c.toDataURL('image/png');
if (!datauri) return false;
var filename = "Method Draw Image";
var type = 'image/png';
var file = svgedit.utilities.dataURItoBlob(datauri, type);
if (window.navigator.msSaveOrOpenBlob) // IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
else { // Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}});
}

File diff suppressed because it is too large Load Diff

3
src/js/lib/css.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -7,8 +7,8 @@ editor.modal = {
about: new MD.Modal({
html: `
<h1>About this application</h1>
<p>Method Draw is a simple <a href="https://github.com/methodofaction/Method-Draw">open source</a> vector drawing application. Method Draw was forked from <a href="https://github.com/SVG-Edit/svgedit">SVG-Edit</a> several years ago with the goal of improving and modernizing the interface.</p>
<p>At this time (2021), the author (<a href="http://method.ac/writing">Mark MacKay</a>) is working on improving stability and improving the codebase, which contains a lot of legacy practices. The goal is to create a vector editor suitable for simple graphic design tasks.</p>
<p>Fujikohsan Vector Editor is a vector drawing application by Fuji Kosan Co., Ltd. from Tokyo, Japan. Fujikohsan specializes in uniforms, safety clothes, and promotional goods.</p>
<p>Visit our website at <a target="_blank" href="https://fujikohsan.co.jp/">fujikohsan.co.jp</a>
`
}),
source: new MD.Modal({

View File

@ -49,7 +49,8 @@ var curConfig = {
initFill: {color: 'fff', opacity: 1},
initStroke: {width: 1, color: '000', opacity: 1},
imgPath: 'images/',
baseUnit: 'px'
baseUnit: 'px',
defaultFont: "Noto Sans JP"
};
// Update config with new one if given
@ -146,7 +147,7 @@ $.extend(all_properties.text, {
fill: "#000000",
stroke_width: 0,
font_size: 24,
font_family: 'sans-serif'
font_family: curConfig.defaultFont
});
// Current shape style properties
@ -569,15 +570,11 @@ getStrokedBBox = this.getStrokedBBox = function(elems) {
var angle = svgedit.utilities.getRotationAngle(elem);
if ((angle && angle % 90) ||
svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) {
// Accurate way to get BBox of rotated element in Firefox:
// Put element in group and get its BBox
var good_bb = false;
// Get the BBox from the raw path for these elements
var elemNames = ['ellipse','path','line','polyline','polygon'];
if(elemNames.indexOf(elem.tagName) >= 0) {
bb = good_bb = canvas.convertToPath(elem, true);
bb = canvas.convertToPath(elem, true);
} else if(elem.tagName == 'rect') {
// Look for radius
var rx = elem.getAttribute('rx');
@ -586,51 +583,6 @@ getStrokedBBox = this.getStrokedBBox = function(elems) {
bb = good_bb = canvas.convertToPath(elem, true);
}
}
if(!good_bb) {
// Must use clone else FF freaks out
var clone = elem.cloneNode(true);
var g = document.createElementNS(svgns, "g");
var parent = elem.parentNode;
parent.appendChild(g);
g.appendChild(clone);
bb = svgedit.utilities.bboxToObj(g.getBBox());
parent.removeChild(g);
}
// Old method: Works by giving the rotated BBox,
// this is (unfortunately) what Opera and Safari do
// natively when getting the BBox of the parent group
// var angle = angle * Math.PI / 180.0;
// var rminx = Number.MAX_VALUE, rminy = Number.MAX_VALUE,
// rmaxx = Number.MIN_VALUE, rmaxy = Number.MIN_VALUE;
// var cx = round(bb.x + bb.width/2),
// cy = round(bb.y + bb.height/2);
// var pts = [ [bb.x - cx, bb.y - cy],
// [bb.x + bb.width - cx, bb.y - cy],
// [bb.x + bb.width - cx, bb.y + bb.height - cy],
// [bb.x - cx, bb.y + bb.height - cy] ];
// var j = 4;
// while (j--) {
// var x = pts[j][0],
// y = pts[j][1],
// r = Math.sqrt( x*x + y*y );
// var theta = Math.atan2(y,x) + angle;
// x = round(r * Math.cos(theta) + cx);
// y = round(r * Math.sin(theta) + cy);
//
// // now set the bbox for the shape after it's been rotated
// if (x < rminx) rminx = x;
// if (y < rminy) rminy = y;
// if (x > rmaxx) rmaxx = x;
// if (y > rmaxy) rmaxy = y;
// }
//
// bb.x = rminx;
// bb.y = rminy;
// bb.width = rmaxx - rminx;
// bb.height = rmaxy - rminy;
}
return bb;
} catch(e) {
@ -856,6 +808,7 @@ var getId, getNextId, call;
// Parameters:
// newDoc - The SVG DOM document
this.prepareSvg = function(newDoc) {
this.sanitizeSvg(newDoc.documentElement);
// convert paths into absolute commands
@ -865,6 +818,7 @@ this.prepareSvg = function(newDoc) {
path.setAttribute('d', pathActions.convertPath(path));
pathActions.fixEnd(path);
}
};
// Function getRefElem
@ -1286,8 +1240,18 @@ var updateClipPath = function(attr, tx, ty) {
// Undo command object with the resulting change
var recalculateDimensions = this.recalculateDimensions = function(selected) {
if (selected == null) return null;
var tlist = getTransformList(selected);
// apply transformation to path and to text if is textpath
const textPath = selected.querySelector("textPath");
if (textPath) {
return false;
const href = textPath.getAttribute("href");
const id = href.replace("#", "");
const path = svgroot.getElementById(id);
//recalculateDimensions(selected, true);
if (path) selected = path;
}
// remove any unnecessary transforms
if (tlist && tlist.numberOfItems > 0) {
@ -1313,7 +1277,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
// End here if all it has is a rotation
if(tlist.numberOfItems === 1 && getRotationAngle(selected)) return null;
}
// if this element had no transforms, we are done
if (!tlist || tlist.numberOfItems == 0) {
selected.removeAttribute("transform");
@ -1399,6 +1363,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
case "use":
case "text":
case "tspan":
case "textPath":
attrs = ["x", "y"];
break;
case "polygon":
@ -2263,7 +2228,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
if(mouse_target.tagName === 'a' && mouse_target.childNodes.length === 1) {
mouse_target = mouse_target.firstChild;
}
// real_x/y ignores grid-snap value
var real_x = r_start_x = start_x = x;
var real_y = r_start_y = start_y = y;
@ -2339,10 +2304,6 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
}
r_start_x *= current_zoom;
r_start_y *= current_zoom;
// console.log('p',[evt.pageX, evt.pageY]);
// console.log('c',[evt.clientX, evt.clientY]);
// console.log('o',[evt.offsetX, evt.offsetY]);
// console.log('s',[start_x, start_y]);
assignAttributes(rubberBox, {
'x': r_start_x,
@ -3104,7 +3065,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
case "select":
if (selectedElements[0] != null) {
// if we only have one selected element
if (selectedElements.length == 1) {
if (selectedElements.length === 1) {
// set our current stroke/fill properties to the element's
var selected = selectedElements[0];
switch ( selected.tagName ) {
@ -3556,7 +3517,7 @@ var textActions = canvas.textActions = function() {
selblock = document.createElementNS(svgns, "path");
assignAttributes(selblock, {
'id': "text_selectblock",
'fill': "green",
'fill': "blue",
'opacity': .5,
'style': "pointer-events:none"
});
@ -5128,13 +5089,6 @@ this.svgCanvasToString = function() {
pathActions.clear(true);
// Keep SVG-Edit comment on top
$.each(svgcontent.childNodes, function(i, node) {
if(i && node.nodeType === 8 && node.data.indexOf('Created with') >= 0) {
svgcontent.insertBefore(node, svgcontent.firstChild);
}
});
// Move out of in-group editing mode
if(current_group) {
leaveContext();
@ -5162,6 +5116,7 @@ this.svgCanvasToString = function() {
$(this).replaceWith(svg);
}
});
var output = this.svgToString(svgcontent, 0);
// Rewrap gsvg
@ -5171,6 +5126,8 @@ this.svgCanvasToString = function() {
});
}
return output;
};
@ -5202,17 +5159,6 @@ this.svgToString = function(elem, indent) {
var res = getResolution();
var vb = "";
// TODO: Allow this by dividing all values by current baseVal
// Note that this also means we should properly deal with this on import
// if(curConfig.baseUnit !== "px") {
// var unit = curConfig.baseUnit;
// var unit_m = svgedit.units.getTypeMap()[unit];
// res.w = svgedit.units.shortFloat(res.w / unit_m)
// res.h = svgedit.units.shortFloat(res.h / unit_m)
// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"';
// res.w += unit;
// res.h += unit;
// }
if(unit !== "px") {
res.w = svgedit.units.convertUnit(res.w, unit) + unit;
@ -5220,7 +5166,7 @@ this.svgToString = function(elem, indent) {
}
out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"');
var nsuris = {};
// Check elements for namespaces, add if found
@ -5401,9 +5347,11 @@ this.save = function() {
// no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration
var str = this.svgCanvasToString();
if (str.includes(" href=")) str = str.replace(" href=", " xlink:href=");
console.log(str)
var blob = new Blob([ str ], {type: "image/svg+xml;charset=utf-8"});
var dropAutoBOM = true;
saveAs(blob, "method-draw-image.svg", dropAutoBOM);
saveAs(blob, "FVE-image.svg", dropAutoBOM);
};
// Function: rasterExport
@ -5780,6 +5728,23 @@ var convertToGroup = this.convertToGroup = function(elem) {
}
}
this.styleToAttr = function(doc) {
const docEl = doc.documentElement;
const styles = docEl.querySelectorAll("style");
var parser = new cssjs();
styles.forEach(style =>{
var parsed = parser.parseCSS(style.textContent);
parsed.forEach(ruleset => {
const els = docEl.querySelectorAll(ruleset.selector);
els.forEach(el => {
ruleset.rules.forEach(rule => el.setAttribute(rule.directive, rule.value));
})
})
});
styles.forEach(style => {style.parentNode.removeChild(style)});
return doc;
}
//
// Function: setSvgString
// This function sets the current drawing as the input SVG XML.
@ -5793,6 +5758,7 @@ this.setSvgString = function(xmlString) {
try {
// convert string into XML document
var newDoc = svgedit.utilities.text2xml(xmlString);
this.styleToAttr(newDoc);
this.prepareSvg(newDoc);
var batchCmd = new BatchCommand("Change Source");
@ -7176,6 +7142,25 @@ this.setStrokeAttr = function(attr, val) {
}
};
this.setTextPathAttr = function(attr, val) {
cur_shape[attr.replace('-','_')] = val;
var elems = [];
var i = selectedElements.length;
while (i--) {
var elem = selectedElements[i];
if (elem) {
if (elem.tagName === "text") {
const textPath = elem.querySelector("textPath");
if (textPath) elems.push(textPath)
}
}
}
if (elems.length > 0) {
changeSelectedAttribute(attr, val, elems);
call("changed", selectedElements);
}
};
// Function: getStyle
// Returns current style options
this.getStyle = function() {
@ -7505,11 +7490,65 @@ this.getText = function() {
// Parameters:
// val - String with the new text
this.setTextContent = function(val) {
changeSelectedAttribute("#text", val);
const selected = selectedElements[0];
const textPath = selected.querySelector("textPath");
changeSelectedAttribute("#text", val, textPath ? [textPath] : null);
textActions.init(val);
textActions.setCursor();
};
this.textPath = function(){
const text = selectedElements.find(element => element.tagName === "text");
var path = selectedElements.find(element => element.tagName === "path" || element.tagName === "ellipse");
if (path.tagName === "ellipse") {
console.log("ellipse")
}
if (!text || !path) return false;
const textPath = svgdoc.createElementNS(svgns, "textPath");
textPath.textContent = text.textContent;
text.textContent = "";
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", 0);
text.setAttribute("y", 0);
textPath.setAttribute("xlink:href", "#" + path.id);
textPath.setAttribute("href", "#" + path.id);
const offset = (path.getTotalLength()/2).toFixed(0)
textPath.setAttribute("startOffset", offset);
text.appendChild(textPath);
findDefs().appendChild(path);
selectorManager.releaseSelector(path);
selectorManager.requestSelector(text).resize();
call("changed", [textPath]);
return text;
}
this.releaseTextPath = function(){
const text = selectedElements.find(element => element.tagName === "text");
const textPath = text.querySelector("textPath");
const content = textPath.textContent;
if (!text) return false;
const path = svgCanvas.getTextPath(text);
if (!text || !path) return false;
text.removeChild(textPath);
text.textContent = content;
getCurrentDrawing().getCurrentLayer().appendChild(path);
const bb = path.getBBox();
text.setAttribute("x", bb.x);
text.setAttribute("y", bb.y);
return text;
}
this.getTextPath = function(elem){
const textPath = elem.querySelector("textPath");
var path = null;
if (textPath) {
const href = textPath.getAttribute("href");
const id = href.replace("#", "");
path = svgroot.getElementById(id);
}
return path;
}
// Function: setImageURL
// Sets the new image URL for the selected image element. Updates its size if
// a new URL is given
@ -7743,15 +7782,24 @@ this.convertToPath = function(elem, getBBox) {
if(elem.tagName == 'circle') {
rx = ry = $(elem).attr('r');
}
joinSegs([
['M',[(cx-rx),(cy)]],
['M',[(cx),(cy+ry)]], //
['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]],
['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]],
['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]],
['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]],
['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]],
['Z',[]]
]);
//joinSegs([
// ['M',[(cx-rx),(cy)]], //
// ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]],
// ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]],
// ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]],
// ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]],
// ['Z',[]]
//]);
break;
case 'path':
d = elem.getAttribute('d');
@ -7857,6 +7905,19 @@ var changeSelectedAttributeNoUndo = this.changeSelectedAttributeNoUndo = functio
pathActions.moveNode(attr, newValue);
}
var elems = elems || selectedElements;
// get the path instead of text if is textPath
//elems = elems.map((elem) => {
// if (elem.tagName === 'text') {
// const path = svgCanvas.getTextPath(elem);
// console.log(path)
// if (path) elem = path;
// }
// return elem;
//});
var i = elems.length;
var no_xy_elems = ['g', 'polyline', 'path'];
var good_g_attrs = ['transform', 'opacity', 'filter'];
@ -7880,7 +7941,7 @@ var changeSelectedAttributeNoUndo = this.changeSelectedAttributeNoUndo = functio
var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr);
if (oldval == null) oldval = "";
if (oldval !== String(newValue)) {
if (attr == "#text") {
if (attr === "#text") {
var old_w = svgedit.utilities.getBBox(elem).width;
elem.textContent = newValue;

View File

@ -482,9 +482,11 @@ function groupBBFix(selected) {
// elem - Optional DOM element to get the BBox for
svgedit.utilities.getBBox = function(elem) {
var selected = elem || editorContext_.getSelectedElements()[0];
if (selected.nodeName === "textPath") selected = elem.parentNode;
if (elem.nodeType != 1) return null;
var ret = null;
var elname = selected.nodeName;
switch ( elname ) {
case 'text':