Commit 71818282 by ramdayalmunda

changes for pdf

parent 940f5e70
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
hidden { hidden {
display: none; display: none;
} }
canvas:focus-visible{
outline: unset;
}
.header { .header {
position: relative; position: relative;
......
let isModule = (typeof module != 'undefined') ? true : false let isModule = (typeof module != 'undefined') ? true : false
if (!isModule) console.log('Browser Environment') if (!isModule) console.log('Browser Environment')
var ADocEditor = function (customConfig) { var ADocEditor = function (customConfig) {
var container, counter = 0, shadow, pxMmRatio, canvasPxMmRatio, config, htmlStr, htmlTag, htmlObj = {}, fontList = [], headerToolbar = []; var container, counter = 0, shadow, pxMmRatio, config, htmlStr, htmlTag, htmlObj = {}, fontList = [], headerToolbar = [];
const mmPtRatio = 254 / 720; // this is used for font size
var paperSizes = { var paperSizes = {
"A4": { mmWidth: 210, mmHeight: 297 }, "A4": { mmWidth: 210, mmHeight: 297 },
} }
...@@ -13,10 +14,10 @@ var ADocEditor = function (customConfig) { ...@@ -13,10 +14,10 @@ var ADocEditor = function (customConfig) {
background: "#fff", background: "#fff",
margin: 15, // mm margin: 15, // mm
border: "", border: "",
tabWidth: 20, // mm tabWidth: 10, // mm
}, },
style: { style: {
fontSize: 10, // this is in mm fontSize: 11, // this is in pt // 1pt = 1/72 inch // 1pt = 254/72 mm
fontFamily: 'Calibri', fontFamily: 'Calibri',
bold: false, bold: false,
italic: false, italic: false,
...@@ -68,6 +69,7 @@ var ADocEditor = function (customConfig) { ...@@ -68,6 +69,7 @@ var ADocEditor = function (customConfig) {
<div adc-type="sub-menu" adc-action="new-file">New</div> <div adc-type="sub-menu" adc-action="new-file">New</div>
<div adc-type="sub-menu" adc-action="open-file">Open</div> <div adc-type="sub-menu" adc-action="open-file">Open</div>
<div adc-type="sub-menu" adc-action="save-file">Save</div> <div adc-type="sub-menu" adc-action="save-file">Save</div>
<div adc-type="sub-menu" adc-action="print-file">Print</div>
</div> </div>
</div> </div>
<div class="item" adc-target="help-menu" adc-type="menu-item"> <div class="item" adc-target="help-menu" adc-type="menu-item">
...@@ -247,6 +249,9 @@ var ADocEditor = function (customConfig) { ...@@ -247,6 +249,9 @@ var ADocEditor = function (customConfig) {
}) })
shadow.querySelector('[adc-action="open-file"]') shadow.querySelector('[adc-action="open-file"]')
.addEventListener('click', () => { openFileInput.click() }) .addEventListener('click', () => { openFileInput.click() })
shadow.querySelector('[adc-action="print-file"]')
.addEventListener('click', printDoc)
})() })()
reConfigure(customConfig) reConfigure(customConfig)
...@@ -417,7 +422,7 @@ var ADocEditor = function (customConfig) { ...@@ -417,7 +422,7 @@ var ADocEditor = function (customConfig) {
lineObj.plainContent = dataBlock.plainContent.slice(lineObj.charStartIndex, lineObj.charEndIndex + 1) lineObj.plainContent = dataBlock.plainContent.slice(lineObj.charStartIndex, lineObj.charEndIndex + 1)
// there is chance that the last line is not at the width// so we need to handle the last line separately // there is chance that the last line is not at the width// so we need to handle the last line separately
if (lineObj.charEndIndex <= dataBlock.plainContent.length) { if (lineObj.charEndIndex <= dataBlock.plainContent.length) {
lineObj.charEndIndex = dataBlock.plainContent.length - 1 lineObj.charEndIndex = dataBlock.plainContent.length
} }
lineObj.plainContent = dataBlock.plainContent.slice(lineObj.charStartIndex, lineObj.charEndIndex) lineObj.plainContent = dataBlock.plainContent.slice(lineObj.charStartIndex, lineObj.charEndIndex)
...@@ -430,24 +435,45 @@ var ADocEditor = function (customConfig) { ...@@ -430,24 +435,45 @@ var ADocEditor = function (customConfig) {
} }
function renderLines() { function renderLines() {
let maxHeight = config.pageSetup.pxHeight - config.format.margin * pxMmRatio * 2
let pageIndex = 0
let x = 0, y = config.format.margin * pxMmRatio; let x = 0, y = config.format.margin * pxMmRatio;
for (let l = 0; l < lines.length; l++) { for (let l = 0; l < lines.length; l++) {
let setData = dataList[lines[l].dataIndex] let setData = dataList[lines[l].dataIndex]
let ctx = pageList[0].el.getContext('2d', { willReadFrequently: true }) let ctx = pageList[pageIndex].el.getContext('2d', { willReadFrequently: true })
x = config.format.margin * pxMmRatio x = config.format.margin * pxMmRatio
x += lines[l].tabWidth x += lines[l].tabWidth
y = y + (lines[l].maxFontSize * pxMmRatio) y = y + (lines[l].maxFontSize * pxMmRatio * mmPtRatio)
lines[l].y = y lines[l].y = y
// check if the line is to be written on the next page
if (maxHeight < y) {
pageIndex++
if (!pageList?.[pageIndex]) {
pageList[pageIndex] = { id: ++counter, el: createNewPage(), dataIndex: lines[l].dataIndex }
shadow.querySelector('[adc="page-list"]').append(pageList[pageIndex].el)
}
ctx = pageList[pageIndex].el.getContext('2d', { willReadFrequently: true })
y = config.format.margin * pxMmRatio + (lines[l].maxFontSize * pxMmRatio * mmPtRatio);
lastFocussedPage = pageList[pageIndex].el
caretData.blink = false
focusOnPage({ scroll: true })
}
lines[l].pageIndex = pageIndex
ctx.save() ctx.save()
// this is to render the numbering and bullets etc // this is to render the numbering and bullets etc
if (lines[l].dataType == 1) { if (lines[l].dataType == 1) {
ctx.save() ctx.save()
ctx.font = `${setData.style.fontSize * pxMmRatio}px ${setData.style.fontFamily}` ctx.font = `${setData.style.fontSize * pxMmRatio * mmPtRatio}px ${setData.style.fontFamily}`
ctx.fillStyle = `${setData.style.fontColor}` ctx.fillStyle = `${setData.style.fontColor}`
let label = getLabel(lines[l].dataIndex) let label = getLabel(lines[l].dataIndex)
let labelWidth = ctx.measureText(label).width let labelWidth = ctx.measureText(label).width
labelWidth += pxMmRatio * 5 labelWidth += mmPtRatio * pxMmRatio * 5
lines[l].labelWidth = labelWidth
ctx.fillText(label, x - labelWidth, y) ctx.fillText(label, x - labelWidth, y)
ctx.restore() ctx.restore()
} }
...@@ -459,7 +485,7 @@ var ADocEditor = function (customConfig) { ...@@ -459,7 +485,7 @@ var ADocEditor = function (customConfig) {
if (char) { if (char) {
let style = setData.formatedText[c] let style = setData.formatedText[c]
ctx.save() ctx.save()
ctx.font = `${style?.bold ? 'bold ' : ''}${style?.italic ? 'italic ' : ''} ${style.fontSize * pxMmRatio}px ${style.fontFamily}` ctx.font = `${style?.bold ? 'bold ' : ''}${style?.italic ? 'italic ' : ''} ${style.fontSize * pxMmRatio * mmPtRatio}px ${style.fontFamily}`
ctx.fillStyle = `${style?.fontColor}` ctx.fillStyle = `${style?.fontColor}`
ctx.fillText(char, x, y) ctx.fillText(char, x, y)
setData.formatedText[c].x = x setData.formatedText[c].x = x
...@@ -476,63 +502,12 @@ var ADocEditor = function (customConfig) { ...@@ -476,63 +502,12 @@ var ADocEditor = function (customConfig) {
return return
} }
function getLabel(dataIndex) {
let label = "x."
if (dataList[dataIndex].listStyle == 0) { // 1. a. i.
let tabCount = dataList[dataIndex].tabCount
tabCount = tabCount ? tabCount : 0
if (tabCount % 3 == 0) label = `${dataList[dataIndex].listItemNumber}.`
else if (tabCount % 3 == 1) label = `${convertToLetter(dataList[dataIndex].listItemNumber)}.`
else label = `${convertToRoman(dataList[dataIndex].listItemNumber).toLowerCase()}.`
}
else if (dataList[dataIndex].listStyle == 1) { // >
label = `>`
}
function convertToLetter(num) {
num = (num - 1).toString(26)
let label = ""
for (let i = 0; i < num.length; i++) label += letters[num[i]]
return label
}
function convertToRoman(num) {
let result = '';
let divisor = 1000;
for (let i = 3; i >= 0; i--) {
const digit = Math.floor(num / divisor);
num %= divisor;
divisor /= 10;
if (digit > 0) {
if (digit === 9) {
result += romanNumerals[i][3];
} else if (digit >= 5) {
result += romanNumerals[i][2];
result += romanNumerals[i][0].repeat(digit - 5);
} else if (digit === 4) {
result += romanNumerals[i][1];
} else {
result += romanNumerals[i][0].repeat(digit);
}
}
}
return result;
}
return label
}
function getCharacterWidth(char, style) { function getCharacterWidth(char, style) {
let canvas = pageList[0].el let canvas = pageList[0].el
let ctx = canvas.getContext('2d', { willReadFrequently: true }) let ctx = canvas.getContext('2d', { willReadFrequently: true })
ctx.save() ctx.save()
ctx.font = `${style?.bold ? 'bold ' : ''}${style?.italic ? 'italic ' : ''} ${style.fontSize * pxMmRatio}px ${style.fontFamily}` ctx.font = `${style?.bold ? 'bold ' : ''}${style?.italic ? 'italic ' : ''} ${style.fontSize * pxMmRatio * mmPtRatio}px ${style.fontFamily}`
ctx.fillStyle = `${style?.fontColor}` ctx.fillStyle = `${style?.fontColor}`
let width = ctx.measureText(char).width let width = ctx.measureText(char).width
ctx.restore() ctx.restore()
...@@ -680,7 +655,7 @@ var ADocEditor = function (customConfig) { ...@@ -680,7 +655,7 @@ var ADocEditor = function (customConfig) {
let found = false let found = false
for (let l = 0; l < lines.length; l++) { for (let l = 0; l < lines.length; l++) {
if ((cursor.y <= lines[l].y) && (cursor.y >= (lines[l].maxFontSize * pxMmRatio))) { if ((cursor.y <= lines[l].y) && (cursor.y >= (lines[l].maxFontSize * pxMmRatio * mmPtRatio))) {
let dataSet = dataList[lines[l].dataIndex] let dataSet = dataList[lines[l].dataIndex]
for (let c = lines[l].charStartIndex; c <= lines[l].charEndIndex; c++) { for (let c = lines[l].charStartIndex; c <= lines[l].charEndIndex; c++) {
if ((cursor.x >= dataSet.formatedText[c].x) && (cursor.x <= (dataSet.formatedText[c].width + dataSet.formatedText[c].x))) { if ((cursor.x >= dataSet.formatedText[c].x) && (cursor.x <= (dataSet.formatedText[c].width + dataSet.formatedText[c].x))) {
...@@ -730,6 +705,58 @@ var ADocEditor = function (customConfig) { ...@@ -730,6 +705,58 @@ var ADocEditor = function (customConfig) {
} }
} }
function getLabel(dataIndex) {
let label = "x."
if (dataList[dataIndex].listStyle == 0) { // 1. a. i.
let tabCount = dataList[dataIndex].tabCount
tabCount = tabCount ? tabCount : 0
if (tabCount % 3 == 0) label = `${dataList[dataIndex].listItemNumber}.`
else if (tabCount % 3 == 1) label = `${convertToLetter(dataList[dataIndex].listItemNumber)}.`
else label = `${convertToRoman(dataList[dataIndex].listItemNumber).toLowerCase()}.`
}
else if (dataList[dataIndex].listStyle == 1) { // >
label = `>`
}
function convertToLetter(num) {
num = (num - 1).toString(26)
let label = ""
for (let i = 0; i < num.length; i++) label += letters[num[i]]
return label
}
function convertToRoman(num) {
let result = '';
let divisor = 1000;
for (let i = 3; i >= 0; i--) {
const digit = Math.floor(num / divisor);
num %= divisor;
divisor /= 10;
if (digit > 0) {
if (digit === 9) {
result += romanNumerals[i][3];
} else if (digit >= 5) {
result += romanNumerals[i][2];
result += romanNumerals[i][0].repeat(digit - 5);
} else if (digit === 4) {
result += romanNumerals[i][1];
} else {
result += romanNumerals[i][0].repeat(digit);
}
}
}
return result;
}
return label
}
function changeListStyle() { function changeListStyle() {
let activeDataIndex = dataList.findIndex(item => item.id == caretData.activeData.id) let activeDataIndex = dataList.findIndex(item => item.id == caretData.activeData.id)
let d = activeDataIndex - 1 let d = activeDataIndex - 1
...@@ -762,6 +789,12 @@ var ADocEditor = function (customConfig) { ...@@ -762,6 +789,12 @@ var ADocEditor = function (customConfig) {
format = format[format.length - 1] format = format[format.length - 1]
fontObj.paths.push(paths[i]) fontObj.paths.push(paths[i])
linkString += `url(${paths[i]}) format("${format == 'ttf' ? 'truetype' : format}")${(i >= paths.length - 1) ? '' : ',\n'}` linkString += `url(${paths[i]}) format("${format == 'ttf' ? 'truetype' : format}")${(i >= paths.length - 1) ? '' : ',\n'}`
if (format == 'ttf') {
fetch(paths[i])
.then(response => response.arrayBuffer())
.then(fontBytes => { fontObj.fontBytes = fontBytes })
}
} }
const customFont = new FontFace(`${name}`, `${linkString}`); const customFont = new FontFace(`${name}`, `${linkString}`);
customFont.load() customFont.load()
...@@ -820,12 +853,18 @@ var ADocEditor = function (customConfig) { ...@@ -820,12 +853,18 @@ var ADocEditor = function (customConfig) {
if (item.getAttribute('adc') == targetId) item.classList.toggle('show') if (item.getAttribute('adc') == targetId) item.classList.toggle('show')
else item.classList.remove('show') else item.classList.remove('show')
}) })
} }
function renderCaret(toLoop) { function renderCaret(toLoop) {
clearTimeout(caretData.timeout) clearTimeout(caretData.timeout)
let ctx = pageList[0].el.getContext('2d', { willReadFrequently: true }) let dataIndex = dataList.findIndex(item => item.id == caretData.activeData.id)
let lineIndex = lines.findIndex(item => item.dataIndex == dataIndex && caretData.index <= item.charEndIndex)
let lineObj = lines[lineIndex]
let prevLine = lines[lineIndex - 1]
let ctx = pageList[lineObj.pageIndex].el.getContext('2d', { willReadFrequently: true })
ctx.save() ctx.save()
if (caretData.previousCaret) { if (caretData.previousCaret) {
ctx.putImageData(caretData.previousCaret.imageData, caretData.previousCaret.x, caretData.previousCaret.y); ctx.putImageData(caretData.previousCaret.imageData, caretData.previousCaret.x, caretData.previousCaret.y);
...@@ -836,16 +875,21 @@ var ADocEditor = function (customConfig) { ...@@ -836,16 +875,21 @@ var ADocEditor = function (customConfig) {
let lineObj = lines.find(item => item.dataIndex == dataIndex && caretData.index >= item.charStartIndex) let lineObj = lines.find(item => item.dataIndex == dataIndex && caretData.index >= item.charStartIndex)
let x = (config.format.margin * pxMmRatio) + lineObj.tabWidth let x = (config.format.margin * pxMmRatio) + lineObj.tabWidth
let y = (config.format.margin) * pxMmRatio let y = (config.format.margin) * pxMmRatio
let height = caretData.style.fontSize * pxMmRatio * 5 / 4 let height = caretData.style.fontSize * pxMmRatio * mmPtRatio * 5 / 4
let width = height / 10 let width = height / 10
let charData = caretData.activeData.formatedText[caretData.index - 1] let charData = caretData.activeData.formatedText[caretData.index - 1]
if (lineObj) { if (lineObj) {
x = (charData ? (charData.x + charData.width) : x) x = (charData ? (charData.x + charData.width) : x)
if (charData) { if (charData) {
y = charData.y - (caretData.style.fontSize * pxMmRatio) y = charData.y - (caretData.style.fontSize * pxMmRatio * mmPtRatio)
} else { } else {
y = lineObj.y - (lineObj.maxFontSize * pxMmRatio) if (prevLine && prevLine.pageIndex != lineObj.pageIndex) {
y = (config.format.margin) * pxMmRatio
}
else {
y = lineObj.y - (lineObj.maxFontSize * pxMmRatio * mmPtRatio)
}
} }
} }
...@@ -866,6 +910,13 @@ var ADocEditor = function (customConfig) { ...@@ -866,6 +910,13 @@ var ADocEditor = function (customConfig) {
caretData.blink = false caretData.blink = false
} }
let thisPage = pageList[lineObj.pageIndex].el
if (thisPage != focussedPage) {
lastFocussedPage = thisPage
focussedPage = thisPage
focusOnPage()
}
ctx.restore() ctx.restore()
if (toLoop) { if (toLoop) {
caretData.timeout = setTimeout(() => { caretData.timeout = setTimeout(() => {
...@@ -874,13 +925,16 @@ var ADocEditor = function (customConfig) { ...@@ -874,13 +925,16 @@ var ADocEditor = function (customConfig) {
} }
return return
} }
function focusOnPage() { function focusOnPage(options = { scroll: false }) {
caretData.blink = false caretData.blink = false
if (!lastFocussedPage) lastFocussedPage = pageList[0].el if (!lastFocussedPage) lastFocussedPage = pageList[0].el
if (lastFocussedPage) { if (lastFocussedPage) {
const scrollTop = pageScrollingDiv.scrollTop const scrollTop = pageScrollingDiv.scrollTop
lastFocussedPage.focus() lastFocussedPage.focus(); // comment this
pageScrollingDiv.scrollTop = scrollTop pageScrollingDiv.scrollTop = scrollTop
if (options.scroll) {
lastFocussedPage.scrollIntoView({ behavior: "smooth" })
}
} }
} }
...@@ -931,6 +985,8 @@ var ADocEditor = function (customConfig) { ...@@ -931,6 +985,8 @@ var ADocEditor = function (customConfig) {
function compressDocJSON() { function compressDocJSON() {
let activeDataIndex = dataList.findIndex(item => item.id == caretData.activeData.id) let activeDataIndex = dataList.findIndex(item => item.id == caretData.activeData.id)
let returnObj = { let returnObj = {
lines: JSON.parse(JSON.stringify(lines)), // this is not required by the user.
pxMmRatio: pxMmRatio,
config: JSON.parse(JSON.stringify(config)), config: JSON.parse(JSON.stringify(config)),
content: JSON.parse(JSON.stringify(dataList)), content: JSON.parse(JSON.stringify(dataList)),
caretData: JSON.parse(JSON.stringify(caretData)) caretData: JSON.parse(JSON.stringify(caretData))
...@@ -956,6 +1012,100 @@ var ADocEditor = function (customConfig) { ...@@ -956,6 +1012,100 @@ var ADocEditor = function (customConfig) {
reRenderCanvas() reRenderCanvas()
} }
// http://localhost:3910/assets/fonts/calibri-regular.woff2
async function printDoc() {
// pdf dimention in pdf-lib is based on 'pt' or 'points' by default.
// 1pt = 1/72 inch
const { PDFDocument, rgb } = PDFLib
const pdfDoc = await PDFDocument.create();
pdfDoc.registerFontkit(fontkit)
let embeddedFonts = {}
let page;
let pageHeight = config.pageSetup.mmHeight / mmPtRatio
let pageWidth = config.pageSetup.mmWidth / mmPtRatio
let x = 0, y = config.format.margin * pxMmRatio;
for (let l = 0; l < lines.length; l++) {
let dataSet = dataList[lines[l].dataIndex]
if (lines?.[l - 1]?.pageIndex != lines[l].pageIndex) {
page = pdfDoc.addPage([pageWidth, pageHeight]);
}
x = config.format.margin * pxMmRatio
x += lines[l].tabWidth
// this is to render the numbering and bullets etc
if (lines[l].dataType == 1) {
let fontObj = fontList.find(item => item.name == dataSet.style.fontFamily)
let font = embeddedFonts[fontObj.name]
if (!font) {
const fontBytes = fontObj.fontBytes
font = await pdfDoc.embedFont(fontBytes);
embeddedFonts[fontObj.name] = font
}
let label = getLabel(lines[l].dataIndex)
let width = lines[l].labelWidth
x = (x - width) / (pxMmRatio * mmPtRatio)
y = pageHeight - lines[l].y / (pxMmRatio * mmPtRatio)
page.drawText(label, {
x, y, font,
size: dataSet.style.fontSize,
color: rgb(...getRgb(dataSet.style.fontColor))
});
}
for (let c = lines[l].charStartIndex; c < lines[l].charEndIndex; c++) {
let fontObj = fontList.find(item => item.name == dataSet.formatedText[c].fontFamily)
let font = embeddedFonts[fontObj.name]
if (!font) {
const fontBytes = fontObj.fontBytes
font = await pdfDoc.embedFont(fontBytes);
embeddedFonts[fontObj.name] = font
}
x = dataSet.formatedText[c].x / (pxMmRatio * mmPtRatio); // X-coordinate
y = pageHeight - dataSet.formatedText[c].y / (pxMmRatio * mmPtRatio); // Y-coordinate
page.drawText(dataSet.plainContent[c], {
x, y, font,
size: dataSet.formatedText[c].fontSize,
color: rgb(...getRgb(dataSet.formatedText[c].fontColor))
});
}
// Set the font and size
// Embed the custom font
}
function getRgb(hex) {
let rgbArr = [0, 0, 0]
if (hex.length == 7) {
rgbArr = [parseInt(hex.slice(1, 3), 16) / 255, parseInt(hex.slice(3, 5), 16) / 255, parseInt(hex.slice(5, 7), 16) / 255]
} else if (hex.length == 4) {
rgbArr = [parseInt(hex.slice(1, 2), 16) / 15, parseInt(hex.slice(2, 3), 16) / 15, parseInt(hex.slice(3, 4), 16) / 15]
}
return rgbArr
}
// Save the modified PDF
const pdfBytes = await pdfDoc.save();
// For demonstration purposes, you can download the PDF
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const link = shadow.querySelector('[adc="download-link"]');
link.href = URL.createObjectURL(blob);
link.download = '1_from_editor.pdf';
link.click();
}
var returnObj = { var returnObj = {
getDocumentData() { getDocumentData() {
return compressDocJSON() return compressDocJSON()
...@@ -972,6 +1122,7 @@ var ADocEditor = function (customConfig) { ...@@ -972,6 +1122,7 @@ var ADocEditor = function (customConfig) {
console.log(compressDocJSON()) console.log(compressDocJSON())
}, },
focusOnPage, focusOnPage,
printDoc,
} }
initialize() initialize()
......
...@@ -13,7 +13,9 @@ var tempDocData = [ ...@@ -13,7 +13,9 @@ var tempDocData = [
var editor = new ADocEditor({ var editor = new ADocEditor({
container: document.getElementById("user-container-for-editor") container: document.getElementById("user-container-for-editor")
}) })
editor.focusOnPage() setTimeout( ()=>{
editor.focusOnPage()
}, 100)
var extractedData = null var extractedData = null
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment