Anonymous
Создание шаблона с помощью jQuery и повторение его на холсте
Сообщение
Anonymous » 10 ноя 2024, 19:23
Я работаю над алгоритмом размещения узоров для SVG на холсте, и это будет плагин WordPress. Я могу разместить SVG на холсте и вычислить значения ширины и высоты, однако, поскольку SVG имеет углубления и выступы, неправильно учитывать только ограничивающую рамку, поскольку этот метод создает промежутки между шаблонами. Я пытался разместить следующий узор правильно, учитывая реальные границы узора и занимаемую им площадь, но и с этим мне не удалось добиться желаемого результата. Фиксированное значение в любом случае не решает ситуацию, потому что у меня есть шаблоны с очень разными углублениями и выступами.
Вот изображение, которое я получил с помощью написанного мной кода:
Это вот какой образ я пытаюсь достичь:
Я какое-то время застрял на этом этапе проекта и больше не могу найти решение. Где я ошибаюсь? Я думаю, что мне нужна совершенно другая перспектива, потому что я не могу получить желаемый результат с помощью расчета площади, ширины и высоты. Может ли кто-нибудь мне помочь с этим?
Вот мои коды:
Код: Выделить всё
jQuery(document).ready(function($) {
const mainCanvas = $('#cmc-canvas')[0];
const mainCtx = mainCanvas.getContext('2d');
const svgElements = $('.cmc-svg-item');
if (svgElements.length === 0) {
return;
}
function loadAndDrawPattern() {
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
let loadedSVGs = 0;
svgElements.each(function(index, imgElem) {
const svgSrc = $(imgElem).attr('src');
$.get(svgSrc, function(data) {
const svgElement = $(data).find('svg')[0];
if (svgElement) {
const svgData = new XMLSerializer().serializeToString(svgElement);
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(svgBlob);
const img = new Image();
img.onload = function() {
tempCtx.drawImage(img, 0, 0);
loadedSVGs++;
URL.revokeObjectURL(url);
if (loadedSVGs === svgElements.length) {
calculateRealDimensions(tempCanvas);
}
};
img.onerror = function() {
URL.revokeObjectURL(url);
};
img.src = url;
}
}).fail(function() {});
});
}
function calculateRealDimensions(tempCanvas) {
const imageData = tempCanvas.getContext('2d').getImageData(0, 0, tempCanvas.width, tempCanvas.height);
let minX = tempCanvas.width, minY = tempCanvas.height;
let maxX = 0, maxY = 0;
for (let y = 0; y < imageData.height; y++) {
for (let x = 0; x < imageData.width; x++) {
const alpha = imageData.data[(y * imageData.width + x) * 4 + 3];
if (alpha > 0) {
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
}
}
const realWidth = maxX - minX;
const realHeight = maxY - minY;
const patternCanvas = document.createElement('canvas');
patternCanvas.width = realWidth;
patternCanvas.height = realHeight;
const patternCtx = patternCanvas.getContext('2d');
patternCtx.drawImage(tempCanvas, minX, minY, realWidth, realHeight, 0, 0, realWidth, realHeight);
const patternArea = calculatePatternArea(patternCanvas);
fillCanvasWithDynamicPlacement(patternCanvas, patternArea);
}
function calculatePatternArea(tempCanvas) {
const ctx = tempCanvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
let pixelCount = 0;
for (let i = 0; i < imageData.data.length; i += 4) {
const alpha = imageData.data[i + 3];
if (alpha > 0) {
pixelCount++;
}
}
return pixelCount;
}
function fillCanvasWithDynamicPlacement(patternCanvas, patternArea) {
const patternWidth = patternCanvas.width;
const patternHeight = patternCanvas.height;
const mainCanvasWidth = mainCanvas.width;
const mainCanvasHeight = mainCanvas.height;
let currentX = 0;
let currentY = 0;
while (currentY < mainCanvasHeight) {
while (currentX < mainCanvasWidth) {
mainCtx.drawImage(patternCanvas, currentX, currentY, patternWidth, patternHeight);
currentX += patternWidth;
}
currentX = 0;
currentY += patternHeight;
}
}
loadAndDrawPattern();
});
Код, который я упростил и который работает в JSFiddle:
Код: Выделить всё
document.addEventListener('DOMContentLoaded', () => {
const mainCanvas = document.getElementById('cmc-canvas');
const mainCtx = mainCanvas.getContext('2d');
const svgString = `
`;
function loadSVGData(svgString, callback) {
const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
const url = URL.createObjectURL(svgBlob);
const img = new Image();
img.onload = function() {
callback(img);
URL.revokeObjectURL(url);
};
img.onerror = function() {
console.error('SVG yüklenemedi.');
URL.revokeObjectURL(url);
};
img.src = url;
}
function drawSVGOnCanvasRepeated() {
loadSVGData(svgString, (img) => {
const patternWidth = 100; // Desired width of each SVG pattern
const patternHeight = 100; // Desired height of each SVG pattern
let currentX = 0;
let currentY = 0;
while (currentY < mainCanvas.height) {
while (currentX < mainCanvas.width) {
mainCtx.drawImage(img, currentX, currentY, patternWidth, patternHeight);
currentX += patternWidth;
}
currentX = 0;
currentY += patternHeight;
}
});
}
drawSVGOnCanvasRepeated();
});
Подробнее здесь:
https://stackoverflow.com/questions/791 ... nto-canvas
1731255807
Anonymous
Я работаю над алгоритмом размещения узоров для SVG на холсте, и это будет плагин WordPress. Я могу разместить SVG на холсте и вычислить значения ширины и высоты, однако, поскольку SVG имеет углубления и выступы, неправильно учитывать только ограничивающую рамку, поскольку этот метод создает промежутки между шаблонами. Я пытался разместить следующий узор правильно, учитывая реальные границы узора и занимаемую им площадь, но и с этим мне не удалось добиться желаемого результата. Фиксированное значение в любом случае не решает ситуацию, потому что у меня есть шаблоны с очень разными углублениями и выступами. Вот изображение, которое я получил с помощью написанного мной кода: [img]https://i.sstatic.net/65MIH9RB.png[/img] Это вот какой образ я пытаюсь достичь: [img]https://i.sstatic.net/A2cYW6r8.png[/img] Я какое-то время застрял на этом этапе проекта и больше не могу найти решение. Где я ошибаюсь? Я думаю, что мне нужна совершенно другая перспектива, потому что я не могу получить желаемый результат с помощью расчета площади, ширины и высоты. Может ли кто-нибудь мне помочь с этим? Вот мои коды: [code]jQuery(document).ready(function($) { const mainCanvas = $('#cmc-canvas')[0]; const mainCtx = mainCanvas.getContext('2d'); const svgElements = $('.cmc-svg-item'); if (svgElements.length === 0) { return; } function loadAndDrawPattern() { const tempCanvas = document.createElement('canvas'); const tempCtx = tempCanvas.getContext('2d'); let loadedSVGs = 0; svgElements.each(function(index, imgElem) { const svgSrc = $(imgElem).attr('src'); $.get(svgSrc, function(data) { const svgElement = $(data).find('svg')[0]; if (svgElement) { const svgData = new XMLSerializer().serializeToString(svgElement); const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' }); const url = URL.createObjectURL(svgBlob); const img = new Image(); img.onload = function() { tempCtx.drawImage(img, 0, 0); loadedSVGs++; URL.revokeObjectURL(url); if (loadedSVGs === svgElements.length) { calculateRealDimensions(tempCanvas); } }; img.onerror = function() { URL.revokeObjectURL(url); }; img.src = url; } }).fail(function() {}); }); } function calculateRealDimensions(tempCanvas) { const imageData = tempCanvas.getContext('2d').getImageData(0, 0, tempCanvas.width, tempCanvas.height); let minX = tempCanvas.width, minY = tempCanvas.height; let maxX = 0, maxY = 0; for (let y = 0; y < imageData.height; y++) { for (let x = 0; x < imageData.width; x++) { const alpha = imageData.data[(y * imageData.width + x) * 4 + 3]; if (alpha > 0) { minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x); maxY = Math.max(maxY, y); } } } const realWidth = maxX - minX; const realHeight = maxY - minY; const patternCanvas = document.createElement('canvas'); patternCanvas.width = realWidth; patternCanvas.height = realHeight; const patternCtx = patternCanvas.getContext('2d'); patternCtx.drawImage(tempCanvas, minX, minY, realWidth, realHeight, 0, 0, realWidth, realHeight); const patternArea = calculatePatternArea(patternCanvas); fillCanvasWithDynamicPlacement(patternCanvas, patternArea); } function calculatePatternArea(tempCanvas) { const ctx = tempCanvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, tempCanvas.width, tempCanvas.height); let pixelCount = 0; for (let i = 0; i < imageData.data.length; i += 4) { const alpha = imageData.data[i + 3]; if (alpha > 0) { pixelCount++; } } return pixelCount; } function fillCanvasWithDynamicPlacement(patternCanvas, patternArea) { const patternWidth = patternCanvas.width; const patternHeight = patternCanvas.height; const mainCanvasWidth = mainCanvas.width; const mainCanvasHeight = mainCanvas.height; let currentX = 0; let currentY = 0; while (currentY < mainCanvasHeight) { while (currentX < mainCanvasWidth) { mainCtx.drawImage(patternCanvas, currentX, currentY, patternWidth, patternHeight); currentX += patternWidth; } currentX = 0; currentY += patternHeight; } } loadAndDrawPattern(); }); [/code] Код, который я упростил и который работает в JSFiddle: [code]document.addEventListener('DOMContentLoaded', () => { const mainCanvas = document.getElementById('cmc-canvas'); const mainCtx = mainCanvas.getContext('2d'); const svgString = ` `; function loadSVGData(svgString, callback) { const svgBlob = new Blob([svgString], { type: 'image/svg+xml' }); const url = URL.createObjectURL(svgBlob); const img = new Image(); img.onload = function() { callback(img); URL.revokeObjectURL(url); }; img.onerror = function() { console.error('SVG yüklenemedi.'); URL.revokeObjectURL(url); }; img.src = url; } function drawSVGOnCanvasRepeated() { loadSVGData(svgString, (img) => { const patternWidth = 100; // Desired width of each SVG pattern const patternHeight = 100; // Desired height of each SVG pattern let currentX = 0; let currentY = 0; while (currentY < mainCanvas.height) { while (currentX < mainCanvas.width) { mainCtx.drawImage(img, currentX, currentY, patternWidth, patternHeight); currentX += patternWidth; } currentX = 0; currentY += patternHeight; } }); } drawSVGOnCanvasRepeated(); });[/code] [code] [/code] Подробнее здесь: [url]https://stackoverflow.com/questions/79169412/creating-pattern-with-jquery-and-repeat-into-canvas[/url]