Hi everyone, I'm the open source image editor for the/ikuaitu/vue-fabric-editor is the author of a PC-based version of an open source image editor.
Many developers have recently inquired thatIs it possible to transform an open source image editor into an H5 version of an image editor for mobile?The H5 version of the image editor has just been launched, so I'll organize the implementation ideas and product details into notes and share them for your reference.
infrastructural
The basic functions of the open source image editor are available, such as switching templates, adding elements, customizing fonts, etc., but compared to the interaction of the mobile side will be very different, do a lot of remodeling, this time the notes are mainly to share theMobile image editor implementation ideas and details。
leading principles
- Switching Templates
- Add Picture
- Adding Combination Elements
- Setting the background color
- Modify canvas size
- menu
- Properties Toolbar
- special effects font
- Switching Fonts
- input
- typesetting
- frame
- fig. a traumatic experience that haunts someone
- Download images
Note: Some of the code examples are encapsulated code, not native methods.
1. Switching templates
The editor is based on the development, all the templates are stored in json format, switching templates only need to request the details of the interface, will be added to the canvas of the json format of the data transfer can be, it is necessary to pay attention to the need for the template to be used in the name of the font, and load the font file and then rendering, otherwise there is no way to render the font styles properly.
const loadInfo = async (res: any) => {
const info =
= ;
await (());
((), () => LoadingPlugin(false));
};
2. Adding pictures
There are a number of ways to add an image to a file, and we've used the simplest of these to add an image to a file.Can be, in addition, often have a picture size greater than the canvas, but also need to zoom the picture according to the general width of the canvas, more convenient for users to operate.
const toEditor = async (e: MouseEvent) => {
= false
LoadingPlugin(true)
const item = await ( as HTMLImageElement)
await (item, { scale: true })
LoadingPlugin(false)
}
3. Adding combinatorial elements
Support for export/import of individual elements in JSON format, we will export the data stored in the database, import by element type can be imported, you need to get the type of the element in the JSON, and called as a method name, the same need to do the font loading before importing, and do the scaling after pouring.
const capitalizeFirstLetter = (str: string) => {
return (0).toUpperCase() + (1);
}
const toEditor = async (item: ItemProps) => {
= false
LoadingPlugin(true)
await (());
const el = (());
const elType = capitalizeFirstLetter();
new fabric[elType].fromObject(el, (fabricEl: ) => {
(fabricEl);
LoadingPlugin(false)
});
}
4. Setting the background color
Setting the background color is relatively simple, according to the API to set the color can be, it should be noted that most of the PC side of the color component is not adapted to the mobile side of the H5 scene, does not support the touch event, we use the@jaames/iro
This component, which performs well on mobile, is perfectly adapted to our scenario, and its API is flexible enough that we encapsulate it into a generic color component that is called in multiple places.
<template>
<div ref="pickerContainer">
</div>
</template>
<script setup lang="ts">
import iro from '@jaames/iro';
const emit = defineEmits(['update:modelValue', 'change']);
const props = defineProps({
modelValue: {
type: String,
default: '#000000'
},
width: {
type: Number,
default: 200
}
});
const pickerContainer = ref<HTMLButtonElement | string>('');
let colorPicker: any = null;
onMounted(() => {
// Creating a color picker
colorPicker = (, {
width: ,
color: ,
borderWidth: 1,
borderColor: "#fff",
layoutDirection: 'horizontal',
layout: [
{
component: ,
options: {
id: 'hue-slider',
sliderType: 'hue'
}
},
{
component: ,
},
{
component: ,
options: {
sliderType: 'alpha'
}
}
]
});
// Listen to color change events and fire custom events
('color:change', (color: any) => {
const rgbaString = ;
emit('update:modelValue', rgbaString);
emit('change', rgbaString);
});
});
</script>
5. Modifying canvas size
Daily use of image editors have the need to modify the size of the canvas , in the open source project has encapsulated the corresponding method , you can call directly , it should be noted that when the size of the modification of the pop-up box pop-up , in order to achieve the effect of WYSIWYG , in order to avoid the pop-up box blocking the canvas , the other attributes of the modification of the same reason .
const resizeEditor = async () => {
await nextTick()
const editorWorkspase = ('#workspace') as HTMLElement
const popElement = ('.my-editor-popup') as HTMLElement
const headerElement = ('.t-navbar') as HTMLElement
if (popElement) {
= `calc(100vh - ${popElement?.offsetHeight + headerElement?.offsetHeight || 0}px)`
} else {
= ''
}
}
6. Shortcut menu
Many shortcut operations need to be able to allow users to quickly find and complete the operation, we added a shortcut menu function for the element, to avoid some simple operations so that the user in the bottom of the menu bar point to point to go, when the element is elected to automatically display, unchecked when the hide can be, it is important to note that the shortcut menu is not always in the element above the shortcut menu should be based on the location of the element and the size of the canvas to locate, when the menu When the menu exceeds the canvas area, we need to adjust the menu position in time; in addition, when the attribute pop-up box appears, the canvas size changes, you need to synchronize the menu position.
// Updating location information
const upDatePosition = async () => {
const activeObject = ();
if (activeObject) {
();
= 10;
= 10;
await nextTick();
isIncluded(activeObject);
await nextTick();
}
}
// 监听选中对象变化Updating location information
getObjectAttr(upDatePosition)
('selection:updated', upDatePosition)
('mouse:move', upDatePosition)
('workspaceAutoEvent', upDatePosition)
7. Attribute toolbar
With reference to other image editors, some of the attributes can be modified only after clicking on the element, and the options are hidden when the element is unchecked, and the modifiable options are also different for different selected elements, which is a great interaction in a complex image editor on the mobile side.
We encapsulate generic check types and methods, setting hide/show individually for each property component.
8. Special effects fonts
The special effect font is mainly a combination of the color, border and shadow of the text element. We will export the JSON after setting the style of the text and save it in the database, and then set the attributes to the element according to the data in the JSON when a special effect is selected.
const setStyle = (item: ImgItem) => {
const activeObject = ()[0];
if (activeObject) {
const values = toRaw();
const keys = ['fill', 'stroke', 'strokeWidth', 'shadow', 'strokeLineCap'];
('paintFirst', 'stroke');
((key) => {
(key, values[key]);
if (key === 'fill' && typeof values[key] != 'string') {
(key, new (values[key]));
}
});
();
}
};
9. Switching fonts
Modifying the font is simply a matter of calling the element'sfontFamily
attribute is sufficient, make sure the font is loaded before modifying it.
const changeCommon = async (key: string, value: any) => {
const activeObject = ()[0];
if (activeObject) {
LoadingPlugin(true);
= value;
try {
await (value)
} catch (error) {
(error)
}
LoadingPlugin(false);
activeObject && (key, value);
();
}
};
10. Entering text
You can directly double-click the text element to modify, but in the mobile terminal this interaction is not eye-catching, we have a separate modification for the text element, after selecting the element, click again when the pop-up input box, you can click the button in the bottom menu bar to modify.
11. Typography
Text layout is relatively simple, we just need to follow the text properties of the text properties can be set, such as fontSize, lineHeight, charSpacing and so on.
// attribute value
const baseAttr = reactive({
fontSize: 0,
lineHeight: 0,
charSpacing: 0,
textAlign: '',
fontWeight: '',
fontStyle: '',
underline: false,
linethrough: false,
overline: false,
});
12. Borders
The border style is similar to the text style, and with the color component you can achieve the function very quickly.
// Attribute values
const baseAttr = reactive({
stroke: '#fff',
strokeWidth: 0,
strokeDashArray: [],
});
13. Shadows
The referenced attribute is primarily a modification of the element's shadow subattribute, as shown in the following code:
// attribute value
const baseAttr = reactive({
shadow: {
color: '#fff',
blur: 0,
offsetX: 1,
offsetY: 1,
}
});
// Generic attribute changes
const changeCommon = () => {
const activeObject = ()[0];
if (activeObject) {
('shadow', new ());
();
}
};
14. Download images
Png/Jpeg/Base64 formats can be exported, while the JPEG format can also specify the image quality and size multiplier, see the API documentation for details.
wind up
The above is the development of mobile editor implementation details , combined with our open source projects and plug-in architecture can be very easy to complete the project development , if you are doing a similar project or do a similar project , welcome to communicate with me .
Open Source Project:/ikuaitu/vue-fabric-editor/blob/main/