docs: add oversized label demo (#5505)

* docs: add oversized label demo

* docs: add copy label demo

* docs: update label text wordWrap

* docs: use clipboard API

* test: add test for element label oversized
This commit is contained in:
hustcc 2024-03-08 10:20:05 +08:00 committed by GitHub
parent cb9f274a36
commit a5f887908b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 407 additions and 369 deletions

View File

@ -29,6 +29,7 @@ export * from './edge-loop';
export * from './edge-polyline';
export * from './edge-port';
export * from './edge-quadratic';
export * from './element-label-oversized';
export * from './graph-element';
export * from './layered-canvas';
export * from './node-circle';

View File

@ -0,0 +1,77 @@
import { Graph } from '@/src';
import type { StaticTestCase } from '../types';
export const elementLabelOversized: StaticTestCase = async (context) => {
const { container, animation, theme } = context;
const data = {
nodes: [
{
id: 'node1',
data: {
x: 100,
y: 150,
label: `This label is too long to be displayed`,
size: 100,
},
},
{
id: 'node2',
data: {
x: 400,
y: 150,
label: 'This label is too long to be displayed',
size: 150,
},
},
],
edges: [
{
id: 'edge1',
source: 'node1',
target: 'node2',
data: {
label: 'This label is too long to be displayed',
},
},
],
};
const graph = new Graph({
container: container,
theme,
data,
node: {
style: {
type: 'rect',
x: (d: any) => d.data.x,
y: (d: any) => d.data.y,
size: (d: any) => d.data.size,
labelPosition: 'bottom',
labelText: (d: any) => d.data.label,
labelMaxWidth: '90%',
labelBackgroundFill: '#eee',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
labelWordWrap: true,
labelMaxLines: 4,
},
},
edge: {
style: {
labelOffsetY: -4,
labelTextBaseline: 'bottom',
labelText: (d: any) => d.data.label,
labelMaxWidth: '80%',
labelBackgroundFill: 'red',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
labelWordWrap: true,
labelMaxLines: 4,
},
},
behaviors: ['drag-node'],
animation,
});
await graph.render();
};

View File

@ -0,0 +1,175 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="500"
height="500"
style="background: transparent; position: absolute; outline: none;"
color-interpolation-filters="sRGB"
tabindex="1"
>
<defs />
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
<g id="g-svg-7" fill="none" transform="matrix(1,0,0,1,0,0)" />
<g id="g-svg-6" fill="none" transform="matrix(1,0,0,1,0,0)">
<g
id="edge1"
fill="none"
marker-start="false"
marker-end="false"
transform="matrix(1,0,0,1,0,0)"
>
<g
id="edge1"
fill="none"
marker-start="false"
marker-end="false"
stroke="transparent"
stroke-width="3"
/>
<g transform="matrix(1,0,0,1,150,150)">
<path
id="key"
fill="none"
d="M 0,0 L 175,0"
stroke-width="1"
stroke="rgba(153,173,209,1)"
/>
<path
id="key"
fill="none"
d="M 0,0 L 175,0"
stroke-width="3"
stroke="transparent"
/>
</g>
<g id="label" fill="none" transform="matrix(1,0,0,1,241.500000,146)">
<g transform="matrix(1,0,0,1,-67.379997,-46)">
<path
id="background"
fill="rgba(255,0,0,1)"
d="M 4,0 l 127.76000000000002,0 a 4,4,0,0,1,4,4 l 0,38 a 4,4,0,0,1,-4,4 l -127.76000000000002,0 a 4,4,0,0,1,-4,-4 l 0,-38 a 4,4,0,0,1,4,-4 z"
opacity="0.75"
stroke-width="0"
fill-opacity="0.5"
width="135.76000000000002"
height="46"
/>
</g>
<g transform="matrix(1,0,0,1,0,0)">
<text
id="text"
fill="rgba(0,0,0,0.8509803921568627)"
dominant-baseline="text-after-edge"
paint-order="stroke"
font-size="12"
text-anchor="middle"
>
<tspan x="0" dx="0.5" dy="-23">
This label is too long to
</tspan>
<tspan x="0" dx="0.5" dy="23">
be displayed
</tspan>
</text>
</g>
</g>
</g>
</g>
<g id="g-svg-5" fill="none" transform="matrix(1,0,0,1,0,0)">
<g id="node1" fill="none" transform="matrix(1,0,0,1,100,150)">
<g transform="matrix(1,0,0,1,0,0)">
<path
id="key"
fill="rgba(34,126,255,1)"
d="M 0,0 l 100,0 l 0,100 l-100 0 z"
transform="translate(-50,-50)"
stroke-width="0"
stroke="rgba(0,0,0,1)"
width="100"
height="100"
/>
</g>
<g id="label" fill="none" transform="matrix(1,0,0,1,0,50)">
<g transform="matrix(1,0,0,1,-42.060001,0)">
<path
id="background"
fill="rgba(238,238,238,1)"
d="M 4,0 l 77.12,0 a 4,4,0,0,1,4,4 l 0,61 a 4,4,0,0,1,-4,4 l -77.12,0 a 4,4,0,0,1,-4,-4 l 0,-61 a 4,4,0,0,1,4,-4 z"
opacity="0.5"
stroke-width="0"
fill-opacity="0.5"
width="85.12"
height="69"
/>
</g>
<g transform="matrix(1,0,0,1,0,0)">
<text
id="text"
fill="rgba(0,0,0,0.8509803921568627)"
dominant-baseline="hanging"
paint-order="stroke"
font-size="12"
text-anchor="middle"
>
<tspan x="0" dx="0.5" dy="0">
This label is
</tspan>
<tspan x="0" dx="0.5" dy="23">
too long to be
</tspan>
<tspan x="0" dx="0.5" dy="23">
displayed
</tspan>
</text>
</g>
</g>
</g>
<g id="node2" fill="none" transform="matrix(1,0,0,1,400,150)">
<g transform="matrix(1,0,0,1,0,0)">
<path
id="key"
fill="rgba(34,126,255,1)"
d="M 0,0 l 150,0 l 0,150 l-150 0 z"
transform="translate(-75,-75)"
stroke-width="0"
stroke="rgba(0,0,0,1)"
width="150"
height="150"
/>
</g>
<g id="label" fill="none" transform="matrix(1,0,0,1,0,75)">
<g transform="matrix(1,0,0,1,-67.379997,0)">
<path
id="background"
fill="rgba(238,238,238,1)"
d="M 4,0 l 127,0 a 4,4,0,0,1,4,4 l 0,38 a 4,4,0,0,1,-4,4 l -127,0 a 4,4,0,0,1,-4,-4 l 0,-38 a 4,4,0,0,1,4,-4 z"
opacity="0.5"
stroke-width="0"
fill-opacity="0.5"
width="135"
height="46"
/>
</g>
<g transform="matrix(1,0,0,1,0,0)">
<text
id="text"
fill="rgba(0,0,0,0.8509803921568627)"
dominant-baseline="hanging"
paint-order="stroke"
font-size="12"
text-anchor="middle"
>
<tspan x="0" dx="0.5" dy="0">
This label is too long to
</tspan>
<tspan x="0" dx="0.5" dy="23">
be displayed
</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -1,258 +0,0 @@
import { Graph, Extensions, extend, stdLib } from '@antv/g6';
const container = document.getElementById('container');
const tipDiv = document.createElement('div');
tipDiv.innerHTML = `Click to show the complete label. <br/> Click the icon to copy the content.`;
container.appendChild(tipDiv);
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const nodeHeight = 80;
const nodeWidth = 200;
const fillColor = '#f6e9d7';
const fontColor = '#ff7900';
const padding = 7;
class CopyNode extends Extensions.RectNode {
drawOtherShapes(model, shapeMap, diffData, diffState) {
const { data: cfg } = model;
const topGroup = {
topBox: this.upsertShape(
'rect',
'topBox',
{
fill: '#fff',
stroke: '#c7d0d1',
x: padding,
y: padding,
width: nodeWidth - padding * 2,
height: 0.5 * nodeHeight - padding,
lineWidth: 1.5,
radius: 4,
},
{
model,
shapeMap,
diffData,
diffState,
},
),
topText: this.upsertShape(
'text',
'topText',
{
// text: fittingString(cfg.topText, nodeWidth - padding * 2 - 10, 14),
text: cfg.topText,
x: cfg.isTopTextEllipsis ? padding : padding + 24,
y: (0.5 * nodeHeight + padding) * 0.5,
fontSize: 14,
textAlign: 'start',
textBaseline: 'middle',
shadowColor: fontColor,
fill: fontColor,
wordWrap: cfg.isTopTextEllipsis,
wordWrapWidth: nodeWidth - padding * 2,
textOverflow: 'ellipsis',
maxLines: 1,
},
{
model,
shapeMap,
diffData,
diffState,
},
model,
),
topImage: this.upsertShape(
'image',
'topImage',
{
x: padding + 5,
y: padding + (0.5 * nodeHeight - padding) * 0.5 - 10,
height: 20,
width: 20,
img: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
opacity: cfg.isTopTextEllipsis ? 0 : 1,
cursor: 'pointer',
},
{
model,
shapeMap,
diffData,
diffState,
},
),
};
const bottomGroup = {
bottomText: this.upsertShape(
'text',
'bottomText',
{
// text: fittingString(cfg.bottomText, nodeWidth - 10, 14),
text: cfg.bottomText,
x: cfg.isBottomTextEllipsis ? padding : padding + 20,
y: nodeHeight - (0.5 * nodeHeight + padding) * 0.5,
fontSize: 14,
textAlign: 'start',
textBaseline: 'middle',
shadowColor: fontColor,
fill: fontColor,
wordWrap: cfg.isBottomTextEllipsis,
wordWrapWidth: nodeWidth,
textOverflow: 'ellipsis',
maxLines: 1,
},
{
model,
shapeMap,
diffData,
diffState,
},
),
bottomImage: this.upsertShape(
'image',
'bottomImage',
{
x: 5,
y: 0.5 * nodeHeight + 8,
height: 20,
width: 20,
img: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
opacity: cfg.isBottomTextEllipsis ? 0 : 1,
cursor: 'pointer',
},
{
model,
shapeMap,
diffData,
diffState,
},
),
};
return { ...topGroup, ...bottomGroup };
}
}
const ExtGraph = extend(Graph, {
nodes: {
'copy-node': CopyNode,
},
});
const graph = new ExtGraph({
container: 'container',
width,
height,
modes: {
default: ['drag-node'],
},
data: {
nodes: [
{
id: 'node1',
data: {
x: 100,
y: 100,
topText: 'This label is too long to be displayed',
bottomText: 'This label is too long to be displayed',
isTopTextEllipsis: true,
isBottomTextEllipsis: true,
},
},
{
id: 'node2',
data: {
x: 100,
y: 200,
topText: 'Short Label',
bottomText: 'Click the Logo to Copy!',
isTopTextEllipsis: true,
isBottomTextEllipsis: true,
},
},
],
},
node: {
type: 'copy-node',
keyShape: {
x: nodeWidth / 2,
y: nodeHeight / 2,
width: nodeWidth,
height: nodeHeight,
fill: fillColor,
lineWidth: 2,
stroke: fontColor,
radius: 5,
},
otherShapes: {},
},
});
const copyStr = (str) => {
const input = document.createElement('textarea');
input.value = str;
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
alert('Copy Success!');
};
const resetTextEllipsis = () => {
const nodeIds = graph.getAllNodesData().map((node) => node.id);
nodeIds.map((nodeId) => {
graph.updateData('node', {
id: nodeId,
data: {
isTopTextEllipsis: true,
isBottomTextEllipsis: true,
},
});
});
};
graph.on('node:pointermove', (event) => {
const { itemId, target } = event;
resetTextEllipsis();
if (target.id === 'topText' || target.id === 'topImage') {
graph.updateData('node', {
id: itemId,
data: {
isTopTextEllipsis: false,
},
});
}
if (target.id === 'bottomText' || target.id === 'bottomImage') {
graph.updateData('node', {
id: itemId,
data: {
isBottomTextEllipsis: false,
},
});
}
});
graph.on('node:click', (event) => {
const { itemId, target } = event;
if (target.id === 'topImage') {
const model = graph.getNodeData(itemId);
const text = model.data.topText;
copyStr(text);
}
if (target.id === 'bottomImage') {
const model = graph.getNodeData(itemId);
const text = model.data.bottomText;
copyStr(text);
}
});
graph.on('node:pointerleave', (event) => {
resetTextEllipsis();
});
window.graph = graph;

View File

@ -0,0 +1,53 @@
import { Graph } from '@antv/g6';
const data = {
nodes: [
{
id: 'node1',
data: {
label: 'Click to copy this label which is too long to be displayed',
},
},
],
edges: [],
};
const graph = new Graph({
container: 'container',
data,
node: {
style: {
x: 200,
y: 200,
size: 150,
labelPosition: 'center',
labelText: (d) => d.data.label,
labelMaxWidth: '90%',
labelBackgroundFill: '#eee',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
labelPointerEvents: 'none',
labelBackgroundPointerEvents: 'none',
},
},
behaviors: ['drag-node'],
});
graph.render();
graph.on('node:click', (e) => {
const id = e.target.id;
const node = graph.getNodeData(id);
const label = node?.data?.label;
navigator.clipboard.writeText(label);
alert('copied to clipboard!');
});
graph.on('node:pointerenter', (e) => {
graph.setElementState(e.target.id, 'active');
});
graph.on('node:pointerout', (e) => {
graph.setElementState(e.target.id, '');
});

View File

@ -8,7 +8,7 @@ const data = {
x: 100,
y: 150,
label: 'This label is too long to be displayed',
size: 50,
size: 100,
},
},
{
@ -17,7 +17,7 @@ const data = {
x: 400,
y: 150,
label: 'This label is too long to be displayed',
size: 100,
size: 150,
},
},
],
@ -33,38 +33,34 @@ const data = {
],
};
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new Graph({
container,
width,
height,
modes: {
default: ['drag-node'],
},
container: 'container',
data,
node: {
keyShape: {
r: {
fields: ['size'],
formatter: (model) => model.data.size / 2,
},
style: {
x: (d) => d.data.x,
y: (d) => d.data.y,
size: (d) => d.data.size,
labelPosition: 'center',
labelText: (d) => d.data.label,
labelMaxWidth: '90%',
labelBackgroundFill: '#eee',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
},
labelShape: {
position: 'center',
text: {
fields: ['label'],
formatter: (model) => model.data.label,
},
maxWidth: '80%',
},
labelBackgroundShape: {},
},
edge: {
labelBackgroundShape: {},
style: {
labelOffsetY: -4,
labelTextBaseline: 'bottom',
labelText: (d) => d.data.label,
labelMaxWidth: '80%',
labelBackgroundFill: 'red',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
},
},
data,
behaviors: ['drag-node'],
});
window.graph = graph;
graph.render();

View File

@ -1,79 +0,0 @@
import { Graph } from '@antv/g6';
const data = {
nodes: [
{
id: 'node1',
data: {
x: 100,
y: 150,
label: `This label is too long to be displayed`,
size: 50,
},
},
{
id: 'node2',
data: {
x: 400,
y: 150,
label: 'This label is too long to be displayed',
size: 100,
},
},
],
edges: [
{
id: 'edge1',
source: 'node1',
target: 'node2',
data: {
label: 'This label is too long to be displayed',
},
},
],
};
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new Graph({
container,
width,
height,
modes: {
default: ['drag-node'],
},
node: {
type: 'rect-node',
keyShape: {
width: {
fields: ['size'],
formatter: (model) => model.data.size,
},
},
labelShape: {
position: 'center',
maxLines: 4,
text: {
fields: ['label'],
formatter: (model) => model.data.label,
},
maxWidth: '80%',
},
},
edge: {
labelShape: {
position: 'center',
maxLines: 4,
text: {
fields: ['label'],
formatter: (model) => model.data.label,
},
wordWrapWidth: 80,
},
},
data,
});
window.graph = graph;

View File

@ -0,0 +1,72 @@
import { Graph } from '@antv/g6';
const data = {
nodes: [
{
id: 'node1',
data: {
x: 100,
y: 150,
label: `This label is too long to be displayed`,
size: 100,
},
},
{
id: 'node2',
data: {
x: 400,
y: 150,
label: 'This label is too long to be displayed',
size: 150,
},
},
],
edges: [
{
id: 'edge1',
source: 'node1',
target: 'node2',
data: {
label: 'This label is too long to be displayed',
},
},
],
};
const graph = new Graph({
container: 'container',
fitCenter: true,
data,
node: {
style: {
type: 'rect',
x: (d) => d.data.x,
y: (d) => d.data.y,
size: (d) => d.data.size,
labelPosition: 'bottom',
labelText: (d) => d.data.label,
labelMaxWidth: '90%',
labelBackgroundFill: '#eee',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
labelWordWrap: true,
labelMaxLines: 4,
},
},
edge: {
style: {
labelOffsetY: -4,
labelTextBaseline: 'bottom',
labelText: (d) => d.data.label,
labelMaxWidth: '80%',
labelBackgroundFill: 'red',
labelBackgroundFillOpacity: 0.5,
labelBackgroundRadius: 4,
labelWordWrap: true,
labelMaxLines: 4,
},
},
behaviors: ['drag-node'],
});
graph.render();

View File

@ -5,15 +5,16 @@
},
"demos": [
{
"filename": "copyLabel.js",
"filename": "copyLabel.ts",
"title": {
"zh": "文本超长交互与复制",
"en": "Long Label Show and Copy"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*O5DCQ4ziMisAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "labelLen.js",
"filename": "labelLen.ts",
"title": {
"zh": "文本超长",
"en": "Long Label"
@ -21,7 +22,7 @@
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*LsGJTIaynVwAAAAAAAAAAAAADmJ7AQ/original"
},
{
"filename": "labelLen1.js",
"filename": "labelLen1.ts",
"title": {
"zh": "多行显示超长文本",
"en": "Break Line for Long Label"