我正在开发一个项目,其中使用 Fabric.js 库创建带有文本和图像的画布。我有一个要求,即使我主动选择要上传的图像,我也想确保文本始终保留在顶层。
我已经实现了上传图像并将文本添加到画布的功能。但是,当我选择图像时,图像似乎覆盖了文本,这不是我想要的行为。相反,我希望文本保留在顶层,无论是否选择图像。
我尝试使用以下方法来管理分层:
canvas.sendBackwards(myObject)
canvas.sendToBack(myObject)
canvas.bringForward(myObject)
canvas.bringToFront(myObject)
但是,我还没有达到预期的行为。在图像上传过程中,文本仍然被图像遮挡。
<script>
// Initialize Firebase with your own config
const firebaseConfig = {//
};
firebase.initializeApp(firebaseConfig);
const storage = firebase.storage();
const firestore = firebase.firestore();
// Update the submit button click event handler
document
.getElementById("submit-button")
.addEventListener("click", async () => {
const imageFilename = document.getElementById("image-filename").value;
// Convert the canvas to a PNG data URL
const pngDataURL = canvas.toDataURL({ format: "png", multiplier: 3 }); // Adjust multiplier as needed for higher resolution
// Convert the data URL to a Blob
const pngBlob = await (await fetch(pngDataURL)).blob();
// Create a reference to Firebase storage
const storageRef = storage.ref();
// Define the path for the uploaded PNG
const pngPath = `designs/${imageFilename}.png`;
// Upload PNG to Firebase storage
const pngUploadTask = storageRef.child(pngPath).put(pngBlob);
pngUploadTask.on(
"state_changed",
(snapshot) => {
// Handle upload progress if needed
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(`Upload progress: ${progress}%`);
},
(error) => {
// Handle errors
console.error("Upload error:", error);
},
async () => {
// Get the download URL of the uploaded PNG
const downloadURL =
await pngUploadTask.snapshot.ref.getDownloadURL();
console.log("PNG download URL:", downloadURL);
const designRef = firestore.collection("designs").doc();
const timestamp = firebase.firestore.FieldValue.serverTimestamp();
await designRef.set({
filename: imageFilename,
url: downloadURL,
timestamp: timestamp,
completed: false,
});
// Show a success message
window.location.href = "thank_you.html";
// Clear the filename input field
document.getElementById("image-filename").value = "";
}
);
});
const canvas = new fabric.Canvas("spacebar-canvas");
// Load the sample SVG background
fabric.loadSVGFromURL("sample.svg", function (objects, options) {
const svg = fabric.util.groupSVGElements(objects, options);
svg.scaleToWidth(canvas.width);
svg.scaleToHeight(canvas.height);
canvas.setBackgroundImage(svg, canvas.renderAll.bind(canvas));
});
document
.getElementById("image-upload")
.addEventListener("change", handleImageUpload);
document
.getElementById("image-upload-2")
.addEventListener("change", handleImageUpload);
document
.getElementById("image-upload-3")
.addEventListener("change", handleImageUpload);
document
.getElementById("text-input")
.addEventListener("input", updateText);
document
.getElementById("font-family")
.addEventListener("change", updateText);
document
.getElementById("font-weight")
.addEventListener("change", updateText);
document.getElementById("italic").addEventListener("change", updateText);
document
.getElementById("text-color")
.addEventListener("input", updateTextColor);
document
.getElementById("shape-color")
.addEventListener("input", updateShapeColor);
document
.getElementById("small-shape-color")
.addEventListener("input", updateSmallShapeColor);
function handleImageUpload(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (event) {
const imageUrl = event.target.result;
fabric.Image.fromURL(imageUrl, function (img) {
img.scaleToWidth(40); // Adjust the width
img.set({ left: 100, top: 10 }); // Adjust the initial position
canvas.add(img);
canvas.sendToBack(img); // Send the image to the back
canvas.renderAll();
});
};
reader.readAsDataURL(file);
}
}
// Add an event listener to the text input to select the text object when focused
document
.getElementById("text-input")
.addEventListener("focus", selectTextObject);
function selectTextObject() {
const textObject = canvas.getActiveObject();
if (textObject && textObject.type === "text") {
canvas.setActiveObject(textObject);
canvas.renderAll();
}
}
// Update the text input event listeners
document
.getElementById("text-input")
.addEventListener("input", updateText);
document
.getElementById("font-family")
.addEventListener("change", updateText);
document
.getElementById("font-weight")
.addEventListener("change", updateText);
document.getElementById("italic").addEventListener("change", updateText);
document
.getElementById("text-color")
.addEventListener("input", updateTextColor);
// Update the updateText function
function updateText() {
const text = document.getElementById("text-input").value;
const fontFamily = document.getElementById("font-family").value;
const fontWeight = document.getElementById("font-weight").value;
const isItalic = document.getElementById("italic").checked;
const textColor = document.getElementById("text-color").value;
// Remove existing text object before adding a new one
canvas.forEachObject(function (obj) {
if (obj.type === "text") {
canvas.remove(obj);
}
});
if (text) {
const textObject = new fabric.Text(text, {
left: canvas.width / 2,
top: canvas.height / 2,
fontSize: 18,
fontFamily: fontFamily,
fontWeight: fontWeight,
fontStyle: isItalic ? "italic" : "normal",
fill: textColor,
originX: "center",
originY: "center",
});
canvas.add(textObject);
canvas.sendToFront(textObject); // Bring the text to the front
canvas.renderAll();
}
}
function updateShapeColor() {
const shape = canvas
.getObjects()
.find((obj) => obj.type === "rect" && obj.name === "bgRect");
if (shape) {
shape.set({ fill: document.getElementById("shape-color").value });
shape.visible = true; // Make the large rectangle visible
canvas.renderAll();
}
}
function updateSmallShapeColor() {
const shape = canvas
.getObjects()
.find((obj) => obj.type === "rect" && obj.name === "centerRect");
if (shape) {
shape.set({
fill: document.getElementById("small-shape-color").value,
});
shape.visible = true; // Make the small rectangle visible
canvas.renderAll();
}
}
function updateTextColor() {
const textObject = canvas
.getObjects()
.find((obj) => obj.type === "text");
if (textObject) {
textObject.set({ fill: document.getElementById("text-color").value });
canvas.renderAll();
}
}
// Add a larger rectangle shape (background)
const bgRect = new fabric.Rect({
width: canvas.width,
height: canvas.height,
fill: "#000000",
name: "bgRect", // Add a name to distinguish it
selectable: false,
visible: false, // Initially hidden
});
canvas.add(bgRect);
// Add a smaller rectangle shape (centered)
const centerRect = new fabric.Rect({
width: 565, // Adjust the width
height: 70, // Adjust the height
fill: "#FF0000", // Initial color
name: "centerRect", // Add a name to distinguish it
left: canvas.width / 2,
top: canvas.height / 2,
originX: "center",
originY: "center",
selectable: false,
visible: false, // Initially hidden
});
canvas.add(centerRect);
</script>
您在找这个吗?下面的代码是一个设置,即使选择了对象也可以保留图层。
const canvas = new fabric.Canvas("spacebar-canvas", {
preserveObjectStacking: true
});