代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@8.3.5/konva.min.js"></script>
<script src="./js/quilli.js"></script>
<link rel="stylesheet" href="./css/quilli.snow.css" />
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<meta charset="utf-8" />
<title>Konva Rich text on Canvas Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
#editor-container {}
.ql-editor {
overflow: visible;
}
</style>
</head>
<body>
<div id="editor-container">
That is <u>some</u> <span style="color: red"> styled text</span> on
<strong>canvas</strong>!
<h2>What do you think about it?</h2>
</div>
Rendered stage:
<div id="container"></div>
<script>
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
],
},
placeholder: 'Compose an epic...',
theme: 'snow', // or 'bubble'
});
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
const layer = new Konva.Layer();
stage.add(layer);
const shape = new Konva.Image({
x: 20,
y: 20,
draggable: true,
stroke: 'red',
scaleX: 1 / window.devicePixelRatio,
scaleY: 1 / window.devicePixelRatio,
});
var MIN_WIDTH = 60;
var tr = new Konva.Transformer({
nodes: [shape],
padding: 5,
// enable only side anchors
enabledAnchors: ['middle-left', 'middle-right'],
// limit transformer size
boundBoxFunc: (oldBox, newBox) => {
if (newBox.width < MIN_WIDTH) {
return oldBox;
}
return newBox;
},
});
layer.add(tr);
layer.add(shape);
function renderText() {
let qlEditor = document.querySelector('.ql-editor');
const calcWidth = shape.width() * shape.scaleX()
qlEditor.style.width = Math.max(calcWidth, MIN_WIDTH) + 'px'
console.log(qlEditor.style.width)
// convert DOM into image
html2canvas(document.querySelector('.ql-editor'), {
backgroundColor: 'rgba(0,0,0,0)',
}).then((canvas) => {
if (canvas.width > 0) {
// show it inside Konva.Image
shape.image(canvas);
}
});
}
// batch updates, so we don't render text too frequently
var timeout = null;
function requestTextUpdate(time = 500) {
clearTimeout(timeout)
timeout = setTimeout(() => {
timeout = null;
renderText();
}, time);
}
// render text on all changes
quill.on('text-change', requestTextUpdate);
// make initial rendering
renderText();
shape.on('transform', () => {
// with enabled anchors we can only change scaleX
// so we don't need to reset height
// just width
/* shap.setAttrs({
width: Math.max(text.width() * text.scaleX(), MIN_WIDTH),
scaleX: 1,
scaleY: 1,
}); */
requestTextUpdate(200)
});
shape.on('dblclick dbltap', () => {
// hide text node and transformer:
shape.hide();
tr.hide();
// create textarea over canvas with absolute position
// first we need to find position for textarea
// how to find it?
// at first lets find position of text node relative to the stage:
var textPosition = shape.absolutePosition();
// so position of textarea will be the sum of positions above:
var areaPosition = {
x: stage.container().offsetLeft + textPosition.x,
y: stage.container().offsetTop + textPosition.y,
};
// create textarea and style it
var textarea = document.querySelector('.ql-editor')
// apply many styles to match text on canvas as close as possible
// remember that text rendering on canvas and on the textarea can be different
// and sometimes it is hard to make it 100% the same. But we will try...
textarea.style.display = 'block';
textarea.style.position = 'absolute';
textarea.style.top = areaPosition.y - 40 + 'px';
textarea.style.left = areaPosition.x - 1 + 'px';
textarea.style.width = Math.max(shape.width() * shape.scaleX(), MIN_WIDTH) + 'px'
/* textarea.style.height =
shape.height() + 5 + 'px'; */
textarea.style.border = 'none';
// textarea.style.padding = '12px 30px 12px 15px';
// textarea.style.margin = '0px';
// textarea.style.overflow = 'hidden';
textarea.style.background = 'none';
textarea.style.outline = 'none';
textarea.style.resize = 'none';
textarea.style.transformOrigin = 'left top';
textarea.style.color = shape.fill();
textarea.style.zIndex = 999;
rotation = shape.rotation();
var transform = '';
if (rotation) {
transform += 'rotateZ(' + rotation + 'deg)';
}
var px = 0;
// also we need to slightly move textarea on firefox
// because it jumps a bit
var isFirefox =
navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if (isFirefox) {
px += 2 + Math.round(shape.fontSize() / 20);
}
transform += 'translateY(-' + px + 'px)';
textarea.style.transform = transform;
// reset height
textarea.style.height = 'auto';
// after browsers resized it we can set actual value
// textarea.style.height = textarea.scrollHeight + 3 + 'px';
textarea.focus();
function removeTextarea() {
textarea.style.display = 'none';
window.removeEventListener('click', handleOutsideClick);
shape.show();
tr.show();
tr.forceUpdate();
}
function setTextareaWidth(newWidth) {
if (!newWidth) {
// set width for placeholder
newWidth = shape.placeholder.length * shape.fontSize();
}
// some extra fixes on different browsers
var isSafari = /^((?!chrome|android).)*safari/i.test(
navigator.userAgent
);
var isFirefox =
navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if (isSafari || isFirefox) {
newWidth = Math.ceil(newWidth);
}
var isEdge =
document.documentMode || /Edge/.test(navigator.userAgent);
if (isEdge) {
newWidth += 1;
}
textarea.style.width = newWidth + 'px';
}
function handleOutsideClick(e) {
e.stopPropagation()
if (!textarea.contains(e.target) &&
!document.querySelector(".ql-toolbar").contains(e.target)) {
// shape.text(textarea.value);
removeTextarea();
}
}
setTimeout(() => {
window.addEventListener('click', handleOutsideClick);
});
});
// document.querySelector('.ql-editor').style.display = 'none'
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。