PHP SVG 动态创建彩色美国地图

PHP SVG Dynamically Create Colored US Map

我正在尝试创建一张美国地图,其中某些州使用某些颜色进行了着色以供参考。

目前我有一个代码,它只会显示一种颜色。 我需要两种颜色,所以目前我必须创建两张地图。

使用一种颜色代码创建单个地图的代码之一是:

$bumperStates = array(
     "tn", // Tennessee
     "al", // Alabama
     "ga", // Georgia
     "ky", // Kentucky
     "ca", // California
     "nm", // New Mexico
     "wy", // Wyoming
     "ne", // Nebraska
     "ks", // Kansas
     "ok", // Oklahoma
     "tx", // Texas
     "ia", // Iowa
     "mo", // Montana
     "ar", // Arkansas
     "la", // Louisiana
     "ms", // Mississippi
     "fl", // Florida
     "nc", // North Carolina
     "va", // Virginia
     "wv", // West Virginia
     "oh", // Ohio
     "sd", // South Dakota
     "in", // Indiana
     "ky", // Kentucky
     "sc", // South Carolina
     "pa", // Pennsylvania
     "ny", // New York
     "vt", // Vermont
     "me", // Maine
     "il", // Illinois
     "de", // Delaware
     "nj", // New Jersey
     "nh", // New Hampshire
     "ri" // Rhode Island
);
error_reporting( E_ALL );
ini_set( 'display_errors', 1 );

function createPNG( $svgfile, $pngfile ) {
    $command = "rsvg " . $svgfile . " " . $pngfile;
    $make_map = system( $command, $retval );
    if ( $retval ) echo "PNG creation failed."; // Did it work?
}

$bumperstateArray = array();
// Add dot in front of each state to make it a CSS class selector
foreach ( $bumperStates as $bumperstate ) {
    $bumperstateArray[] = '.' . $bumperstate;
}
// Make array into a string consisting of a list of states
$bumperstateList = implode( ', ', $bumperstateArray );

// Generate new map data
$map = file_get_contents( "USA-map.svg" );
if ( $bumperStates ) {
    $newdata = preg_replace( '/\.bumperSign {/i', '.bumperSign, ' . $bumperstateList . ' {', $map );
}

// Write the new map to a file
/*
$fh = fopen( "newmap.svg", "w" );
fwrite( $fh, $newdata );
fclose( $fh );
*/

//createPNG( 'newmap.svg', 'newmap.png' );

// Output new SVG map
header( 'Content-type: image/svg+xml' );
print( $newdata );
flush();

另一个是:

$topstates = array(
     "wa", // Washington
     "ut", // Utag
     "co", // Colorado
     "mi", // Michigan
     "id", // Idaho
     "wy", // Wyoming
     "ct", // Connecticut
     "az", // Arizona
     "or", // Oregon
     "mt", // Montana
     "nv", // Nevada
     "nd", // North Dakota
     "mn", // Minnessota
     "wi", // Wisconsin
     "md", // Maryland
     "de", // Delaware
     "ma" // Massechusetts

);
error_reporting( E_ALL );
ini_set( 'display_errors', 1 );

function createPNG( $svgfile, $pngfile ) {
    $command = "rsvg " . $svgfile . " " . $pngfile;
    $make_map = system( $command, $retval );
    if ( $retval ) echo "PNG creation failed."; // Did it work?
}

$topstateArray = array();
// Add dot in front of each state to make it a CSS class selector
foreach ( $topstates as $topstate ) {
    $topstateArray[] = '.' . $topstate;
}
// Make array into a string consisting of a list of states
$topstateList = implode( ', ', $topstateArray );

// Generate new map data
$map = file_get_contents( "USA-map.svg" );
if ( $topstates ) {
    $newdata = preg_replace( '/\.topSign {/i', '.topSign, ' . $topstateList . ' {', $map );
}

// Write the new map to a file
/*
$fh = fopen( "newmap.svg", "w" );
fwrite( $fh, $newdata );
fclose( $fh );
*/

//createPNG( 'newmap.svg', 'newmap.png' );

// Output new SVG map
header( 'Content-type: image/svg+xml' );
print( $newdata );
flush();

当我尝试将两者结合起来时,我想到了:

