Я использую виджет svg ниже из этого ответа на вопрос
Захват подписи с помощью HTML5 и iPad
для создания захватываемой подписи. Код как есть работает, но когда я помещаю над ним контент, например текст в теге <p>
, он перестает работать, что проблематично, поскольку мне нужно, чтобы он находился внизу документа. Кто-нибудь знает, почему он перестает работать и как заставить его работать независимо от того, где он расположен на html-странице?
//init
let r = document.getElementById('r'),
p = document.getElementById('p'),
signaturePath = '',
isDown = false,
svg = document.getElementById('sig_panel'),
b_show = document.getElementById('show'),
b_clear = document.getElementById('clear'),
pathdata = document.getElementById('pathdata');
//drawing functions
function isTouchEvent(e) {
return e.type.match(/^touch/);
}
function getCoords(e) {
if (isTouchEvent(e)) {
return e.targetTouches[0].clientX + ',' + e.targetTouches[0].clientY;
}
return e.clientX + ',' + e.clientY;
}
function down(e) {
signaturePath += 'M' + getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
isDown = true;
if (isTouchEvent(e)) e.preventDefault();
}
function move(e) {
if (isDown) {
signaturePath += 'L' + getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
}
if (isTouchEvent(e)) e.preventDefault();
}
function up(e) {
isDown = false;
if (isTouchEvent(e)) e.preventDefault();
}
//input handlers
r.addEventListener('touchstart', down, false);
r.addEventListener('touchmove', move, false);
r.addEventListener('touchend', up, false);
r.addEventListener('mousedown', down, false);
r.addEventListener('mousemove', move, false);
r.addEventListener('mouseup', up, false);
r.addEventListener('mouseout', up, false);
//helper functions
function clearSignature() {
pathdata.textContent = '';
signaturePath = '';
p.setAttribute('d', '');
}
function getSignature() {
pathdata.textContent = signaturePath;
return signaturePath;
}
//button handlers
b_show.addEventListener('click', getSignature);
b_clear.addEventListener('click', clearSignature);
svg {
margin: .5em;
border: 1px solid gray;
border-radius: .5em;
}
.flex {
display: flex;
}
button {
margin: .5em;
}
#pathdata {
font-family: monospace;
background: #ddd;
padding: 1em;
margin: 1em .5em;
}
<svg id = "sig_panel" xmlns = "http://www.w3.org/2000/svg" width = "300" height = "100" viewBox = "0 0 300 100">
<rect id = "r" width = "300" height = "100" fill = "#ffa"/>
<line x1 = "0" y1 = "80" x2 = "300" y2 = "80" stroke = "#666" stroke-width = "1" stroke-dasharray = "3" shape-rendering = "crispEdges" pointer-events = "none"/>
<path id = "p" stroke = "navy" stroke-width = "2" fill = "none" pointer-events = "none"/>
</svg>
<div class = "flex">
<button id = "show">Show signaure path data</button>
<button id = "clear">Clear signature</button>
</div>
<div id = "pathdata"></div>
Я не могу сказать вам, как на самом деле решить проблему, но могу предложить возможный обходной путь: если svg работает, когда он закодирован как верхний элемент, то вы можете просто создать свою страницу в обратном порядке, а затем использовать flex column-revere
, и svg будет отображаться внизу.
Например: Ниже приведен пример. Для демонстрации я использовал SVG для значка начальной загрузки.
.container {
display: flex;
flex-direction: column-reverse;
/*add other flex properties like justify-content to better display everything*/
}
<div class='container'>
<svg xmlns = "http://www.w3.org/2000/svg" width = "16" height = "16" fill = "currentColor" class = "bi bi-check-circle-fill" viewBox = "0 0 16 16">
<path d = "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
</svg>
<p>Your P element</p>
</div>
Вам необходимо преобразовать координаты экрана в пользовательские единицы SVG, как описано здесь «Как преобразовать координаты элемента svg в координаты экрана?»
Теперь вы можете легко масштабировать свой SVG, не испортив координаты.
По сути, вам нужно только обновить функцию getCoords(e)
.
//init
let r = document.getElementById('r'),
p = document.getElementById('p'),
signaturePath = '',
isDown = false,
svg = document.getElementById('sig_panel'),
b_show = document.getElementById('show'),
b_clear = document.getElementById('clear'),
pathdata = document.getElementById('pathdata');
//drawing functions
function isTouchEvent(e) {
return e.type.match(/^touch/);
}
function getCoords(e) {
let pt
if (isTouchEvent(e)) {
pt = new DOMPoint(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
} else {
pt = new DOMPoint(e.clientX, e.clientY);
}
// get Svg transform matrix
let ctm = svg.getScreenCTM().inverse();
// convert screen to SVG coordinates
pt = pt.matrixTransform(ctm);
// round coordinates
let decimals = 1;
return `${+pt.x.toFixed(decimals)} ${+pt.y.toFixed(decimals)}`;
}
function down(e) {
signaturePath += 'M' + getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
isDown = true;
if (isTouchEvent(e)) e.preventDefault();
}
function move(e) {
if (isDown) {
signaturePath += getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
}
if (isTouchEvent(e)) e.preventDefault();
}
function up(e) {
isDown = false;
if (isTouchEvent(e)) e.preventDefault();
}
//input handlers
r.addEventListener('touchstart', down, false);
r.addEventListener('touchmove', move, false);
r.addEventListener('touchend', up, false);
r.addEventListener('mousedown', down, false);
r.addEventListener('mousemove', move, false);
r.addEventListener('mouseup', up, false);
r.addEventListener('mouseout', up, false);
//button handlers
b_show.addEventListener('click', getSignature);
b_clear.addEventListener('click', clearSignature);
//helper functions
function clearSignature() {
pathdata.textContent = '';
signaturePath = '';
p.setAttribute('d', '');
}
function getSignature() {
pathdata.textContent = signaturePath;
return signaturePath;
}
svg {
margin: .5em;
border: 1px solid gray;
border-radius: .5em;
}
.flex {
display: flex;
}
button {
margin: .5em;
}
#pathdata {
font-family: monospace;
background: #ddd;
padding: 1em;
margin: 1em .5em;
}
<svg id = "sig_panel" viewBox = "0 0 300 100">
<rect id = "r" width = "100%" height = "100%" fill = "#ffa"/>
<line x1 = "0" y1 = "80" x2 = "300" y2 = "80" stroke = "#666" stroke-width = "1" stroke-dasharray = "3" shape-rendering = "crispEdges" pointer-events = "none" />
<path id = "p" stroke = "navy" stroke-width = "2" fill = "none" pointer-events = "none"/>
</svg>
<div class = "flex">
<button id = "show">Show signaure path data</button>
<button id = "clear">Clear signature</button>
</div>
<div id = "pathdata"></div>
КСТАТИ. вы также можете сэкономить несколько байтов, опустив командные буквы L
и применив некоторое округление координат.
Вы также можете поиграть с некоторыми методами сглаживания кривой упрощения, как описано здесь «Гладкое рисование от руки в формате SVG»
Ценю идею, но пока мне не удалось заставить это решение работать. Виджет подписи svg не позволяет мне рисовать подпись в поле даже после помещения в
<div class='container'>
с обозначенным CSS в тегах стиля заголовка.