$bumperStates = array(
     "tn", // Tennessee
     "al", // Alabama
     "ga", // Georgia
     "ky", // Kentucky
     "ca", // California
     "nm", // New Mexico
     "wy", // Wyoming
     "ne", // Nebraska
     "ks", // Kansas
     "ok", // Oklahoma
     "tx", // Texas
     "ia", // Iowa
     "mo", // Montana
     "ar", // Arkansas
     "la", // Louisiana
     "ms", // Mississippi
     "fl", // Florida
     "nc", // North Carolina
     "va", // Virginia
     "wv", // West Virginia
     "oh", // Ohio
     "sd", // South Dakota
     "in", // Indiana
     "ky", // Kentucky
     "sc", // South Carolina
     "pa", // Pennsylvania
     "ny", // New York
     "vt", // Vermont
     "me", // Maine
     "il", // Illinois
     "de", // Delaware
     "nj", // New Jersey
     "nh", // New Hampshire
     "ri" // Rhode Island
);
$topStates = array(
     "wa", // Washington
     "ut", // Utag
     "co", // Colorado
     "mi", // Michigan
     "id", // Idaho
     "wy", // Wyoming
     "ct", // Connecticut
     "az", // Arizona
     "or", // Oregon
     "mt", // Montana
     "nv", // Nevada
     "nd", // North Dakota
     "mn", // Minnessota
     "wi", // Wisconsin
     "md", // Maryland
     "de", // Delaware
     "ma" // Massechusetts

);
error_reporting( E_ALL );
ini_set( 'display_errors', 1 );

function createPNG( $svgfile, $pngfile ) {
    $command = "rsvg " . $svgfile . " " . $pngfile;
    $make_map = system( $command, $retval );
    if ( $retval ) echo "PNG creation failed."; // Did it work?
}

$bumperstateArray = array();
// Add dot in front of each state to make it a CSS class selector
foreach ( $bumperStates as $bumperstate ) {
    $bumperstateArray[] = '.' . $bumperstate;
}
$topstateArray = array();
// Add dot in front of each state to make it a CSS class selector
foreach ( $topStates as $topstate ) {
    $topstateArray[] = '.' . $topstate;
}
// Make array into a string consisting of a list of states
$bumperstateList = implode( ', ', $bumperstateArray );
$topstateList = implode( ', ', $topstateArray );

// Generate new map data
$map = file_get_contents( "USA-map.svg" );
if ( $bumperStates ) {
    $newdata = preg_replace( '/\.bumperSign {/i', '.bumperSign, ' . $bumperstateList . ' {', $map );
}
if ( $topStates ) {
    $newdata .= preg_replace( '/\.topSign {/i', '.topSign, ' . $topstateList . ' {', $map );
}

// Write the new map to a file
/*
$fh = fopen( "newmap.svg", "w" );
fwrite( $fh, $newdata );
fclose( $fh );
*/

//createPNG( 'newmap.svg', 'newmap.png' );

// Output new SVG map
header( 'Content-type: image/svg+xml' );
print( $newdata );
flush();

生成了一半的地图,但随后出现以下错误:

error on line 390 at column 12: XML declaration allowed only at the start of the document

错误必须来自 SVG 文件,因为它是唯一一个超过 300 行的文件。

我无法 post SVG 文件的内容,因为它太长了:/ Whosebug 说 Body is limited to 30000 characters; you entered 113909

所有原始文件都位于此处:https://github.com/kaldari/SVG-map-maker

也许有人可以告诉我我在 PHP 那边做错了什么?

解决方案

您需要将第二次替换应用于已处理的文档:

// Generate new map data (and assuming you want to keep $map intact)
$newdata = $map = file_get_contents( "USA-map.svg" );
if ( $bumperStates ) {
    $newdata = preg_replace( '/\.bumperSign {/i', '.bumperSign, ' . $bumperstateList . ' {', $newdata  );
}
if ( $topStates ) {
    $newdata = preg_replace( '/\.topSign {/i', '.topSign, ' . $topstateList . ' {', $newdata );
}

解释

错误很明显,您正在尝试重新声明一个 xml 已经存在的文档。详情:

  • svg 文件本质上是一个 xml 文件
  • 您不能在同一文件中两次声明一个 xml 文档
  • 您正在将一个 svg 文件附加到另一个 svg 文件,这意味着您在一个文件中声明了两个 xml 文档

问题在这里:

if ( $topStates ) {
    $newdata .= preg_replace( '/\.topSign {/i', '.topSign, ' . $topstateList . ' {', $map );
}

这基本上导致了这个(这是不允许的):

<?xml ...?><svg>...</svg><?xml ...?><svg>...</svg>